New option --list-config for gpgconf.
authorWerner Koch <wk@gnupg.org>
Tue, 23 Oct 2007 18:13:27 +0000 (18:13 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 23 Oct 2007 18:13:27 +0000 (18:13 +0000)
NEWS
doc/ChangeLog
doc/examples/gpgconf.conf
doc/tools.texi
g10/call-agent.c
tools/ChangeLog
tools/gpgconf-comp.c
tools/gpgconf.c
tools/gpgconf.h

diff --git a/NEWS b/NEWS
index a0a2c10..ce06549 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,8 @@ Noteworthy changes in version 2.0.8
 
  * Enhanced gpg-connect-agent with a small scripting language.
 
+ * New option --list-config for gpgconf.
+
 
 Noteworthy changes in version 2.0.7 (2007-09-10)
 ------------------------------------------------
index 096e8eb..6d34811 100644 (file)
@@ -1,3 +1,7 @@
+2007-10-23  Werner Koch  <wk@g10code.com>
+
+       * tools.texi (Listing global options): New.
+
 2007-10-19  Werner Koch  <wk@g10code.com>
 
        * tools.texi (Controlling gpg-connect-agent): Updated.
index 0f4a021..ec8685a 100644 (file)
@@ -9,8 +9,8 @@
 # white space character, are ignored.  The line is separated by white
 # space into fields. The first field is used to match the user or
 # group and must start at the first column, the file is processes
-# sequential until a matching rle is found.  A rule may contain
-# several lines, continuation lines are indicated by a indenting them.
+# sequential until a matching rule is found.  A rule may contain
+# several lines; continuation lines are indicated by a indenting them.
 #
 # Syntax of a line:
 # <key>|WS  <component> <option> ["["<flag>"]"] [<value>]
@@ -38,8 +38,8 @@
 #         gpg-agent min-passphrase-nonalpha [no-change] 1 
 #         gpg-agent max-passphrase-days [no-change] 700
 #         gpg-agent enable-passphrase-history [no-change]
-#         gpg-agent enforce-passphrase-policy [default]
-#         gpg-agent enforce-passphrase-policy [no-change]
+#         gpg-agent enforce-passphrase-constraints [default]
+#         gpg-agent enforce-passphrase-constraints [no-change]
 #         gpg-agent max-cache-ttl [no-change] 10800
 #         gpg-agent max-cache-ttl-ssh [no-change] 10800
 #         gpg-agent allow-mark-trusted [default]
index d240aca..c65de93 100644 (file)
@@ -197,13 +197,14 @@ program that uses @command{gpgconf} in this way will be called GUI
 throughout this section.
 
 @menu
-* Invoking gpgconf::      List of all commands and options.
-* Format conventions::    Formatting conventions relevant for all commands.
-* Listing components::    List all gpgconf components.
-* Checking programs::     Check all programs know to gpgconf.
-* Listing options::       List all options of a component.
-* Changing options::      Changing options of a component.
-* Files used by gpgconf:: What files are used by gpgconf.
+* Invoking gpgconf::       List of all commands and options.
+* Format conventions::     Formatting conventions relevant for all commands.
+* Listing components::     List all gpgconf components.
+* Checking programs::      Check all programs know to gpgconf.
+* Listing options::        List all options of a component.
+* Changing options::       Changing options of a component.
+* Listing global options:: List all global options.
+* Files used by gpgconf::  What files are used by gpgconf.
 @end menu
 
 @manpause
@@ -232,6 +233,10 @@ Change the options of the component @var{component}.
 Update all configuration files with values taken from the global
 configuration file (usually @file{/etc/gnupg/gpgconf.conf}).
 
+@item --list-config [@var{filename}]
+List the global configuration file in a colon separated format.  If
+@var{filename} is given, check that file instead.
+
 @item --check-config [@var{filename}]
 Run a syntax check on the global configuration file.  If @var{filename}
 is given, check that file instead.
@@ -767,6 +772,64 @@ $ echo 'force:16:' | gpgconf --change-options dirmngr
 The @code{--runtime} option can influence when the changes take
 effect.
 
+
+@node Listing global options
+@subsection Listing global options
+
+Sometimes it is useful for applications to look at the global options
+file @file{gpgconf.conf}. 
+The colon separated listing format is record oriented and uses the first
+field to identify the record type:
+
+@table @code
+@item k
+This describes a key record to start the definition of a new ruleset for
+a user/group.  The format of a key record is:
+
+  @code{k:@var{user}:@var{group}:}
+
+@table @var
+@item user
+This is the user field of the key.  It is percent escaped.  See the
+definition of the gpgconf.conf format for details.
+
+@item group
+This is the group field of the key.  It is percent escaped.
+@end table
+
+@item r
+This describes a rule record. All rule records up to the next key record
+make up a rule set for that key.  The format of a rule record is:
+
+  @code{r:::@var{component}:@var{option}:@var{flags}:@var{value}:}
+
+@table @var
+@item component
+This is the component part of a rule.  It is a plain string.
+
+@item option
+This is the option part of a rule.  It is a plain string.
+
+@item flag
+This is the flags part of a rule.  There may be only one flag per rule
+but by using the same component and option, several flags may be
+assigned to an option.  It is a plain string.
+
+@item value
+This is the optional value for the option.  It is a percent escaped
+string with a single quotation mark to indicate a string.  The quotation
+mark is only required to distinguish between no value specified and an
+empty string.
+@end table
+
+@end table
+
+@noindent
+Unknown record typs should be ignored.  Note that there is intentionally
+no feature to change the global option file through @command{gpgconf}.
+
+
+
 @mansect files
 @node Files used by gpgconf
 @subsection Files used by gpgconf
index 34c1fde..03c3a74 100644 (file)
@@ -714,7 +714,7 @@ agent_clear_pin_cache (const char *sn)
 
 
 \f
-/* Note: All strings shall be UTF-8. On success the caler needs to
+/* Note: All strings shall be UTF-8. On success the caller needs to
    free the string stored at R_PASSPHRASE. On error NULL will be
    stored at R_PASSPHRASE and an appropriate fpf error code
    returned. */
index 37652eb..69a2430 100644 (file)
@@ -1,6 +1,13 @@
 2007-10-23  Werner Koch  <wk@g10code.com>
 
-       * gpgconf-comp.c (gc_options_gpg_agent): Repalce accidently used
+       * gpgconf-comp.c (gc_process_gpgconf_conf): Add arg
+       LISTFP.  Changed all callers.
+       * gpgconf.h: Add gc_error.
+       * gpgconf.c: Add command --list-config.
+       (get_outfp): New.
+       (main): Make --output work.
+
+       * gpgconf-comp.c (gc_options_gpg_agent): Replace accidently used
        GC_BACKEND_SCDAEMON.  We should consider to create these tables
        from plain files.
 
index 6e1d604..3cde745 100644 (file)
@@ -337,7 +337,7 @@ static struct
    argument value.  */
 #define GC_OPT_FLAG_LIST       (1UL << 2)
 /* The NO_CHANGE flag for an option indicates that the user should not
-   be allowed to chnage this option using the standard gpgconf method.
+   be allowed to change this option using the standard gpgconf method.
    Frontends using gpgconf should grey out such options, so that only
    the current value is displayed.  */
 #define GC_OPT_FLAG_NO_CHANGE   (1UL <<7)
@@ -522,7 +522,7 @@ static gc_option_t gc_options_gpg_agent[] =
    { "Passphrase policy",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
      "gnupg", N_("Options enforcing a passphrase policy") },
-   { "enforce-passphrases-constraints", GC_OPT_FLAG_RUNTIME, 
+   { "enforce-passphrase-constraints", GC_OPT_FLAG_RUNTIME, 
      GC_LEVEL_EXPERT, "gnupg", 
      N_("do not allow to bypass the passphrase policy"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
@@ -542,7 +542,7 @@ static gc_option_t gc_options_gpg_agent[] =
      GC_LEVEL_EXPERT, "gnupg", 
      N_("|N|expire the passphrase after N days"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
-   { "enable-passphrases-history", GC_OPT_FLAG_RUNTIME, 
+   { "enable-passphrase-history", GC_OPT_FLAG_RUNTIME, 
      GC_LEVEL_EXPERT, "gnupg", 
      N_("do not allow the reuse of old passphrases"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
@@ -3094,12 +3094,14 @@ key_matches_user_or_group (char *user)
    default name will be used.  With UPDATE set to true the internal
    tables are actually updated; if not set, only a syntax check is
    done.  If DEFAULTS is true the global options are written to the
-   configuration files.
+   configuration files.  If LISTFP is set, no changes are done but the
+   configuration file is printed to LISTFP in a colon separated format.
 
    Returns 0 on success or if the config file is not present; -1 is
    returned on error. */
 int
-gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults)
+gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
+                         FILE *listfp)
 {
   int result = 0;
   char *line = NULL;
@@ -3112,9 +3114,11 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults)
   int runtime[GC_BACKEND_NR];
   int used_components[GC_COMPONENT_NR];
   int backend_id, component_id;
-  char *fname = (char *) fname_arg;
+  char *fname;
 
-  if (!fname)
+  if (fname_arg)
+    fname = xstrdup (fname_arg);
+  else
     fname = make_filename (gnupg_sysconfdir (), "gpgconf.conf", NULL);
 
   for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++)
@@ -3126,7 +3130,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults)
   if (!config)
     {
       /* Do not print an error if the file is not available, except
-         when runnign in syntax check mode.  */
+         when running in syntax check mode.  */
       if (errno != ENOENT || !update)
         {
           gc_error (0, errno, "can not open global config file `%s'", fname);
@@ -3295,12 +3299,41 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults)
                     fname, lineno);
           result = -1;
         }
-      
+
+      /* In list mode we print out all records.  */
+      if (listfp && !result)
+        {
+          /* If this is a new ruleset, print a key record.  */
+          if (!is_continuation)
+            {
+              char *group = strchr (key, ':');
+              if (group)
+                {
+                  *group++ = 0;
+                  if ((p = strchr (group, ':')))
+                    *p = 0; /* We better strip any extra stuff. */
+                }                    
+              
+              fprintf (listfp, "k:%s:", my_percent_escape (key));
+              fprintf (listfp, "%s:\n", group? my_percent_escape (group):"");
+            }
+
+          /* All other lines are rule records.  */
+          fprintf (listfp, "r:::%s:%s:%s:",
+                   gc_component[component_id].name,                     
+                   option_info->name? option_info->name : "",
+                   flags? flags : "");
+          if (value != empty)
+            fprintf (listfp, "\"%s", my_percent_escape (value));
           
+          putc (':', listfp);
+          putc ('\n', listfp);
+        }
+
       /* Check whether the key matches but do this only if we are not
          running in syntax check mode. */
       if ( update 
-           && !result
+           && !result && !listfp
            && (got_match || (key && key_matches_user_or_group (key))) )
         {
           int newflags = 0;
@@ -3348,7 +3381,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults)
   xfree (line);
 
   /* If it all worked, process the options. */
-  if (!result && update && defaults)
+  if (!result && update && defaults && !listfp)
     {
       /* We need to switch off the runtime update, so that we can do
          it later all at once. */
index 3d81f01..9c1c77a 100644 (file)
@@ -44,6 +44,7 @@ enum cmd_and_opt_values
     aListOptions,
     aChangeOptions,
     aApplyDefaults,
+    aListConfig,
     aCheckConfig
 
   };
@@ -60,6 +61,8 @@ static ARGPARSE_OPTS opts[] =
     { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
     { aApplyDefaults, "apply-defaults", 256,
       N_("apply global default values") },
+    { aListConfig,   "list-config", 256,
+      N_("list global configuration file") },
     { aCheckConfig,   "check-config", 256,
       N_("check global configuration file") },
 
@@ -104,6 +107,27 @@ my_strusage( int level )
 }
 
 
+/* Return the fp for the output.  This is usually stdout unless
+   --output has been used.  In the latter case this function opens
+   that file.  */
+static FILE *
+get_outfp (FILE **fp)
+{
+  if (!*fp)
+    {
+      if (opt.outfile)
+        {
+          *fp = fopen (opt.outfile, "w");
+          if (!*fp)
+            gc_error (1, errno, "can not open `%s'", opt.outfile);
+        }
+      else
+        *fp = stdout;
+    }
+  return *fp;
+}
+
+
 /* gpgconf main. */
 int
 main (int argc, char **argv)
@@ -112,6 +136,7 @@ main (int argc, char **argv)
   const char *fname;
   int no_more_options = 0;
   enum cmd_and_opt_values cmd = 0;
+  FILE *outfp = NULL;
 
   set_strusage (my_strusage);
   log_set_prefix ("gpgconf", 1);
@@ -143,6 +168,7 @@ main (int argc, char **argv)
         case aListOptions:
         case aChangeOptions:
         case aApplyDefaults:
+        case aListConfig:
         case aCheckConfig:
          cmd = pargs.r_opt;
          break;
@@ -161,12 +187,12 @@ main (int argc, char **argv)
     case aListComponents:
     default:
       /* List all components. */
-      gc_component_list_components (stdout);
+      gc_component_list_components (get_outfp (&outfp));
       break;
 
     case aCheckPrograms:
       /* Check all programs. */
-      gc_component_check_programs (stdout);
+      gc_component_check_programs (get_outfp (&outfp));
       break;
 
     case aListOptions:
@@ -189,17 +215,22 @@ main (int argc, char **argv)
              exit (1);
            }
          gc_component_retrieve_options (idx);
-          if (gc_process_gpgconf_conf (NULL, 1, 0))
+          if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
             exit (1);
          if (cmd == aListOptions)
-           gc_component_list_options (idx, stdout);
+           gc_component_list_options (idx, get_outfp (&outfp));
          else
             gc_component_change_options (idx, stdin);
        }
       break;
 
+    case aListConfig:
+      if (gc_process_gpgconf_conf (fname, 0, 0, get_outfp (&outfp)))
+        exit (1);
+      break;
+
     case aCheckConfig:
-      if (gc_process_gpgconf_conf (fname, 0, 0))
+      if (gc_process_gpgconf_conf (fname, 0, 0, NULL))
         exit (1);
       break;
 
@@ -213,14 +244,15 @@ main (int argc, char **argv)
          exit (2);
        }
       gc_component_retrieve_options (-1);
-      if (gc_process_gpgconf_conf (NULL, 1, 1))
+      if (gc_process_gpgconf_conf (NULL, 1, 1, NULL))
         exit (1);
       break;
-
     }
-  
-  return 0; 
-}
 
+  if (outfp && outfp != stdout)
+    if (fclose (outfp))
+      gc_error (1, errno, "error closing `%s'", opt.outfile);
 
+  return 0; 
+}
 
index f0d3c59..2f4bd52 100644 (file)
@@ -37,6 +37,8 @@ struct
 
 
 /*-- gpgconf-comp.c --*/
+void gc_error (int status, int errnum, const char *fmt, ...);
+
 /* List all components that are available.  */
 void gc_component_list_components (FILE *out);
 
@@ -58,7 +60,8 @@ void gc_component_list_options (int component, FILE *out);
 void gc_component_change_options (int component, FILE *in);
 
 /* Process global configuration file.  */
-int gc_process_gpgconf_conf (const char *fname, int update, int defaults);
+int gc_process_gpgconf_conf (const char *fname, int update, int defaults,
+                             FILE *listfp);
 
 
 #endif /*GPGCONF_H*/