2004-01-29 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / tools / gpgconf-comp.c
1 /* gpgconf-comp.c - Configuration utility for GnuPG.
2    Copyright (C) 2003 g10 Code GmbH
3
4    This file is part of GnuPG.
5  
6    GnuPG is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10  
11    GnuPG is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15  
16    You should have received a copy of the GNU General Public License
17    along with GnuPG; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 /* FIXME use gettext.h */
27 #include <libintl.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <time.h>
34
35 #include <error.h>
36
37 #include "gpgconf.h"
38
39 \f
40 /* TODO:
41    Portability - Add gnulib replacements for getline, error, etc.
42    Backend: File backend must be able to write out changes !!!
43    Components: Add more components and their options.
44    Robustness: Do more validation.  Call programs to do validation for us.
45 */
46
47 \f
48 /* Backend configuration.  Backends are used to decide how the default
49    and current value of an option can be determined, and how the
50    option can be changed.  To every option in every component belongs
51    exactly one backend that controls and determines the option.  Some
52    backends are programs from the GPG system.  Others might be
53    implemented by GPGConf itself.  If you change this enum, don't
54    forget to update GC_BACKEND below.  */
55 typedef enum
56   {
57     /* Any backend, used for find_option ().  */
58     GC_BACKEND_ANY,
59
60     /* The Gnu Privacy Guard.  */
61     GC_BACKEND_GPG,
62
63     /* The Gnu Privacy Guard for S/MIME.  */
64     GC_BACKEND_GPGSM,
65
66     /* The GPG Agent.  */
67     GC_BACKEND_GPG_AGENT,
68
69     /* The Aegypten directory manager.  */
70     GC_BACKEND_DIRMNGR,
71
72     /* The LDAP server list file for the Aegypten director manager.  */
73     GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST,
74
75     /* The number of the above entries.  */
76     GC_BACKEND_NR
77   } gc_backend_t;
78
79
80 /* To be able to implement generic algorithms for the various
81    backends, we collect all information about them in this struct.  */
82 static struct
83 {
84   /* The name of the backend.  */
85   const char *name;
86
87   /* The name of the program that acts as the backend.  Some backends
88      don't have an associated program, but are implemented directly by
89      GPGConf.  In this case, PROGRAM is NULL.  */
90   char *program;
91
92   /* The option name for the configuration filename of this backend.
93      This must be an absolute pathname.  It can be an option from a
94      different backend (but then ordering of the options might
95      matter).  */
96   const char *option_config_filename;
97
98   /* If this is a file backend rather than a program backend, then
99      this is the name of the option associated with the file.  */
100   const char *option_name;
101 } gc_backend[GC_BACKEND_NR] =
102   {
103     { NULL, NULL, NULL },               /* GC_BACKEND_ANY dummy entry.  */
104     { "GnuPG", "gpg", "gpgconf-config-file" },
105     { "GPGSM", "gpgsm", "gpgconf-config-file" },
106     { "GPG Agent", "gpg-agent", "gpgconf-config-file" },
107     { "DirMngr", "dirmngr", "gpgconf-config-file" },
108     { "DirMngr LDAP Server List", NULL, "ldapserverlist-file", "LDAP Server" },
109   };
110
111 \f
112 /* Option configuration.  */
113
114 /* An option might take an argument, or not.  Argument types can be
115    basic or complex.  Basic types are generic and easy to validate.
116    Complex types provide more specific information about the intended
117    use, but can be difficult to validate.  If you add to this enum,
118    don't forget to update GC_ARG_TYPE below.  YOU MUST NOT CHANGE THE
119    NUMBERS OF THE EXISTING ENTRIES, AS THEY ARE PART OF THE EXTERNAL
120    INTERFACE.  */
121 typedef enum
122   {
123     /* Basic argument types.  */
124
125     /* No argument.  */
126     GC_ARG_TYPE_NONE = 0,
127
128     /* A String argument.  */
129     GC_ARG_TYPE_STRING = 1,
130
131     /* A signed integer argument.  */
132     GC_ARG_TYPE_INT32 = 2,
133
134     /* An unsigned integer argument.  */
135     GC_ARG_TYPE_UINT32 = 3,
136
137
138     /* Complex argument types.  */
139
140     /* A complete pathname.  */
141     GC_ARG_TYPE_PATHNAME = 4,
142
143     /* An LDAP server in the format
144        HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN.  */
145     GC_ARG_TYPE_LDAP_SERVER = 5,
146
147     /* A 40 character fingerprint.  */
148     GC_ARG_TYPE_KEY_FPR = 6,
149
150     /* ADD NEW ENTRIES HERE.  */
151
152     /* The number of the above entries.  */
153     GC_ARG_TYPE_NR
154   } gc_arg_type_t;
155
156
157 /* For every argument, we record some information about it in the
158    following struct.  */
159 static struct
160 {
161   /* For every argument type exists a basic argument type that can be
162      used as a fallback for input and validation purposes.  */
163   gc_arg_type_t fallback;
164
165   /* Human-readable name of the type.  */
166   const char *name;
167 } gc_arg_type[GC_ARG_TYPE_NR] =
168   {
169     /* The basic argument types have their own types as fallback.  */
170     { GC_ARG_TYPE_NONE, "none" },
171     { GC_ARG_TYPE_STRING, "string" },
172     { GC_ARG_TYPE_INT32, "int32" },
173     { GC_ARG_TYPE_UINT32, "uint32" },
174
175     /* The complex argument types have a basic type as fallback.  */
176     { GC_ARG_TYPE_STRING, "pathname" },
177     { GC_ARG_TYPE_STRING, "ldap server" },
178     { GC_ARG_TYPE_STRING, "key fpr" },
179   };
180
181
182 /* Every option has an associated expert level, than can be used to
183    hide advanced and expert options from beginners.  If you add to
184    this list, don't forget to update GC_LEVEL below.  YOU MUST NOT
185    CHANGE THE NUMBERS OF THE EXISTING ENTRIES, AS THEY ARE PART OF THE
186    EXTERNAL INTERFACE.  */
187 typedef enum
188   {
189     /* The basic options should always be displayed.  */
190     GC_LEVEL_BASIC,
191
192     /* The advanced options may be hidden from beginners.  */
193     GC_LEVEL_ADVANCED,
194
195     /* The expert options should only be displayed to experts.  */
196     GC_LEVEL_EXPERT,
197
198     /* The invisible options should normally never be displayed.  */
199     GC_LEVEL_INVISIBLE,
200
201     /* The internal options are never exported, they mark options that
202        are recorded for internal use only.  */
203     GC_LEVEL_INTERNAL,
204
205     /* ADD NEW ENTRIES HERE.  */
206
207     /* The number of the above entries.  */
208     GC_LEVEL_NR
209   } gc_expert_level_t;
210
211 /* A description for each expert level.  */
212 static struct
213 {
214   const char *name;
215 } gc_level[] =
216   {
217     { "basic" },
218     { "advanced" },
219     { "expert" },
220     { "invisible" },
221     { "internal" }
222   };
223
224
225 /* Option flags.  YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING
226    FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE.  */
227 #define GC_OPT_FLAG_NONE        0
228 /* Some entries in the option list are not options, but mark the
229    beginning of a new group of options.  These entries have the GROUP
230    flag set.  */
231 #define GC_OPT_FLAG_GROUP       (1 << 0)
232 /* The ARG_OPT flag for an option indicates that the argument is
233    optional.  */
234 #define GC_OPT_FLAG_ARG_OPT     (1 << 1)
235 /* The LIST flag for an option indicates that the option can occur
236    several times.  A comma separated list of arguments is used as the
237    argument value.  */
238 #define GC_OPT_FLAG_LIST        (1 << 2)
239 /* The RUNTIME flag for an option indicates that the option can be
240    changed at runtime.  */
241 #define GC_OPT_FLAG_RUNTIME     (1 << 3)
242
243 /* A human-readable description for each flag.  */
244 static struct
245 {
246   const char *name;
247 } gc_flag[] =
248   {
249     { "group" },
250     { "optional arg" },
251     { "list" },
252     { "runtime" }
253   };
254
255
256 /* To each option, or group marker, the information in the GC_OPTION
257    struct is provided.  If you change this, don't forget to update the
258    option list of each component.  */
259 struct gc_option
260 {
261   /* If this is NULL, then this is a terminator in an array of unknown
262      length.  Otherwise, if this entry is a group marker (see FLAGS),
263      then this is the name of the group described by this entry.
264      Otherwise it is the name of the option described by this
265      entry.  The name must not contain a colon.  */
266   const char *name;
267
268   /* The option flags.  If the GROUP flag is set, then this entry is a
269      group marker, not an option, and only the fields LEVEL,
270      DESC_DOMAIN and DESC are valid.  In all other cases, this entry
271      describes a new option and all fields are valid.  */
272   unsigned int flags;
273
274   /* The expert level.  This field is valid for options and groups.  A
275      group has the expert level of the lowest-level option in the
276      group.  */
277   gc_expert_level_t level;
278
279   /* A gettext domain in which the following description can be found.
280      If this is NULL, then DESC is not translated.  Valid for groups
281      and options.  */
282   const char *desc_domain;
283
284   /* A gettext description for this group or option.  If it starts
285      with a '|', then the string up to the next '|' describes the
286      argument, and the description follows the second '|'.  */
287   const char *desc;
288
289   /* The following fields are only valid for options.  */
290
291   /* The type of the option argument.  */
292   gc_arg_type_t arg_type;
293
294   /* The backend that implements this option.  */
295   gc_backend_t backend;
296
297   /* The following fields are set to NULL at startup (because all
298      option's are declared as static variables).  They are at the end
299      of the list so that they can be omitted from the option
300      declarations.  */
301
302   /* The default value for this option.  This is NULL if the option is
303      not present in the backend, the empty string if no default is
304      available, and otherwise a quoted string.  */
305   char *default_value;
306
307   /* The current value of this option.  */
308   char *value;
309
310   /* The new value of this option.  */
311   char *new_value;
312 };
313 typedef struct gc_option gc_option_t;
314
315 /* Use this macro to terminate an option list.  */
316 #define GC_OPTION_NULL { NULL }
317
318 \f
319 /* The options of the GC_COMPONENT_GPG_AGENT component.  */
320 static gc_option_t gc_options_gpg_agent[] =
321  {
322    GC_OPTION_NULL
323  };
324
325
326 /* The options of the GC_COMPONENT_DIRMNGR component.  */
327 static gc_option_t gc_options_dirmngr[] =
328  {
329    /* The configuration file to which we write the changes.  */
330    { "gpgconf-config-file", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
331      NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
332
333    { "Monitor",
334      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
335      NULL, "Options controlling the diagnostic output" },
336    { "verbose", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
337      "dirmngr", "verbose",
338      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
339    { "quiet", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
340      "dirmngr", "be somewhat more quiet",
341      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
342    { "no-greeting", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
343      NULL, NULL,
344      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
345
346    { "Format",
347      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
348      NULL, "Options controlling the format of the output" },
349    { "sh", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
350      "dirmngr", "sh-style command output",
351      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
352    { "csh", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
353      "dirmngr", "csh-style command output",
354      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
355    
356    { "Configuration",
357      GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
358      NULL, "Options controlling the configuration" },
359    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
360      "dirmngr", "|FILE|read options from FILE",
361      GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
362
363    { "Debug",
364      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
365      "dirmngr", "Options useful for debugging" },
366    { "debug", GC_OPT_FLAG_ARG_OPT, GC_LEVEL_ADVANCED,
367      "dirmngr", "|FLAGS|set the debugging FLAGS",
368      GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
369    { "debug-all", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
370      "dirmngr", "set all debugging flags",
371      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
372    { "no-detach", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
373      "dirmngr", "do not detach from the console",
374      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
375    { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
376      "dirmngr", "|FILE|write logs to FILE",
377      GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
378    { "debug-wait", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
379      NULL, NULL,
380      GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
381    { "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
382      NULL, NULL,
383      GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
384
385    { "Enforcement",
386      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
387      NULL, "Options controlling the interactivity and enforcement" },
388    { "batch", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
389      "dirmngr", "run without asking a user",
390      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
391    { "force", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
392      "dirmngr", "force loading of outdated CRLs",
393      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
394
395    { "LDAP",
396      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
397      NULL, "Configuration of LDAP servers to use" },
398    { "add-servers", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
399      "dirmngr", "add new servers discovered in CRL distribution points"
400      " to serverlist", GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
401    { "ldaptimeout", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
402      "dirmngr", "|N|set LDAP timeout to N seconds",
403      GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
404    /* The following entry must not be removed, as it is required for
405       the GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST.  */
406    { "ldapserverlist-file",
407      GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
408      "dirmngr", "|FILE|read LDAP server list from FILE",
409      GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
410    /* This entry must come after at least one entry for
411       GC_BACKEND_DIRMNGR in this component, so that the entry for
412       "ldapserverlist-file will be initialized before this one.  */
413    { "LDAP Server", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
414      NULL, "LDAP server list",
415      GC_ARG_TYPE_LDAP_SERVER, GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST },
416
417    { "CRL",
418      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
419      NULL, "Configuration of the CRL" },
420    { "max-replies", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
421      "dirmngr", "|N|do not return more than N items in one query",
422      GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
423
424    GC_OPTION_NULL
425  };
426
427 \f
428 /* Component system.  Each component is a set of options that can be
429    configured at the same time.  If you change this, don't forget to
430    update GC_COMPONENT below.  */
431 typedef enum
432   {
433     /* The GPG Agent.  */
434     GC_COMPONENT_GPG_AGENT,
435
436     /* The LDAP Directory Manager for CRLs.  */
437     GC_COMPONENT_DIRMNGR,
438
439     /* The number of components.  */
440     GC_COMPONENT_NR
441   } gc_component_t;
442
443
444 /* The information associated with each component.  */
445 static struct
446 {
447   /* The name of this component.  Must not contain a colon (':')
448      character.  */
449   const char *name;
450
451   /* The gettext domain for the description DESC.  If this is NULL,
452      then the description is not translated.  */
453   const char *desc_domain;
454
455   /* The description for this domain.  */
456   const char *desc;
457
458   /* The list of options for this component, terminated by
459      GC_OPTION_NULL.  */
460   gc_option_t *options;
461 } gc_component[] =
462   {
463     { "gpg-agent", NULL, "GPG Agent", gc_options_gpg_agent },
464     { "dirmngr", NULL, "CRL Manager", gc_options_dirmngr }
465   };
466
467 \f
468 /* Robust version of dgettext.  */
469 static const char *
470 my_dgettext (const char *domain, const char *msgid)
471 {
472   if (domain)
473     {
474       char *text = dgettext (domain, msgid);
475       return text ? text : msgid;
476     }
477   else
478     return msgid;
479 }
480
481
482 /* Percent-Escape special characters.  The string is valid until the
483    next invocation of the function.  */
484 static char *
485 percent_escape (const char *src)
486 {
487   static char *esc_str;
488   static int esc_str_len;
489   int new_len = 3 * strlen (src) + 1;
490   char *dst;
491
492   if (esc_str_len < new_len)
493     {
494       char *new_esc_str = realloc (esc_str, new_len);
495       if (!new_esc_str)
496         error (1, 1, "Can not escape string");
497       esc_str = new_esc_str;
498       esc_str_len = new_len;
499     }
500
501   dst = esc_str;
502   while (*src)
503     {
504       if (*src == '%')
505         {
506           *(dst++) = '%';
507           *(dst++) = '2';
508           *(dst++) = '5';
509         }         
510       else if (*src == ':')
511         {
512           /* The colon is used as field separator.  */
513           *(dst++) = '%';
514           *(dst++) = '3';
515           *(dst++) = 'a';
516         }
517       else if (*src == ',')
518         {
519           /* The comma is used as list separator.  */
520           *(dst++) = '%';
521           *(dst++) = '2';
522           *(dst++) = 'c';
523         }
524       else
525         *(dst++) = *(src);
526       src++;
527     }
528   *dst = '\0';
529   return esc_str;
530 }
531
532
533 \f
534 /* List all components that are available.  */
535 void
536 gc_component_list_components (FILE *out)
537 {
538   gc_component_t idx;
539
540   for (idx = 0; idx < GC_COMPONENT_NR; idx++)
541     {
542       const char *desc = gc_component[idx].desc;
543       desc = my_dgettext (gc_component[idx].desc_domain, desc);
544       fprintf (out, "%s:%s\n", gc_component[idx].name, percent_escape (desc));
545     }
546 }
547
548 \f
549 /* Find the component with the name NAME.  Returns -1 if not
550    found.  */
551 int
552 gc_component_find (const char *name)
553 {
554   gc_component_t idx;
555
556   for (idx = 0; idx < GC_COMPONENT_NR; idx++)
557     {
558       if (!strcmp (name, gc_component[idx].name))
559         return idx;
560     }
561   return -1;
562 }
563
564 \f
565 /* List all options of the component COMPONENT.  */
566 void
567 gc_component_list_options (int component, FILE *out)
568 {  
569   const gc_option_t *option = gc_component[component].options;
570
571   while (option->name)
572     {
573       const char *desc = NULL;
574       char *arg_name = NULL;
575
576       /* Do not output unknown or internal options.  */
577       if (!option->default_value || option->level == GC_LEVEL_INTERNAL)
578         {
579           option++;
580           continue;
581         }
582
583       if (option->desc)
584         {
585           desc = my_dgettext (option->desc_domain, option->desc);
586
587           if (*desc == '|')
588             {
589               const char *arg_tail = strchr (&desc[1], '|');
590
591               if (arg_tail)
592                 {
593                   int arg_len = arg_tail - &desc[1];
594                   arg_name = malloc (arg_len + 1);
595                   if (!arg_name)
596                     error (1, 1, "Can not build argument name");
597                   memcpy (arg_name, &desc[1], arg_len);
598                   arg_name[arg_len] = '\0';
599                   desc = arg_tail + 1;
600                 }
601             }
602         }
603
604       /* YOU MUST NOT REORDER THE FIELDS IN THIS OUTPUT, AS THEIR
605          ORDER IS PART OF THE EXTERNAL INTERFACE.  YOU MUST NOT REMOVE
606          ANY FIELDS.  */
607
608       /* The name field.  */
609       fprintf (out, "%s", option->name);
610
611       /* The flags field.  */
612       fprintf (out, ":%u", option->flags);
613       if (opt.verbose)
614         {
615           putc (' ', out);
616           
617           if (!option->flags)
618             fprintf (out, "none");
619           else
620             {
621               unsigned int flags = option->flags;
622               unsigned int flag = 0;
623               unsigned int first = 1;
624
625               while (flags)
626                 {
627                   if (flags & 1)
628                     {
629                       if (first)
630                         first = 0;
631                       else
632                         putc (',', out);
633                       fprintf (out, "%s", gc_flag[flag].name);
634                     }
635                   flags >>= 1;
636                   flag++;
637                 }
638             }
639         }
640
641       /* The level field.  */
642       fprintf (out, ":%u", option->level);
643       if (opt.verbose)
644         fprintf (out, " %s", gc_level[option->level].name);
645
646       /* The description field.  */
647       fprintf (out, ":%s", desc ? percent_escape (desc) : "");
648
649       /* The type field.  */
650       fprintf (out, ":%u", option->arg_type);
651       if (opt.verbose)
652         fprintf (out, " %s", gc_arg_type[option->arg_type].name);
653
654       /* The alternate type field.  */
655       fprintf (out, ":%u", gc_arg_type[option->arg_type].fallback);
656       if (opt.verbose)
657         fprintf (out, " %s",
658                  gc_arg_type[gc_arg_type[option->arg_type].fallback].name);
659
660       /* The argument name field.  */
661       fprintf (out, ":%s", arg_name ? percent_escape (arg_name) : "");
662       if (arg_name)
663         free (arg_name);
664
665       /* The default value field.  */
666       fprintf (out, ":%s", option->default_value ? option->default_value : "");
667
668       /* The value field.  */
669       fprintf (out, ":%s", option->value ? option->value : "");
670
671       /* ADD NEW FIELDS HERE.  */
672
673       putc ('\n', out);
674       option++;
675     }
676 }
677
678
679 /* Find the option NAME in component COMPONENT, for the backend
680    BACKEND.  If BACKEND is GC_BACKEND_ANY, any backend will match.  */
681 static gc_option_t *
682 find_option (gc_component_t component, const char *name,
683              gc_backend_t backend)
684 {
685   gc_option_t *option = gc_component[component].options;
686   while (option->name)
687     {
688       if (!(option->flags & GC_OPT_FLAG_GROUP)
689           && !strcmp (option->name, name)
690           && (backend == GC_BACKEND_ANY || option->backend == backend))
691         break;
692       option++;
693     }
694   return option->name ? option : NULL;
695 }
696
697 \f
698 /* Determine the configuration pathname for the component COMPONENT
699    and backend BACKEND.  */
700 static char *
701 get_config_pathname (gc_component_t component, gc_backend_t backend)
702 {
703   char *pathname;
704   gc_option_t *option = find_option
705     (component, gc_backend[backend].option_config_filename, GC_BACKEND_ANY);
706   assert (option);
707
708   if (!option->default_value)
709     error (1, 0, "Option %s, needed by backend %s, was not initialized",
710            gc_backend[backend].option_config_filename,
711            gc_backend[backend].name);
712   if (*option->value)
713     pathname = option->value;
714   else
715     pathname = option->default_value;
716
717   if (*pathname != '/')
718     error (1, 0, "Option %s, needed by backend %s, is not absolute",
719            gc_backend[backend].option_config_filename,
720            gc_backend[backend].name);
721
722   return pathname;
723 }
724
725 \f
726 /* Retrieve the options for the component COMPONENT from backend
727    BACKEND, which we already know is a program-type backend.  */
728 static void
729 retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
730 {
731   char *cmd_line;
732   char *line = NULL;
733   size_t line_len = 0;
734   ssize_t length;
735   FILE *output;
736
737   asprintf (&cmd_line, "%s --gpgconf-list", gc_backend[backend].program);
738   if (!cmd_line)
739     error (1, 1, "Can not construct command line");
740
741   output = popen (cmd_line, "r");
742   if (!output)
743     error (1, 1, "Could not gather active options from %s", cmd_line);
744
745   while ((length = getline (&line, &line_len, output)) > 0)
746     {
747       gc_option_t *option;
748       char *default_value;
749       char *value;
750
751       /* Strip newline and carriage return, if present.  */
752       while (length > 0
753              && (line[length - 1] == '\n' || line[length - 1] == '\r'))
754         line[--length] = '\0';
755
756       /* Extract default value and value, if present.  Default to
757          empty if not.  */
758       default_value = strchr (line, ':');
759       if (!default_value)
760         {
761           default_value = "";
762           value = "";
763         }
764       else
765         {
766           *(default_value++) = '\0';
767           value = strchr (default_value, ':');
768           if (!value)
769             value = "";
770           else
771             {
772               char *end;
773
774               *(value++) = '\0';
775               end = strchr (value, ':');
776               if (end)
777                 *end = '\0';
778             }
779         }
780
781       /* Look up the option in the component and install the
782          configuration data.  */
783       option = find_option (component, line, backend);
784       if (option)
785         {
786           if (option->default_value)
787             error (1, 1, "Option %s returned twice from %s",
788                    line, cmd_line);
789           option->default_value = strdup (default_value);
790           option->value = strdup (value);
791           if (!option->default_value || !option->value)
792             error (1, 1, "Could not store options");
793         }
794     }
795   if (ferror (output))
796     error (1, 1, "Error reading from %s", cmd_line);
797   if (fclose (output) && ferror (output))
798     error (1, 1, "Error closing %s", cmd_line);
799   free (cmd_line);
800 }
801
802
803 /* Retrieve the options for the component COMPONENT from backend
804    BACKEND, which we already know is of type file list.  */ 
805 static void
806 retrieve_options_from_file (gc_component_t component, gc_backend_t backend)
807 {
808   gc_option_t *list_option;
809   char *list_pathname;
810   FILE *list_file;
811   char *line = NULL;
812   size_t line_len = 0;
813   ssize_t length;
814   char *list;
815
816   list_option = find_option (component,
817                              gc_backend[backend].option_name, GC_BACKEND_ANY);
818   assert (list_option);
819
820   list_pathname = get_config_pathname (component, backend);
821
822   list_file = fopen (list_pathname, "r");
823   if (ferror (list_file))
824     error (1, 1, "Can not open list file %s", list_pathname);
825
826   list = strdup ("\"");
827   if (!list)
828     error (1, 1, "Can not allocate initial list string");
829
830   while ((length = getline (&line, &line_len, list_file)) > 0)
831     {
832       char *start;
833       char *end;
834       char *new_list;
835
836       start = line;
837       while (*start == ' ' || *start == '\t')
838         start++;
839       if (!*start || *start == '#' || *start == '\r' || *start == '\n')
840         continue;
841
842       end = start;
843       while (*end && *end != '#' && *end != '\r' && *end != '\n')
844         end++;
845       /* Walk back to skip trailing white spaces.  Looks evil, but
846          works because of the conditions on START and END imposed
847          at this point (END is at least START + 1, and START is
848          not a whitespace character).  */
849       while (*(end - 1) == ' ' || *(end - 1) == '\t')
850         end--;
851       *end = '\0';
852       /* FIXME: Oh, no!  This is so lame!  Use realloc and really
853          append.  */
854       if (list)
855         {
856           asprintf (&new_list, "%s,%s", list, percent_escape (start));
857           free (list);
858           list = new_list;
859         }
860       if (!list)
861         error (1, 1, "Can not construct list");
862     }
863   if (ferror (list_file))
864     error (1, 1, "Can not read list file %s", list_pathname);
865   list_option->default_value = "";
866   list_option->value = list;
867 }
868
869
870 /* Retrieve the currently active options and their defaults from all
871    involved backends for this component.  */
872 void
873 gc_component_retrieve_options (int component)
874 {
875   int backend_seen[GC_BACKEND_NR];
876   gc_backend_t backend;
877   gc_option_t *option = gc_component[component].options;
878
879   for (backend = 0; backend < GC_BACKEND_NR; backend++)
880     backend_seen[backend] = 0;
881
882   while (option->name)
883     {
884       if (!(option->flags & GC_OPT_FLAG_GROUP))
885         {
886           backend = option->backend;
887
888           if (backend_seen[backend])
889             {
890               option++;
891               continue;
892             }
893           backend_seen[backend] = 1;
894
895           assert (backend != GC_BACKEND_ANY);
896
897           if (gc_backend[backend].program)
898             retrieve_options_from_program (component, backend);
899           else
900             retrieve_options_from_file (component, backend);
901         }
902       option++;
903     }
904 }
905
906 \f
907 /* Perform a simple validity check based on the type.  */
908 static void
909 option_check_validity (gc_option_t *option, const char *new_value)
910 {
911   if (option->new_value)
912     error (1, 0, "Option %s already changed", option->name);
913
914   if (!*new_value)
915     return;
916
917   /* FIXME.  Verify that lists are lists, numbers are numbers, strings
918      are strings, etc.  */
919 }
920
921
922 /* Create and verify the new configuration file for the specified
923    backend and component.  Returns 0 on success and -1 on error.  */
924 static int
925 change_options_file (gc_component_t component, gc_backend_t backend,
926                      char **src_filenamep, char **dest_filenamep,
927                      char **orig_filenamep)
928 {
929   /* FIXME.  */
930   assert (!"Not implemented.");
931   return -1;
932 }
933
934
935 /* Create and verify the new configuration file for the specified
936    backend and component.  Returns 0 on success and -1 on error.  */
937 static int
938 change_options_program (gc_component_t component, gc_backend_t backend,
939                         char **src_filenamep, char **dest_filenamep,
940                         char **orig_filenamep)
941 {
942   static const char marker[] = "###+++--- GPGConf ---+++###";
943   /* True if we are within the marker in the config file.  */
944   int in_marker = 0;
945   gc_option_t *option;
946 #define LINE_LEN 4096
947   char line[LINE_LEN];
948   int res;
949   int fd;
950   FILE *src_file = NULL;
951   FILE *dest_file = NULL;
952   char *src_filename;
953   char *dest_filename;
954   char *orig_filename;
955
956   /* FIXME.  Throughout the function, do better error reporting.  */
957   dest_filename = strdup (get_config_pathname (component, backend));
958   if (!dest_filename)
959     return -1;
960   asprintf (&src_filename, "%s.gpgconf.%i.new", dest_filename, getpid ());
961   if (!src_filename)
962     return -1;
963   asprintf (&orig_filename, "%s.gpgconf.%i.bak", dest_filename, getpid ());
964   if (!orig_filename)
965     return -1;
966
967   res = link (dest_filename, orig_filename);
968   if (res < 0 && errno != ENOENT)
969     return -1;
970   if (res < 0)
971     {
972       free (orig_filename);
973       orig_filename = NULL;
974     }
975   /* We now initialize the return strings, so the caller can do the
976      cleanup for us.  */
977   *src_filenamep = src_filename;
978   *dest_filenamep = dest_filename;
979   *orig_filenamep = orig_filename;
980
981   /* Use open() so that we can use O_EXCL.  */
982   fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
983   if (fd < 0)
984     return -1;
985   src_file = fdopen (fd, "w");
986   res = errno;
987   if (!src_file)
988     {
989       errno = res;
990       return -1;
991     }
992
993   /* Only if ORIG_FILENAME is not NULL did the configuration file
994      exist already.  In this case, we will copy its content into the
995      new configuration file, changing it to our liking in the
996      process.  */
997   if (orig_filename)
998     {
999       dest_file = fopen (dest_filename, "r");
1000       if (!dest_file)
1001         goto change_one_err;
1002
1003       while (fgets (line, LINE_LEN, dest_file))
1004         {
1005           int length;
1006           int disable = 0;
1007           char *start;
1008           char *end;
1009
1010           line[LINE_LEN - 1] = '\0';
1011           length = strlen (line);
1012           if (length == LINE_LEN - 1)
1013             {
1014               /* FIXME */
1015               errno = ENAMETOOLONG;
1016               goto change_one_err;
1017             }
1018
1019           if (!strncmp (marker, line, sizeof (marker) - 1))
1020             {
1021               if (!in_marker)
1022                 in_marker = 1;
1023               else
1024                 break;
1025             }
1026
1027           start = line;
1028           while (*start == ' ' || *start == '\t')
1029             start++;
1030           if (*start && *start != '\r' && *start != '\n' && *start != '#')
1031             {
1032               char saved_end;
1033
1034               end = start;
1035               while (*end && *end != ' ' && *end != '\t'
1036                      && *end != '\r' && *end != '\n' && *end != '#')
1037                 end++;
1038               saved_end = *end;
1039               *end = '\0';
1040
1041               option = find_option (component, start, backend);
1042               *end = saved_end;
1043               if (option && option->new_value)
1044                 disable = 1;
1045             }
1046           if (disable)
1047             {
1048               if (!in_marker)
1049                 {
1050                   fprintf (src_file,
1051                            "# GPGConf disabled this option here at FIXME\n");
1052                   if (ferror (src_file))
1053                     goto change_one_err;
1054                   fprintf (src_file, "# %s", line);
1055                   if (ferror (src_file))
1056                     goto change_one_err;
1057                 }
1058             }
1059           else
1060             {
1061               fprintf (src_file, "%s", line);
1062               if (ferror (src_file))
1063                 goto change_one_err;
1064             }
1065         }
1066       if (ferror (dest_file))
1067         goto change_one_err;
1068     }
1069
1070   if (!in_marker)
1071     {
1072       /* There was no marker.  This is the first time we edit the
1073          file.  We add our own marker at the end of the file and
1074          proceed.  Note that we first write a newline, this guards us
1075          against files which lack the newline at the end of the last
1076          line, while it doesn't hurt us in all other cases.  */
1077       fprintf (src_file, "\n%s\n", marker);
1078       if (ferror (src_file))
1079         goto change_one_err;
1080     }
1081   /* At this point, we have copied everything up to the end marker
1082      into the new file, except for the options we are going to change.
1083      Now, dump the changed options (except for those we are going to
1084      revert to their default), and write the end marker, possibly
1085      followed by the rest of the original file.  */
1086   option = gc_component[component].options;
1087   while (option->name)
1088     {
1089       if (!(option->flags & GC_OPT_FLAG_GROUP)
1090           && option->backend == backend
1091           && option->new_value
1092           && *option->new_value)
1093         {
1094           if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_STRING)
1095             fprintf (src_file, "%s %s\n", option->name, &option->new_value[1]);
1096           else if (option->arg_type == GC_ARG_TYPE_NONE)
1097             fprintf (src_file, "%s\n", option->name);
1098           else
1099             fprintf (src_file, "%s %s\n", option->name, option->new_value);
1100           if (ferror (src_file))
1101             goto change_one_err;
1102         }
1103       option++;
1104     }
1105   {
1106     time_t cur_time = time (NULL);
1107     
1108     /* asctime() returns a string that ends with a newline
1109        character!  */
1110     fprintf (src_file, "%s %s", marker, asctime (localtime (&cur_time)));
1111     if (ferror (src_file))
1112       goto change_one_err;
1113   }
1114   if (!in_marker)
1115     {
1116       fprintf (src_file, "# GPGConf edited this configuration file.\n");
1117       if (ferror (src_file))
1118         goto change_one_err;
1119       fprintf (src_file, "# It will disable options before this marked "
1120                "block, but it will\n");
1121       if (ferror (src_file))
1122         goto change_one_err;
1123       fprintf (src_file, "# never change anything below these lines.\n");
1124       if (ferror (src_file))
1125         goto change_one_err;
1126     }
1127   if (dest_file)
1128     {
1129       while (fgets (line, LINE_LEN, dest_file))
1130         {
1131           int length;
1132
1133           line[LINE_LEN - 1] = '\0';
1134           length = strlen (line);
1135           if (length == LINE_LEN - 1)
1136             {
1137               /* FIXME */
1138               errno = ENAMETOOLONG;
1139               goto change_one_err;
1140             }
1141           fprintf (src_file, "%s", line);
1142           if (ferror (src_file))
1143             goto change_one_err;
1144         }
1145       if (ferror (dest_file))
1146         goto change_one_err;
1147     }
1148   res = fclose (src_file);
1149   if (res)
1150     {
1151       res = errno;
1152       close (fd);
1153       if (dest_file)
1154         fclose (dest_file);
1155       errno = res;
1156       return -1;
1157     }
1158   close (fd);
1159   if (dest_file)
1160     {
1161       res = fclose (dest_file);
1162       if (res)
1163         return -1;
1164     }
1165   return 0;
1166
1167  change_one_err:
1168   res = errno;
1169   if (src_file)
1170     {
1171       fclose (src_file);
1172       close (fd);
1173     }
1174   if (dest_file)
1175     fclose (dest_file);
1176   errno = res;
1177   return -1;
1178 }
1179
1180 /* Read the modifications from IN and apply them.  */
1181 void
1182 gc_component_change_options (int component, FILE *in)
1183 {
1184   int err = 0;
1185   char *src_pathname[GC_BACKEND_NR];
1186   char *dest_pathname[GC_BACKEND_NR];
1187   char *orig_pathname[GC_BACKEND_NR];
1188   gc_backend_t backend;
1189   gc_option_t *option;
1190   char *line = NULL;
1191   size_t line_len = 0;
1192   ssize_t length;
1193
1194   for (backend = 0; backend < GC_BACKEND_NR; backend++)
1195     {
1196       src_pathname[backend] = NULL;
1197       dest_pathname[backend] = NULL;
1198       orig_pathname[backend] = NULL;
1199     }
1200
1201   while ((length = getline (&line, &line_len, in)) > 0)
1202     {
1203       char *value;
1204
1205       /* Strip newline and carriage return, if present.  */
1206       while (length > 0
1207              && (line[length - 1] == '\n' || line[length - 1] == '\r'))
1208         line[--length] = '\0';
1209
1210       value = strchr (line, ':');
1211       if (!value)
1212         value = "";
1213       else
1214         {
1215           char *end;
1216
1217           *(value++) = '\0';
1218           end = strchr (value, ':');
1219           if (end)
1220             *end = '\0';
1221         }
1222
1223       option = find_option (component, line, GC_BACKEND_ANY);
1224       if (!option)
1225         error (1, 0, "Unknown option %s", line);
1226
1227       option_check_validity (option, value);
1228       option->new_value = strdup (value);
1229     }
1230
1231   /* Now that we have collected and locally verified the changes,
1232      write them out to new configuration files, verify them
1233      externally, and then commit them.  */
1234   option = gc_component[component].options;
1235   while (option->name)
1236     {
1237       /* Go on if we have already seen this backend, or if there is
1238          nothing to do.  */
1239       if (src_pathname[option->backend] || !option->new_value)
1240         {
1241           option++;
1242           continue;
1243         }
1244
1245       if (gc_backend[option->backend].program)
1246         err = change_options_program (component, option->backend,
1247                                       &src_pathname[component],
1248                                       &dest_pathname[component],
1249                                       &orig_pathname[component]);
1250       else
1251         err = change_options_file (component, option->backend,
1252                                    &src_pathname[component],
1253                                    &dest_pathname[component],
1254                                    &orig_pathname[component]);
1255         
1256       if (err)
1257         break;
1258           
1259       option++;
1260     }
1261   if (!err)
1262     {
1263       int i;
1264
1265       for (i = 0; i < GC_COMPONENT_NR; i++)
1266         {
1267           if (src_pathname[i])
1268             {
1269               /* FIXME: Make a verification here.  */
1270
1271               assert (dest_pathname[i]);
1272
1273               if (orig_pathname[i])
1274                 err = rename (src_pathname[i], dest_pathname[i]);
1275               else
1276                 {
1277                   /* This is a bit safer than rename() because we
1278                      expect DEST_PATHNAME not to be there.  If it
1279                      happens to be there, this will fail.  */
1280                   err = link (src_pathname[i], dest_pathname[i]);
1281                   if (!err)
1282                     unlink (src_pathname[i]);
1283                 }
1284               if (err)
1285                 break;
1286               src_pathname[i] = NULL;
1287             }
1288         }
1289     }
1290
1291   if (err)
1292     {
1293       int i;
1294       int res = errno;
1295
1296       /* An error occured.  */
1297       for (i = 0; i < GC_COMPONENT_NR; i++)
1298         {
1299           if (src_pathname[i])
1300             {
1301               /* The change was not yet committed.  */
1302               unlink (src_pathname[i]);
1303               if (orig_pathname[i])
1304                 unlink (orig_pathname[i]);
1305             }
1306           else
1307             {
1308               /* The changes were already committed.  FIXME: This is a
1309                  tad dangerous, as we don't know if we don't overwrite
1310                  a version of the file that is even newer than the one
1311                  we just installed.  */
1312               if (orig_pathname[i])
1313                 rename (orig_pathname[i], dest_pathname[i]);
1314               else
1315                 unlink (dest_pathname[i]);
1316             }
1317         }
1318       errno = res;
1319       error (1, 1, "Could not commit changes");
1320     }
1321 }