core: Don't split gpgconf strings on comma
[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 /* Parse a line received from gpgconf --query-swdb.  This function may
990  * modify LINE.  The result is stored at RESUL.  */
991 static gpg_error_t
992 parse_swdb_line (char *line, gpgme_query_swdb_result_t result)
993 {
994   char *field[9];
995   int fields = 0;
996   gpg_err_code_t ec;
997
998   while (line && fields < DIM (field))
999     {
1000       field[fields++] = line;
1001       line = strchr (line, ':');
1002       if (line)
1003         *line++ = 0;
1004     }
1005   /* We require that all fields exists - gpgme emits all these fields
1006    * even on error.  They might be empty, though. */
1007   if (fields < 9)
1008     return gpg_error (GPG_ERR_INV_ENGINE);
1009
1010   free (result->name);
1011   result->name = strdup (field[0]);
1012   if (!result->name)
1013     return gpg_error_from_syserror ();
1014
1015   free (result->iversion);
1016   result->iversion = strdup (field[1]);
1017   if (!result->iversion)
1018     return gpg_error_from_syserror ();
1019
1020   result->urgent = (strtol (field[3], NULL, 10) > 0);
1021
1022   ec = gpg_err_code (strtoul (field[4], NULL, 10));
1023
1024   result->created  = _gpgme_parse_timestamp (field[5], NULL);
1025   result->retrieved= _gpgme_parse_timestamp (field[6], NULL);
1026
1027   free (result->version);
1028   result->version  = strdup (field[7]);
1029   if (!result->version)
1030     return gpg_error_from_syserror ();
1031
1032   result->reldate  = _gpgme_parse_timestamp (field[8], NULL);
1033
1034   /* Set other flags.  */
1035   result->warning = !!ec;
1036   result->update = 0;
1037   result->noinfo = 0;
1038   result->unknown = 0;
1039   result->tooold = 0;
1040   result->error = 0;
1041
1042   switch (*field[2])
1043     {
1044     case '-': result->warning = 1; break;
1045     case '?': result->unknown = result->warning = 1; break;
1046     case 'u': result->update = 1; break;
1047     case 'c': break;
1048     case 'n': break;
1049     default:
1050       result->warning = 1;
1051       if (!ec)
1052         ec = GPG_ERR_INV_ENGINE;
1053       break;
1054     }
1055
1056   if (ec == GPG_ERR_TOO_OLD)
1057     result->tooold = 1;
1058   else if (ec == GPG_ERR_ENOENT)
1059     result->noinfo = 1;
1060   else if (ec)
1061     result->error = 1;
1062
1063
1064   return 0;
1065 }
1066
1067
1068 static gpgme_error_t
1069 gpgconf_query_swdb (void *engine,
1070                     const char *name, const char *iversion,
1071                     gpgme_query_swdb_result_t result)
1072 {
1073   struct engine_gpgconf *gpgconf = engine;
1074   gpgme_error_t err = 0;
1075   char *linebuf;
1076   size_t linebufsize;
1077   int linelen;
1078   char *argv[7];
1079   int argc = 0;
1080   int rp[2];
1081   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
1082                                    {-1, -1} };
1083   int status;
1084   int nread;
1085   char *mark = NULL;
1086
1087   if (!have_gpgconf_version (gpgconf, "2.1.16"))
1088     return gpg_error (GPG_ERR_ENGINE_TOO_OLD);
1089
1090   /* _gpgme_engine_new guarantees that this is not NULL.  */
1091   argv[argc++] = gpgconf->file_name;
1092
1093   if (gpgconf->home_dir)
1094     {
1095       argv[argc++] = (char*)"--homedir";
1096       argv[argc++] = gpgconf->home_dir;
1097     }
1098
1099   argv[argc++] = (char*)"--query-swdb";
1100   argv[argc++] = (char*)name;
1101   argv[argc++] = (char*)iversion;
1102   argv[argc] = NULL;
1103   assert (argc < DIM (argv));
1104
1105   if (_gpgme_io_pipe (rp, 1) < 0)
1106     return gpg_error_from_syserror ();
1107
1108   cfd[0].fd = rp[1];
1109
1110   status = _gpgme_io_spawn (gpgconf->file_name, argv,
1111                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
1112   if (status < 0)
1113     {
1114       _gpgme_io_close (rp[0]);
1115       _gpgme_io_close (rp[1]);
1116       return gpg_error_from_syserror ();
1117     }
1118
1119   linebufsize = 2048; /* Same as used by gpgconf.  */
1120   linebuf = malloc (linebufsize);
1121   if (!linebuf)
1122     {
1123       err = gpg_error_from_syserror ();
1124       goto leave;
1125     }
1126   linelen = 0;
1127
1128   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
1129                                   linebufsize - linelen - 1)))
1130     {
1131       char *line;
1132       const char *lastmark = NULL;
1133       size_t nused;
1134
1135       if (nread < 0)
1136         {
1137           err = gpg_error_from_syserror ();
1138           goto leave;
1139         }
1140
1141       linelen += nread;
1142       linebuf[linelen] = '\0';
1143
1144       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
1145         {
1146           lastmark = mark;
1147           if (mark > line && mark[-1] == '\r')
1148             mark[-1] = '\0';
1149           else
1150             mark[0] = '\0';
1151
1152           /* Got a full line.  Due to the CR removal code (which
1153              occurs only on Windows) we might be one-off and thus
1154              would see empty lines.  */
1155           if (*line)
1156             {
1157               err = parse_swdb_line (line, result);
1158               goto leave; /* Ready.  */
1159             }
1160           else /* empty line.  */
1161             err = 0;
1162         }
1163
1164       nused = lastmark? (lastmark + 1 - linebuf) : 0;
1165       memmove (linebuf, linebuf + nused, linelen - nused);
1166       linelen -= nused;
1167
1168       if (!(linelen < linebufsize - 1))
1169         {
1170           char *newlinebuf;
1171
1172           if (linelen <  8 * 1024 - 1)
1173             linebufsize = 8 * 1024;
1174           else if (linelen < 64 * 1024 - 1)
1175             linebufsize = 64 * 1024;
1176           else
1177             {
1178               /* We reached our limit - give up.  */
1179               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
1180               goto leave;
1181             }
1182
1183           newlinebuf = realloc (linebuf, linebufsize);
1184           if (!newlinebuf)
1185             {
1186               err = gpg_error_from_syserror ();
1187               goto leave;
1188             }
1189           linebuf = newlinebuf;
1190         }
1191     }
1192
1193  leave:
1194   free (linebuf);
1195   _gpgme_io_close (rp[0]);
1196   return err;
1197 }
1198
1199
1200 static void
1201 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1202 {
1203   (void)engine;
1204   (void)io_cbs;
1205   /* Nothing to do.  */
1206 }
1207
1208 \f
1209 /* Currently, we do not use the engine interface for the various
1210    operations.  */
1211 void
1212 _gpgme_conf_release (gpgme_conf_comp_t conf)
1213 {
1214   gpgconf_config_release (conf);
1215 }
1216
1217 \f
1218 struct engine_ops _gpgme_engine_ops_gpgconf =
1219   {
1220     /* Static functions.  */
1221     _gpgme_get_default_gpgconf_name,
1222     NULL,
1223     gpgconf_get_version,
1224     gpgconf_get_req_version,
1225     gpgconf_new,
1226
1227     /* Member functions.  */
1228     gpgconf_release,
1229     NULL,               /* reset */
1230     NULL,               /* set_status_cb */
1231     NULL,               /* set_status_handler */
1232     NULL,               /* set_command_handler */
1233     NULL,               /* set_colon_line_handler */
1234     NULL,               /* set_locale */
1235     NULL,               /* set_protocol */
1236     NULL,               /* decrypt */
1237     NULL,               /* delete */
1238     NULL,               /* edit */
1239     NULL,               /* encrypt */
1240     NULL,               /* encrypt_sign */
1241     NULL,               /* export */
1242     NULL,               /* export_ext */
1243     NULL,               /* genkey */
1244     NULL,               /* import */
1245     NULL,               /* keylist */
1246     NULL,               /* keylist_ext */
1247     NULL,               /* keylist_data */
1248     NULL,               /* keysign */
1249     NULL,               /* tofu_policy */
1250     NULL,               /* sign */
1251     NULL,               /* trustlist */
1252     NULL,               /* verify */
1253     NULL,               /* getauditlog */
1254     NULL,               /* opassuan_transact */
1255     gpgconf_conf_load,
1256     gpgconf_conf_save,
1257     gpgconf_query_swdb,
1258     gpgconf_set_io_cbs,
1259     NULL,               /* io_event */
1260     NULL,               /* cancel */
1261     NULL,               /* cancel_op */
1262     NULL,               /* passwd */
1263     NULL,               /* set_pinentry_mode */
1264     NULL                /* opspawn */
1265   };