Merge branch 'master' of ssh+git://playfair.gnupg.org/git/gpgme
[gpgme.git] / src / engine-gpgconf.c
1 /* engine-gpgconf.c - gpg-conf engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008,
4                  2013 g10 Code GmbH
5
6    This file is part of GPGME.
7
8    GPGME is free software; you can redistribute it and/or modify it
9    under the terms of the GNU Lesser General Public License as
10    published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    GPGME is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with this program; if not, see <https://www.gnu.org/licenses/>.
20  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 #ifdef HAVE_SYS_TYPES_H
29 # include <sys/types.h>
30 #endif
31 #include <assert.h>
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
35 #include <fcntl.h> /* FIXME */
36 #include <errno.h>
37
38 #include "gpgme.h"
39 #include "util.h"
40 #include "ops.h"
41 #include "wait.h"
42 #include "priv-io.h"
43 #include "sema.h"
44
45 #include "assuan.h"
46 #include "debug.h"
47
48 #include "engine-backend.h"
49
50
51 \f
52 struct engine_gpgconf
53 {
54   char *file_name;
55   char *home_dir;
56   char *version;
57 };
58
59 typedef struct engine_gpgconf *engine_gpgconf_t;
60
61 \f
62 /* Return true if the engine's version is at least VERSION.  */
63 static int
64 have_gpgconf_version (engine_gpgconf_t gpgconf, const char *version)
65 {
66   return _gpgme_compare_versions (gpgconf->version, version);
67 }
68
69
70 static char *
71 gpgconf_get_version (const char *file_name)
72 {
73   return _gpgme_get_program_version (file_name ? file_name
74                                      : _gpgme_get_default_gpgconf_name ());
75 }
76
77
78 static const char *
79 gpgconf_get_req_version (void)
80 {
81   return "2.0.4";
82 }
83
84 \f
85 static void
86 gpgconf_release (void *engine)
87 {
88   engine_gpgconf_t gpgconf = engine;
89
90   if (!gpgconf)
91     return;
92
93   if (gpgconf->file_name)
94     free (gpgconf->file_name);
95   if (gpgconf->home_dir)
96     free (gpgconf->home_dir);
97   if (gpgconf->version)
98     free (gpgconf->version);
99
100   free (gpgconf);
101 }
102
103
104 static gpgme_error_t
105 gpgconf_new (void **engine, const char *file_name, const char *home_dir,
106              const char *version)
107 {
108   gpgme_error_t err = 0;
109   engine_gpgconf_t gpgconf;
110
111   gpgconf = calloc (1, sizeof *gpgconf);
112   if (!gpgconf)
113     return gpg_error_from_syserror ();
114
115   gpgconf->file_name = strdup (file_name ? file_name
116                                : _gpgme_get_default_gpgconf_name ());
117   if (!gpgconf->file_name)
118     err = gpg_error_from_syserror ();
119
120   if (!err && home_dir)
121     {
122       gpgconf->home_dir = strdup (home_dir);
123       if (!gpgconf->home_dir)
124         err = gpg_error_from_syserror ();
125     }
126
127   if (!err && version)
128     {
129       gpgconf->version = strdup (version);
130       if (!gpgconf->version)
131         err = gpg_error_from_syserror ();
132     }
133
134   if (err)
135     gpgconf_release (gpgconf);
136   else
137     *engine = gpgconf;
138
139   return err;
140 }
141
142 \f
143 static void
144 release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
145 {
146   while (arg)
147     {
148       gpgme_conf_arg_t next = arg->next;
149
150       if (alt_type == GPGME_CONF_STRING)
151         free (arg->value.string);
152       free (arg);
153       arg = next;
154     }
155 }
156
157
158 static void
159 release_opt (gpgme_conf_opt_t opt)
160 {
161   if (opt->name)
162     free (opt->name);
163   if (opt->description)
164     free (opt->description);
165   if (opt->argname)
166     free (opt->argname);
167
168   release_arg (opt->default_value, opt->alt_type);
169   if (opt->default_description)
170     free (opt->default_description);
171
172   release_arg (opt->no_arg_value, opt->alt_type);
173   release_arg (opt->value, opt->alt_type);
174   release_arg (opt->new_value, opt->alt_type);
175
176   free (opt);
177 }
178
179
180 static void
181 release_comp (gpgme_conf_comp_t comp)
182 {
183   gpgme_conf_opt_t opt;
184
185   if (comp->name)
186     free (comp->name);
187   if (comp->description)
188     free (comp->description);
189   if (comp->program_name)
190     free (comp->program_name);
191
192   opt = comp->options;
193   while (opt)
194     {
195       gpgme_conf_opt_t next = opt->next;
196       release_opt (opt);
197       opt = next;
198     }
199
200   free (comp);
201 }
202
203
204 static void
205 gpgconf_config_release (gpgme_conf_comp_t conf)
206 {
207   while (conf)
208     {
209       gpgme_conf_comp_t next = conf->next;
210       release_comp (conf);
211       conf = next;
212     }
213 }
214
215 /* Read from gpgconf and pass line after line to the hook function.
216    We put a limit of 64 k on the maximum size for a line.  This should
217    allow for quite a long "group" line, which is usually the longest
218    line (mine is currently ~3k).  */
219 static gpgme_error_t
220 gpgconf_read (void *engine, const char *arg1, char *arg2,
221               gpgme_error_t (*cb) (void *hook, char *line),
222               void *hook)
223 {
224   struct engine_gpgconf *gpgconf = engine;
225   gpgme_error_t err = 0;
226   char *linebuf;
227   size_t linebufsize;
228   int linelen;
229   char *argv[6];
230   int argc = 0;
231   int rp[2];
232   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
233                                    {-1, -1} };
234   int status;
235   int nread;
236   char *mark = NULL;
237
238   /* _gpgme_engine_new guarantees that this is not NULL.  */
239   argv[argc++] = gpgconf->file_name;
240
241   if (gpgconf->home_dir && have_gpgconf_version (gpgconf, "2.1.13"))
242     {
243       argv[argc++] = (char*)"--homedir";
244       argv[argc++] = gpgconf->home_dir;
245     }
246
247   argv[argc++] = (char*)arg1;
248   argv[argc++] = arg2;
249   argv[argc] = NULL;
250   assert (argc < DIM (argv));
251
252   if (_gpgme_io_pipe (rp, 1) < 0)
253     return gpg_error_from_syserror ();
254
255   cfd[0].fd = rp[1];
256
257   status = _gpgme_io_spawn (gpgconf->file_name, argv,
258                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
259   if (status < 0)
260     {
261       _gpgme_io_close (rp[0]);
262       _gpgme_io_close (rp[1]);
263       return gpg_error_from_syserror ();
264     }
265
266   linebufsize = 1024; /* Usually enough for conf lines.  */
267   linebuf = malloc (linebufsize);
268   if (!linebuf)
269     {
270       err = gpg_error_from_syserror ();
271       goto leave;
272     }
273   linelen = 0;
274
275   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
276                                   linebufsize - linelen - 1)))
277     {
278       char *line;
279       const char *lastmark = NULL;
280       size_t nused;
281
282       if (nread < 0)
283         {
284           err = gpg_error_from_syserror ();
285           goto leave;
286         }
287
288       linelen += nread;
289       linebuf[linelen] = '\0';
290
291       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
292         {
293           lastmark = mark;
294           if (mark > line && mark[-1] == '\r')
295             mark[-1] = '\0';
296           else
297             mark[0] = '\0';
298
299           /* Got a full line.  Due to the CR removal code (which
300              occurs only on Windows) we might be one-off and thus
301              would see empty lines.  Don't pass them to the
302              callback. */
303           err = *line? (*cb) (hook, line) : 0;
304           if (err)
305             goto leave;
306         }
307
308       nused = lastmark? (lastmark + 1 - linebuf) : 0;
309       memmove (linebuf, linebuf + nused, linelen - nused);
310       linelen -= nused;
311
312       if (!(linelen < linebufsize - 1))
313         {
314           char *newlinebuf;
315
316           if (linelen <  8 * 1024 - 1)
317             linebufsize = 8 * 1024;
318           else if (linelen < 64 * 1024 - 1)
319             linebufsize = 64 * 1024;
320           else
321             {
322               /* We reached our limit - give up.  */
323               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
324               goto leave;
325             }
326
327           newlinebuf = realloc (linebuf, linebufsize);
328           if (!newlinebuf)
329             {
330               err = gpg_error_from_syserror ();
331               goto leave;
332             }
333           linebuf = newlinebuf;
334         }
335     }
336
337  leave:
338   free (linebuf);
339   _gpgme_io_close (rp[0]);
340   return err;
341 }
342
343
344 static gpgme_error_t
345 gpgconf_config_load_cb (void *hook, char *line)
346 {
347   gpgme_conf_comp_t *comp_p = hook;
348   gpgme_conf_comp_t comp = *comp_p;
349 #define NR_FIELDS 16
350   char *field[NR_FIELDS];
351   int fields = 0;
352
353   while (line && fields < NR_FIELDS)
354     {
355       field[fields++] = line;
356       line = strchr (line, ':');
357       if (line)
358         *(line++) = '\0';
359     }
360
361   /* We require at least the first 3 fields.  */
362   if (fields < 2)
363     return trace_gpg_error (GPG_ERR_INV_ENGINE);
364
365   /* Find the pointer to the new component in the list.  */
366   while (comp && comp->next)
367     comp = comp->next;
368   if (comp)
369     comp_p = &comp->next;
370
371   comp = calloc (1, sizeof (*comp));
372   if (!comp)
373     return gpg_error_from_syserror ();
374   /* Prepare return value.  */
375   comp->_last_opt_p = &comp->options;
376   *comp_p = comp;
377
378   comp->name = strdup (field[0]);
379   if (!comp->name)
380     return gpg_error_from_syserror ();
381
382   comp->description = strdup (field[1]);
383   if (!comp->description)
384     return gpg_error_from_syserror ();
385
386   if (fields >= 3)
387     {
388       comp->program_name = strdup (field[2]);
389       if (!comp->program_name)
390         return gpg_error_from_syserror ();
391     }
392
393   return 0;
394 }
395
396
397 static gpgme_error_t
398 gpgconf_parse_option (gpgme_conf_opt_t opt,
399                       gpgme_conf_arg_t *arg_p, char *line)
400 {
401   gpgme_error_t err;
402   char *mark = NULL;
403
404   if (!line[0])
405     return 0;
406
407   while (line)
408     {
409       gpgme_conf_arg_t arg;
410
411       if (opt->type != GPGME_CONF_STRING)
412         mark = strchr (line, ',');
413       if (mark)
414         *mark = '\0';
415
416       arg = calloc (1, sizeof (*arg));
417       if (!arg)
418         return gpg_error_from_syserror ();
419       *arg_p = arg;
420       arg_p = &arg->next;
421
422       if (*line == '\0')
423         arg->no_arg = 1;
424       else
425         {
426           switch (opt->alt_type)
427             {
428               /* arg->value.count is an alias for arg->value.uint32.  */
429             case GPGME_CONF_NONE:
430             case GPGME_CONF_UINT32:
431               arg->value.uint32 = strtoul (line, NULL, 0);
432               break;
433
434             case GPGME_CONF_INT32:
435               arg->value.uint32 = strtol (line, NULL, 0);
436               break;
437
438             case GPGME_CONF_STRING:
439               /* The complex types below are only here to silent the
440                  compiler warning. */
441             case GPGME_CONF_FILENAME:
442             case GPGME_CONF_LDAP_SERVER:
443             case GPGME_CONF_KEY_FPR:
444             case GPGME_CONF_PUB_KEY:
445             case GPGME_CONF_SEC_KEY:
446             case GPGME_CONF_ALIAS_LIST:
447               /* Skip quote character.  */
448               line++;
449
450               err = _gpgme_decode_percent_string (line, &arg->value.string,
451                                                   0, 0);
452               if (err)
453                 return err;
454               break;
455             }
456         }
457
458       /* Find beginning of next value.  */
459       if (mark++ && *mark)
460         line = mark;
461       else
462         line = NULL;
463     }
464
465   return 0;
466 }
467
468
469 static gpgme_error_t
470 gpgconf_config_load_cb2 (void *hook, char *line)
471 {
472   gpgme_error_t err;
473   gpgme_conf_comp_t comp = hook;
474   gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
475   gpgme_conf_opt_t opt;
476 #define NR_FIELDS 16
477   char *field[NR_FIELDS];
478   int fields = 0;
479
480   while (line && fields < NR_FIELDS)
481     {
482       field[fields++] = line;
483       line = strchr (line, ':');
484       if (line)
485         *(line++) = '\0';
486     }
487
488   /* We require at least the first 10 fields.  */
489   if (fields < 10)
490     return trace_gpg_error (GPG_ERR_INV_ENGINE);
491
492   opt = calloc (1, sizeof (*opt));
493   if (!opt)
494     return gpg_error_from_syserror ();
495
496   comp->_last_opt_p = &opt->next;
497   *opt_p = opt;
498
499   if (field[0][0])
500     {
501       opt->name = strdup (field[0]);
502       if (!opt->name)
503         return gpg_error_from_syserror ();
504     }
505
506   opt->flags = strtoul (field[1], NULL, 0);
507
508   opt->level = strtoul (field[2], NULL, 0);
509
510   if (field[3][0])
511     {
512       opt->description = strdup (field[3]);
513       if (!opt->description)
514         return gpg_error_from_syserror ();
515     }
516
517   opt->type = strtoul (field[4], NULL, 0);
518
519   opt->alt_type = strtoul (field[5], NULL, 0);
520
521   if (field[6][0])
522     {
523       opt->argname = strdup (field[6]);
524       if (!opt->argname)
525         return gpg_error_from_syserror ();
526     }
527
528   if (opt->flags & GPGME_CONF_DEFAULT)
529     {
530       err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
531       if (err)
532         return err;
533     }
534   else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
535     {
536       opt->default_description = strdup (field[7]);
537       if (!opt->default_description)
538         return gpg_error_from_syserror ();
539     }
540
541   if (opt->flags & GPGME_CONF_NO_ARG_DESC)
542     {
543       opt->no_arg_description = strdup (field[8]);
544       if (!opt->no_arg_description)
545         return gpg_error_from_syserror ();
546     }
547   else
548     {
549       err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
550       if (err)
551         return err;
552     }
553
554   err = gpgconf_parse_option (opt, &opt->value, field[9]);
555   if (err)
556     return err;
557
558   return 0;
559 }
560
561
562 static gpgme_error_t
563 gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
564 {
565   gpgme_error_t err;
566   gpgme_conf_comp_t comp = NULL;
567   gpgme_conf_comp_t cur_comp;
568
569   *comp_p = NULL;
570
571   err = gpgconf_read (engine, "--list-components", NULL,
572                       gpgconf_config_load_cb, &comp);
573   if (err)
574     {
575       gpgconf_release (comp);
576       return err;
577     }
578
579   cur_comp = comp;
580   while (!err && cur_comp)
581     {
582       err = gpgconf_read (engine, "--list-options", cur_comp->name,
583                           gpgconf_config_load_cb2, cur_comp);
584       cur_comp = cur_comp->next;
585     }
586
587   if (err)
588     {
589       gpgconf_release (comp);
590       return err;
591     }
592
593   *comp_p = comp;
594   return 0;
595 }
596
597
598 \f
599 gpgme_error_t
600 _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
601                      gpgme_conf_type_t type, const void *value)
602 {
603   gpgme_conf_arg_t arg;
604
605   arg = calloc (1, sizeof (*arg));
606   if (!arg)
607     return gpg_error_from_syserror ();
608
609   if (!value)
610     arg->no_arg = 1;
611   else
612     {
613       /* We need to switch on type here because the alt-type is not
614          yet known.  */
615       switch (type)
616         {
617         case GPGME_CONF_NONE:
618         case GPGME_CONF_UINT32:
619           arg->value.uint32 = *((unsigned int *) value);
620           break;
621
622         case GPGME_CONF_INT32:
623           arg->value.int32 = *((int *) value);
624           break;
625
626         case GPGME_CONF_STRING:
627         case GPGME_CONF_FILENAME:
628         case GPGME_CONF_LDAP_SERVER:
629         case GPGME_CONF_KEY_FPR:
630         case GPGME_CONF_PUB_KEY:
631         case GPGME_CONF_SEC_KEY:
632         case GPGME_CONF_ALIAS_LIST:
633           arg->value.string = strdup (value);
634           if (!arg->value.string)
635             {
636               free (arg);
637               return gpg_error_from_syserror ();
638             }
639           break;
640
641         default:
642           free (arg);
643           return gpg_error (GPG_ERR_INV_VALUE);
644         }
645     }
646
647   *arg_p = arg;
648   return 0;
649 }
650
651
652 void
653 _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
654 {
655   /* Lacking the alt_type we need to switch on type here.  */
656   switch (type)
657     {
658     case GPGME_CONF_NONE:
659     case GPGME_CONF_UINT32:
660     case GPGME_CONF_INT32:
661     case GPGME_CONF_STRING:
662     default:
663       break;
664
665     case GPGME_CONF_FILENAME:
666     case GPGME_CONF_LDAP_SERVER:
667     case GPGME_CONF_KEY_FPR:
668     case GPGME_CONF_PUB_KEY:
669     case GPGME_CONF_SEC_KEY:
670     case GPGME_CONF_ALIAS_LIST:
671       type = GPGME_CONF_STRING;
672       break;
673     }
674
675   release_arg (arg, type);
676 }
677
678
679 gpgme_error_t
680 _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
681 {
682   if (reset)
683     {
684       if (opt->new_value)
685         release_arg (opt->new_value, opt->alt_type);
686       opt->new_value = NULL;
687       opt->change_value = 0;
688     }
689   else
690     {
691       /* Support self-assignment, for example for adding an item to an
692          existing list.  */
693       if (opt->new_value && arg != opt->new_value)
694         release_arg (opt->new_value, opt->alt_type);
695       opt->new_value = arg;
696       opt->change_value = 1;
697     }
698   return 0;
699 }
700
701 \f
702 /* FIXME: Major problem: We don't get errors from gpgconf.  */
703
704 static gpgme_error_t
705 gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
706 {
707   struct engine_gpgconf *gpgconf = engine;
708   gpgme_error_t err = 0;
709 #define BUFLEN 1024
710   char buf[BUFLEN];
711   int buflen = 0;
712   char *argv[7];
713   int argc = 0;
714   int rp[2] = { -1, -1 };
715   int errp[2] = { -1, -1 };
716   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */},
717                                    {-1, 2 /* STDERR_FILENO */, -1},
718                                    {-1, -1} };
719   int status;
720   int nwrite;
721
722   /* _gpgme_engine_new guarantees that this is not NULL.  */
723   argv[argc++] = gpgconf->file_name;
724
725   if (gpgconf->home_dir && have_gpgconf_version (gpgconf, "2.1.13"))
726     {
727       argv[argc++] = (char*)"--homedir";
728       argv[argc++] = gpgconf->home_dir;
729     }
730
731   argv[argc++] = (char*)"--runtime";
732   argv[argc++] = (char*)arg1;
733   argv[argc++] = arg2;
734   argv[argc] = NULL;
735   assert (argc < DIM (argv));
736
737   if (_gpgme_io_pipe (rp, 0) < 0)
738     {
739       err = gpg_error_from_syserror ();
740       goto leave;
741     }
742
743   if (_gpgme_io_pipe (errp, 1) < 0)
744     {
745       err = gpg_error_from_syserror ();
746       goto leave;
747     }
748
749   cfd[0].fd = rp[0];
750   cfd[1].fd = errp[1];
751
752   status = _gpgme_io_spawn (gpgconf->file_name, argv,
753                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
754   if (status < 0)
755     {
756       err = gpg_error_from_syserror ();
757       goto leave;
758     }
759
760   rp[0] = -1;
761   errp[1] = -1;
762
763   for (;;)
764     {
765       if (buflen == 0)
766         {
767           do
768             {
769               buflen = gpgme_data_read (conf, buf, BUFLEN);
770             }
771           while (buflen < 0 && errno == EAGAIN);
772
773           if (buflen < 0)
774             {
775               err = gpg_error_from_syserror ();
776               goto leave;
777             }
778           else if (buflen == 0)
779             {
780               /* All is written.  */
781               _gpgme_io_close (rp[1]);
782               rp[1] = -1;
783
784               for (;;)
785                 {
786                   do
787                     {
788                       buflen = _gpgme_io_read (errp[0], buf, BUFLEN);
789                     }
790                   while (buflen < 0 && errno == EAGAIN);
791
792                   if (buflen == 0)
793                     {
794                       err = 0;
795                       goto leave;
796                     }
797                   /* XXX: Do something useful with BUF.  */
798                 }
799             }
800         }
801
802       do
803         {
804           nwrite = _gpgme_io_write (rp[1], buf, buflen);
805         }
806       while (nwrite < 0 && errno == EAGAIN);
807
808       if (nwrite > 0)
809         {
810           buflen -= nwrite;
811           if (buflen > 0)
812             memmove (&buf[0], &buf[nwrite], buflen);
813         }
814       else if (nwrite < 0)
815         {
816           err = gpg_error_from_syserror ();
817           goto leave;
818         }
819     }
820
821   assert (! "reached");
822
823  leave:
824   if (rp[0] != -1)
825     _gpgme_io_close (rp[0]);
826   if (rp[1] != -1)
827   _gpgme_io_close (rp[1]);
828   if (errp[0] != -1)
829     _gpgme_io_close (errp[0]);
830   if (errp[1] != -1)
831   _gpgme_io_close (errp[1]);
832
833   return err;
834 }
835
836
837 static gpgme_error_t
838 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
839 {
840   gpgme_error_t err = 0;
841   int amt = 0;
842   char buf[16];
843
844   while (amt >= 0 && arg)
845     {
846       switch (option->alt_type)
847         {
848         case GPGME_CONF_NONE:
849         case GPGME_CONF_UINT32:
850         default:
851           snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
852           buf[sizeof (buf) - 1] = '\0';
853           amt = gpgme_data_write (conf, buf, strlen (buf));
854           break;
855
856         case GPGME_CONF_INT32:
857           snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
858           buf[sizeof (buf) - 1] = '\0';
859           amt = gpgme_data_write (conf, buf, strlen (buf));
860           break;
861
862
863         case GPGME_CONF_STRING:
864           /* The complex types below are only here to silent the
865              compiler warning. */
866         case GPGME_CONF_FILENAME:
867         case GPGME_CONF_LDAP_SERVER:
868         case GPGME_CONF_KEY_FPR:
869         case GPGME_CONF_PUB_KEY:
870         case GPGME_CONF_SEC_KEY:
871         case GPGME_CONF_ALIAS_LIST:
872           if (arg->value.string)
873             {
874               /* One quote character, and three times to allow for
875                  percent escaping.  */
876               char *ptr = arg->value.string;
877               amt = gpgme_data_write (conf, "\"", 1);
878               if (amt < 0)
879                 break;
880
881               while (!err && *ptr)
882                 {
883                   switch (*ptr)
884                     {
885                     case '%':
886                       amt = gpgme_data_write (conf, "%25", 3);
887                       break;
888
889                     case ':':
890                       amt = gpgme_data_write (conf, "%3a", 3);
891                       break;
892
893                     case ',':
894                       amt = gpgme_data_write (conf, "%2c", 3);
895                       break;
896
897                     default:
898                       amt = gpgme_data_write (conf, ptr, 1);
899                     }
900                   ptr++;
901                 }
902             }
903           break;
904         }
905
906       if (amt < 0)
907         break;
908
909       arg = arg->next;
910       /* Comma separator.  */
911       if (arg)
912         amt = gpgme_data_write (conf, ",", 1);
913     }
914
915   if (amt < 0)
916     return gpg_error_from_syserror ();
917
918   return 0;
919 }
920
921
922 static gpgme_error_t
923 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
924 {
925   gpgme_error_t err;
926   int amt = 0;
927   /* We use a data object to store the new configuration.  */
928   gpgme_data_t conf;
929   gpgme_conf_opt_t option;
930   int something_changed = 0;
931
932   err = gpgme_data_new (&conf);
933   if (err)
934     return err;
935
936   option = comp->options;
937   while (!err && amt >= 0 && option)
938     {
939       if (option->change_value)
940         {
941           unsigned int flags = 0;
942           char buf[16];
943
944           something_changed = 1;
945
946           amt = gpgme_data_write (conf, option->name, strlen (option->name));
947           if (amt >= 0)
948             amt = gpgme_data_write (conf, ":", 1);
949           if (amt < 0)
950             break;
951
952           if (!option->new_value)
953             flags |= GPGME_CONF_DEFAULT;
954           snprintf (buf, sizeof (buf), "%u", flags);
955           buf[sizeof (buf) - 1] = '\0';
956
957           amt = gpgme_data_write (conf, buf, strlen (buf));
958           if (amt >= 0)
959             amt = gpgme_data_write (conf, ":", 1);
960           if (amt < 0)
961             break;
962
963           if (option->new_value)
964             {
965               err = arg_to_data (conf, option, option->new_value);
966               if (err)
967                 break;
968             }
969           amt = gpgme_data_write (conf, "\n", 1);
970         }
971       option = option->next;
972     }
973   if (!err && amt < 0)
974     err = gpg_error_from_syserror ();
975   if (err || !something_changed)
976     goto bail;
977
978   err = gpgme_data_seek (conf, 0, SEEK_SET);
979   if (err)
980     goto bail;
981
982   err = gpgconf_write (engine, "--change-options", comp->name, conf);
983  bail:
984   gpgme_data_release (conf);
985   return err;
986 }
987
988
989 struct gpgconf_config_dir_s
990 {
991   const char *what;
992   char *result;
993 };
994
995 /* Called for each line in the gpgconf --list-dirs output.  Searches
996    for the desired line and returns the result, indicating success by
997    a special error value GPG_ERR_USER_1 (which terminates the
998    operation immediately).  */
999 static gpgme_error_t
1000 gpgconf_config_dir_cb (void *hook, char *line)
1001 {
1002   /* This is an input- and output-parameter.  */
1003   struct gpgconf_config_dir_s *data = (struct gpgconf_config_dir_s *) hook;
1004   int len = strlen(data->what);
1005
1006   if (!strncmp(line, data->what, len) && line[len] == ':')
1007     {
1008       char *result = strdup(&line[len + 1]);
1009       if (!result)
1010         return gpg_error_from_syserror ();
1011       data->result = result;
1012       return gpg_error(GPG_ERR_USER_1);
1013     }
1014   return 0;
1015 }
1016
1017
1018 /* Like gpgme_get_dirinfo, but uses the home directory of ENGINE and
1019    does not cache the result.  */
1020 static gpgme_error_t
1021 gpgconf_conf_dir (void *engine, const char *what, char **result)
1022 {
1023   gpgme_error_t err;
1024   struct gpgconf_config_dir_s data;
1025
1026   data.what = what;
1027   data.result = NULL;
1028   err = gpgconf_read (engine, "--list-dirs", NULL,
1029                       gpgconf_config_dir_cb, &data);
1030   if (gpg_err_code (err) == GPG_ERR_USER_1)
1031     {
1032       /* This signals to us that a result was found.  */
1033       *result = data.result;
1034       return 0;
1035     }
1036
1037   if (!err)
1038     err = gpg_error(GPG_ERR_NOT_FOUND);
1039   return 0;
1040 }
1041
1042
1043 /* Parse a line received from gpgconf --query-swdb.  This function may
1044  * modify LINE.  The result is stored at RESUL.  */
1045 static gpg_error_t
1046 parse_swdb_line (char *line, gpgme_query_swdb_result_t result)
1047 {
1048   char *field[9];
1049   int fields = 0;
1050   gpg_err_code_t ec;
1051
1052   while (line && fields < DIM (field))
1053     {
1054       field[fields++] = line;
1055       line = strchr (line, ':');
1056       if (line)
1057         *line++ = 0;
1058     }
1059   /* We require that all fields exists - gpgme emits all these fields
1060    * even on error.  They might be empty, though. */
1061   if (fields < 9)
1062     return gpg_error (GPG_ERR_INV_ENGINE);
1063
1064   free (result->name);
1065   result->name = strdup (field[0]);
1066   if (!result->name)
1067     return gpg_error_from_syserror ();
1068
1069   free (result->iversion);
1070   result->iversion = strdup (field[1]);
1071   if (!result->iversion)
1072     return gpg_error_from_syserror ();
1073
1074   result->urgent = (strtol (field[3], NULL, 10) > 0);
1075
1076   ec = gpg_err_code (strtoul (field[4], NULL, 10));
1077
1078   result->created  = _gpgme_parse_timestamp (field[5], NULL);
1079   result->retrieved= _gpgme_parse_timestamp (field[6], NULL);
1080
1081   free (result->version);
1082   result->version  = strdup (field[7]);
1083   if (!result->version)
1084     return gpg_error_from_syserror ();
1085
1086   result->reldate  = _gpgme_parse_timestamp (field[8], NULL);
1087
1088   /* Set other flags.  */
1089   result->warning = !!ec;
1090   result->update = 0;
1091   result->noinfo = 0;
1092   result->unknown = 0;
1093   result->tooold = 0;
1094   result->error = 0;
1095
1096   switch (*field[2])
1097     {
1098     case '-': result->warning = 1; break;
1099     case '?': result->unknown = result->warning = 1; break;
1100     case 'u': result->update = 1; break;
1101     case 'c': break;
1102     case 'n': break;
1103     default:
1104       result->warning = 1;
1105       if (!ec)
1106         ec = GPG_ERR_INV_ENGINE;
1107       break;
1108     }
1109
1110   if (ec == GPG_ERR_TOO_OLD)
1111     result->tooold = 1;
1112   else if (ec == GPG_ERR_ENOENT)
1113     result->noinfo = 1;
1114   else if (ec)
1115     result->error = 1;
1116
1117
1118   return 0;
1119 }
1120
1121
1122 static gpgme_error_t
1123 gpgconf_query_swdb (void *engine,
1124                     const char *name, const char *iversion,
1125                     gpgme_query_swdb_result_t result)
1126 {
1127   struct engine_gpgconf *gpgconf = engine;
1128   gpgme_error_t err = 0;
1129   char *linebuf;
1130   size_t linebufsize;
1131   int linelen;
1132   char *argv[7];
1133   int argc = 0;
1134   int rp[2];
1135   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
1136                                    {-1, -1} };
1137   int status;
1138   int nread;
1139   char *mark = NULL;
1140
1141   if (!have_gpgconf_version (gpgconf, "2.1.16"))
1142     return gpg_error (GPG_ERR_ENGINE_TOO_OLD);
1143
1144   /* _gpgme_engine_new guarantees that this is not NULL.  */
1145   argv[argc++] = gpgconf->file_name;
1146
1147   if (gpgconf->home_dir)
1148     {
1149       argv[argc++] = (char*)"--homedir";
1150       argv[argc++] = gpgconf->home_dir;
1151     }
1152
1153   argv[argc++] = (char*)"--query-swdb";
1154   argv[argc++] = (char*)name;
1155   argv[argc++] = (char*)iversion;
1156   argv[argc] = NULL;
1157   assert (argc < DIM (argv));
1158
1159   if (_gpgme_io_pipe (rp, 1) < 0)
1160     return gpg_error_from_syserror ();
1161
1162   cfd[0].fd = rp[1];
1163
1164   status = _gpgme_io_spawn (gpgconf->file_name, argv,
1165                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
1166   if (status < 0)
1167     {
1168       _gpgme_io_close (rp[0]);
1169       _gpgme_io_close (rp[1]);
1170       return gpg_error_from_syserror ();
1171     }
1172
1173   linebufsize = 2048; /* Same as used by gpgconf.  */
1174   linebuf = malloc (linebufsize);
1175   if (!linebuf)
1176     {
1177       err = gpg_error_from_syserror ();
1178       goto leave;
1179     }
1180   linelen = 0;
1181
1182   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
1183                                   linebufsize - linelen - 1)))
1184     {
1185       char *line;
1186       const char *lastmark = NULL;
1187       size_t nused;
1188
1189       if (nread < 0)
1190         {
1191           err = gpg_error_from_syserror ();
1192           goto leave;
1193         }
1194
1195       linelen += nread;
1196       linebuf[linelen] = '\0';
1197
1198       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
1199         {
1200           lastmark = mark;
1201           if (mark > line && mark[-1] == '\r')
1202             mark[-1] = '\0';
1203           else
1204             mark[0] = '\0';
1205
1206           /* Got a full line.  Due to the CR removal code (which
1207              occurs only on Windows) we might be one-off and thus
1208              would see empty lines.  */
1209           if (*line)
1210             {
1211               err = parse_swdb_line (line, result);
1212               goto leave; /* Ready.  */
1213             }
1214           else /* empty line.  */
1215             err = 0;
1216         }
1217
1218       nused = lastmark? (lastmark + 1 - linebuf) : 0;
1219       memmove (linebuf, linebuf + nused, linelen - nused);
1220       linelen -= nused;
1221
1222       if (!(linelen < linebufsize - 1))
1223         {
1224           char *newlinebuf;
1225
1226           if (linelen <  8 * 1024 - 1)
1227             linebufsize = 8 * 1024;
1228           else if (linelen < 64 * 1024 - 1)
1229             linebufsize = 64 * 1024;
1230           else
1231             {
1232               /* We reached our limit - give up.  */
1233               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
1234               goto leave;
1235             }
1236
1237           newlinebuf = realloc (linebuf, linebufsize);
1238           if (!newlinebuf)
1239             {
1240               err = gpg_error_from_syserror ();
1241               goto leave;
1242             }
1243           linebuf = newlinebuf;
1244         }
1245     }
1246
1247  leave:
1248   free (linebuf);
1249   _gpgme_io_close (rp[0]);
1250   return err;
1251 }
1252
1253
1254 static void
1255 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1256 {
1257   (void)engine;
1258   (void)io_cbs;
1259   /* Nothing to do.  */
1260 }
1261
1262 \f
1263 /* Currently, we do not use the engine interface for the various
1264    operations.  */
1265 void
1266 _gpgme_conf_release (gpgme_conf_comp_t conf)
1267 {
1268   gpgconf_config_release (conf);
1269 }
1270
1271 \f
1272 struct engine_ops _gpgme_engine_ops_gpgconf =
1273   {
1274     /* Static functions.  */
1275     _gpgme_get_default_gpgconf_name,
1276     NULL,
1277     gpgconf_get_version,
1278     gpgconf_get_req_version,
1279     gpgconf_new,
1280
1281     /* Member functions.  */
1282     gpgconf_release,
1283     NULL,               /* reset */
1284     NULL,               /* set_status_cb */
1285     NULL,               /* set_status_handler */
1286     NULL,               /* set_command_handler */
1287     NULL,               /* set_colon_line_handler */
1288     NULL,               /* set_locale */
1289     NULL,               /* set_protocol */
1290     NULL,               /* set_engine_flags */
1291     NULL,               /* decrypt */
1292     NULL,               /* delete */
1293     NULL,               /* edit */
1294     NULL,               /* encrypt */
1295     NULL,               /* encrypt_sign */
1296     NULL,               /* export */
1297     NULL,               /* export_ext */
1298     NULL,               /* genkey */
1299     NULL,               /* import */
1300     NULL,               /* keylist */
1301     NULL,               /* keylist_ext */
1302     NULL,               /* keylist_data */
1303     NULL,               /* keysign */
1304     NULL,               /* tofu_policy */
1305     NULL,               /* sign */
1306     NULL,               /* trustlist */
1307     NULL,               /* verify */
1308     NULL,               /* getauditlog */
1309     NULL,               /* opassuan_transact */
1310     gpgconf_conf_load,
1311     gpgconf_conf_save,
1312     gpgconf_conf_dir,
1313     gpgconf_query_swdb,
1314     gpgconf_set_io_cbs,
1315     NULL,               /* io_event */
1316     NULL,               /* cancel */
1317     NULL,               /* cancel_op */
1318     NULL,               /* passwd */
1319     NULL,               /* set_pinentry_mode */
1320     NULL                /* opspawn */
1321   };