core: Cleanup gpgme_key_unref frees
[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;
403
404   if (!line[0])
405     return 0;
406
407   while (line)
408     {
409       gpgme_conf_arg_t arg;
410
411       mark = strchr (line, ',');
412       if (mark)
413         *mark = '\0';
414
415       arg = calloc (1, sizeof (*arg));
416       if (!arg)
417         return gpg_error_from_syserror ();
418       *arg_p = arg;
419       arg_p = &arg->next;
420
421       if (*line == '\0')
422         arg->no_arg = 1;
423       else
424         {
425           switch (opt->alt_type)
426             {
427               /* arg->value.count is an alias for arg->value.uint32.  */
428             case GPGME_CONF_NONE:
429             case GPGME_CONF_UINT32:
430               arg->value.uint32 = strtoul (line, NULL, 0);
431               break;
432
433             case GPGME_CONF_INT32:
434               arg->value.uint32 = strtol (line, NULL, 0);
435               break;
436
437             case GPGME_CONF_STRING:
438               /* The complex types below are only here to silent the
439                  compiler warning. */
440             case GPGME_CONF_FILENAME:
441             case GPGME_CONF_LDAP_SERVER:
442             case GPGME_CONF_KEY_FPR:
443             case GPGME_CONF_PUB_KEY:
444             case GPGME_CONF_SEC_KEY:
445             case GPGME_CONF_ALIAS_LIST:
446               /* Skip quote character.  */
447               line++;
448
449               err = _gpgme_decode_percent_string (line, &arg->value.string,
450                                                   0, 0);
451               if (err)
452                 return err;
453               break;
454             }
455         }
456
457       /* Find beginning of next value.  */
458       if (mark++ && *mark)
459         line = mark;
460       else
461         line = NULL;
462     }
463
464   return 0;
465 }
466
467
468 static gpgme_error_t
469 gpgconf_config_load_cb2 (void *hook, char *line)
470 {
471   gpgme_error_t err;
472   gpgme_conf_comp_t comp = hook;
473   gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
474   gpgme_conf_opt_t opt;
475 #define NR_FIELDS 16
476   char *field[NR_FIELDS];
477   int fields = 0;
478
479   while (line && fields < NR_FIELDS)
480     {
481       field[fields++] = line;
482       line = strchr (line, ':');
483       if (line)
484         *(line++) = '\0';
485     }
486
487   /* We require at least the first 10 fields.  */
488   if (fields < 10)
489     return trace_gpg_error (GPG_ERR_INV_ENGINE);
490
491   opt = calloc (1, sizeof (*opt));
492   if (!opt)
493     return gpg_error_from_syserror ();
494
495   comp->_last_opt_p = &opt->next;
496   *opt_p = opt;
497
498   if (field[0][0])
499     {
500       opt->name = strdup (field[0]);
501       if (!opt->name)
502         return gpg_error_from_syserror ();
503     }
504
505   opt->flags = strtoul (field[1], NULL, 0);
506
507   opt->level = strtoul (field[2], NULL, 0);
508
509   if (field[3][0])
510     {
511       opt->description = strdup (field[3]);
512       if (!opt->description)
513         return gpg_error_from_syserror ();
514     }
515
516   opt->type = strtoul (field[4], NULL, 0);
517
518   opt->alt_type = strtoul (field[5], NULL, 0);
519
520   if (field[6][0])
521     {
522       opt->argname = strdup (field[6]);
523       if (!opt->argname)
524         return gpg_error_from_syserror ();
525     }
526
527   if (opt->flags & GPGME_CONF_DEFAULT)
528     {
529       err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
530       if (err)
531         return err;
532     }
533   else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
534     {
535       opt->default_description = strdup (field[7]);
536       if (!opt->default_description)
537         return gpg_error_from_syserror ();
538     }
539
540   if (opt->flags & GPGME_CONF_NO_ARG_DESC)
541     {
542       opt->no_arg_description = strdup (field[8]);
543       if (!opt->no_arg_description)
544         return gpg_error_from_syserror ();
545     }
546   else
547     {
548       err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
549       if (err)
550         return err;
551     }
552
553   err = gpgconf_parse_option (opt, &opt->value, field[9]);
554   if (err)
555     return err;
556
557   return 0;
558 }
559
560
561 static gpgme_error_t
562 gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
563 {
564   gpgme_error_t err;
565   gpgme_conf_comp_t comp = NULL;
566   gpgme_conf_comp_t cur_comp;
567
568   *comp_p = NULL;
569
570   err = gpgconf_read (engine, "--list-components", NULL,
571                       gpgconf_config_load_cb, &comp);
572   if (err)
573     {
574       gpgconf_release (comp);
575       return err;
576     }
577
578   cur_comp = comp;
579   while (!err && cur_comp)
580     {
581       err = gpgconf_read (engine, "--list-options", cur_comp->name,
582                           gpgconf_config_load_cb2, cur_comp);
583       cur_comp = cur_comp->next;
584     }
585
586   if (err)
587     {
588       gpgconf_release (comp);
589       return err;
590     }
591
592   *comp_p = comp;
593   return 0;
594 }
595
596
597 \f
598 gpgme_error_t
599 _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
600                      gpgme_conf_type_t type, const void *value)
601 {
602   gpgme_conf_arg_t arg;
603
604   arg = calloc (1, sizeof (*arg));
605   if (!arg)
606     return gpg_error_from_syserror ();
607
608   if (!value)
609     arg->no_arg = 1;
610   else
611     {
612       /* We need to switch on type here because the alt-type is not
613          yet known.  */
614       switch (type)
615         {
616         case GPGME_CONF_NONE:
617         case GPGME_CONF_UINT32:
618           arg->value.uint32 = *((unsigned int *) value);
619           break;
620
621         case GPGME_CONF_INT32:
622           arg->value.int32 = *((int *) value);
623           break;
624
625         case GPGME_CONF_STRING:
626         case GPGME_CONF_FILENAME:
627         case GPGME_CONF_LDAP_SERVER:
628         case GPGME_CONF_KEY_FPR:
629         case GPGME_CONF_PUB_KEY:
630         case GPGME_CONF_SEC_KEY:
631         case GPGME_CONF_ALIAS_LIST:
632           arg->value.string = strdup (value);
633           if (!arg->value.string)
634             {
635               free (arg);
636               return gpg_error_from_syserror ();
637             }
638           break;
639
640         default:
641           free (arg);
642           return gpg_error (GPG_ERR_INV_VALUE);
643         }
644     }
645
646   *arg_p = arg;
647   return 0;
648 }
649
650
651 void
652 _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
653 {
654   /* Lacking the alt_type we need to switch on type here.  */
655   switch (type)
656     {
657     case GPGME_CONF_NONE:
658     case GPGME_CONF_UINT32:
659     case GPGME_CONF_INT32:
660     case GPGME_CONF_STRING:
661     default:
662       break;
663
664     case GPGME_CONF_FILENAME:
665     case GPGME_CONF_LDAP_SERVER:
666     case GPGME_CONF_KEY_FPR:
667     case GPGME_CONF_PUB_KEY:
668     case GPGME_CONF_SEC_KEY:
669     case GPGME_CONF_ALIAS_LIST:
670       type = GPGME_CONF_STRING;
671       break;
672     }
673
674   release_arg (arg, type);
675 }
676
677
678 gpgme_error_t
679 _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
680 {
681   if (reset)
682     {
683       if (opt->new_value)
684         release_arg (opt->new_value, opt->alt_type);
685       opt->new_value = NULL;
686       opt->change_value = 0;
687     }
688   else
689     {
690       /* Support self-assignment, for example for adding an item to an
691          existing list.  */
692       if (opt->new_value && arg != opt->new_value)
693         release_arg (opt->new_value, opt->alt_type);
694       opt->new_value = arg;
695       opt->change_value = 1;
696     }
697   return 0;
698 }
699
700 \f
701 /* FIXME: Major problem: We don't get errors from gpgconf.  */
702
703 static gpgme_error_t
704 gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
705 {
706   struct engine_gpgconf *gpgconf = engine;
707   gpgme_error_t err = 0;
708 #define BUFLEN 1024
709   char buf[BUFLEN];
710   int buflen = 0;
711   char *argv[7];
712   int argc = 0;
713   int rp[2] = { -1, -1 };
714   int errp[2] = { -1, -1 };
715   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */},
716                                    {-1, 2 /* STDERR_FILENO */, -1},
717                                    {-1, -1} };
718   int status;
719   int nwrite;
720
721   /* _gpgme_engine_new guarantees that this is not NULL.  */
722   argv[argc++] = gpgconf->file_name;
723
724   if (gpgconf->home_dir && have_gpgconf_version (gpgconf, "2.1.13"))
725     {
726       argv[argc++] = (char*)"--homedir";
727       argv[argc++] = gpgconf->home_dir;
728     }
729
730   argv[argc++] = (char*)"--runtime";
731   argv[argc++] = (char*)arg1;
732   argv[argc++] = arg2;
733   argv[argc] = NULL;
734   assert (argc < DIM (argv));
735
736   if (_gpgme_io_pipe (rp, 0) < 0)
737     {
738       err = gpg_error_from_syserror ();
739       goto leave;
740     }
741
742   if (_gpgme_io_pipe (errp, 1) < 0)
743     {
744       err = gpg_error_from_syserror ();
745       goto leave;
746     }
747
748   cfd[0].fd = rp[0];
749   cfd[1].fd = errp[1];
750
751   status = _gpgme_io_spawn (gpgconf->file_name, argv,
752                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
753   if (status < 0)
754     {
755       err = gpg_error_from_syserror ();
756       goto leave;
757     }
758
759   rp[0] = -1;
760   errp[1] = -1;
761
762   for (;;)
763     {
764       if (buflen == 0)
765         {
766           do
767             {
768               buflen = gpgme_data_read (conf, buf, BUFLEN);
769             }
770           while (buflen < 0 && errno == EAGAIN);
771
772           if (buflen < 0)
773             {
774               err = gpg_error_from_syserror ();
775               goto leave;
776             }
777           else if (buflen == 0)
778             {
779               /* All is written.  */
780               _gpgme_io_close (rp[1]);
781               rp[1] = -1;
782
783               for (;;)
784                 {
785                   do
786                     {
787                       buflen = _gpgme_io_read (errp[0], buf, BUFLEN);
788                     }
789                   while (buflen < 0 && errno == EAGAIN);
790
791                   if (buflen == 0)
792                     {
793                       err = 0;
794                       goto leave;
795                     }
796                   /* XXX: Do something useful with BUF.  */
797                 }
798             }
799         }
800
801       do
802         {
803           nwrite = _gpgme_io_write (rp[1], buf, buflen);
804         }
805       while (nwrite < 0 && errno == EAGAIN);
806
807       if (nwrite > 0)
808         {
809           buflen -= nwrite;
810           if (buflen > 0)
811             memmove (&buf[0], &buf[nwrite], buflen);
812         }
813       else if (nwrite < 0)
814         {
815           err = gpg_error_from_syserror ();
816           goto leave;
817         }
818     }
819
820   assert (! "reached");
821
822  leave:
823   if (rp[0] != -1)
824     _gpgme_io_close (rp[0]);
825   if (rp[1] != -1)
826   _gpgme_io_close (rp[1]);
827   if (errp[0] != -1)
828     _gpgme_io_close (errp[0]);
829   if (errp[1] != -1)
830   _gpgme_io_close (errp[1]);
831
832   return err;
833 }
834
835
836 static gpgme_error_t
837 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
838 {
839   gpgme_error_t err = 0;
840   int amt = 0;
841   char buf[16];
842
843   while (amt >= 0 && arg)
844     {
845       switch (option->alt_type)
846         {
847         case GPGME_CONF_NONE:
848         case GPGME_CONF_UINT32:
849         default:
850           snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
851           buf[sizeof (buf) - 1] = '\0';
852           amt = gpgme_data_write (conf, buf, strlen (buf));
853           break;
854
855         case GPGME_CONF_INT32:
856           snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
857           buf[sizeof (buf) - 1] = '\0';
858           amt = gpgme_data_write (conf, buf, strlen (buf));
859           break;
860
861
862         case GPGME_CONF_STRING:
863           /* The complex types below are only here to silent the
864              compiler warning. */
865         case GPGME_CONF_FILENAME:
866         case GPGME_CONF_LDAP_SERVER:
867         case GPGME_CONF_KEY_FPR:
868         case GPGME_CONF_PUB_KEY:
869         case GPGME_CONF_SEC_KEY:
870         case GPGME_CONF_ALIAS_LIST:
871           if (arg->value.string)
872             {
873               /* One quote character, and three times to allow for
874                  percent escaping.  */
875               char *ptr = arg->value.string;
876               amt = gpgme_data_write (conf, "\"", 1);
877               if (amt < 0)
878                 break;
879
880               while (!err && *ptr)
881                 {
882                   switch (*ptr)
883                     {
884                     case '%':
885                       amt = gpgme_data_write (conf, "%25", 3);
886                       break;
887
888                     case ':':
889                       amt = gpgme_data_write (conf, "%3a", 3);
890                       break;
891
892                     case ',':
893                       amt = gpgme_data_write (conf, "%2c", 3);
894                       break;
895
896                     default:
897                       amt = gpgme_data_write (conf, ptr, 1);
898                     }
899                   ptr++;
900                 }
901             }
902           break;
903         }
904
905       if (amt < 0)
906         break;
907
908       arg = arg->next;
909       /* Comma separator.  */
910       if (arg)
911         amt = gpgme_data_write (conf, ",", 1);
912     }
913
914   if (amt < 0)
915     return gpg_error_from_syserror ();
916
917   return 0;
918 }
919
920
921 static gpgme_error_t
922 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
923 {
924   gpgme_error_t err;
925   int amt = 0;
926   /* We use a data object to store the new configuration.  */
927   gpgme_data_t conf;
928   gpgme_conf_opt_t option;
929   int something_changed = 0;
930
931   err = gpgme_data_new (&conf);
932   if (err)
933     return err;
934
935   option = comp->options;
936   while (!err && amt >= 0 && option)
937     {
938       if (option->change_value)
939         {
940           unsigned int flags = 0;
941           char buf[16];
942
943           something_changed = 1;
944
945           amt = gpgme_data_write (conf, option->name, strlen (option->name));
946           if (amt >= 0)
947             amt = gpgme_data_write (conf, ":", 1);
948           if (amt < 0)
949             break;
950
951           if (!option->new_value)
952             flags |= GPGME_CONF_DEFAULT;
953           snprintf (buf, sizeof (buf), "%u", flags);
954           buf[sizeof (buf) - 1] = '\0';
955
956           amt = gpgme_data_write (conf, buf, strlen (buf));
957           if (amt >= 0)
958             amt = gpgme_data_write (conf, ":", 1);
959           if (amt < 0)
960             break;
961
962           if (option->new_value)
963             {
964               err = arg_to_data (conf, option, option->new_value);
965               if (err)
966                 break;
967             }
968           amt = gpgme_data_write (conf, "\n", 1);
969         }
970       option = option->next;
971     }
972   if (!err && amt < 0)
973     err = gpg_error_from_syserror ();
974   if (err || !something_changed)
975     goto bail;
976
977   err = gpgme_data_seek (conf, 0, SEEK_SET);
978   if (err)
979     goto bail;
980
981   err = gpgconf_write (engine, "--change-options", comp->name, conf);
982  bail:
983   gpgme_data_release (conf);
984   return err;
985 }
986
987
988 /* Parse a line received from gpgconf --query-swdb.  This function may
989  * modify LINE.  The result is stored at RESUL.  */
990 static gpg_error_t
991 parse_swdb_line (char *line, gpgme_query_swdb_result_t result)
992 {
993   char *field[9];
994   int fields = 0;
995   gpg_err_code_t ec;
996
997   while (line && fields < DIM (field))
998     {
999       field[fields++] = line;
1000       line = strchr (line, ':');
1001       if (line)
1002         *line++ = 0;
1003     }
1004   /* We require that all fields exists - gpgme emits all these fields
1005    * even on error.  They might be empty, though. */
1006   if (fields < 9)
1007     return gpg_error (GPG_ERR_INV_ENGINE);
1008
1009   free (result->name);
1010   result->name = strdup (field[0]);
1011   if (!result->name)
1012     return gpg_error_from_syserror ();
1013
1014   free (result->iversion);
1015   result->iversion = strdup (field[1]);
1016   if (!result->iversion)
1017     return gpg_error_from_syserror ();
1018
1019   result->urgent = (strtol (field[3], NULL, 10) > 0);
1020
1021   ec = gpg_err_code (strtoul (field[4], NULL, 10));
1022
1023   result->created  = _gpgme_parse_timestamp (field[5], NULL);
1024   result->retrieved= _gpgme_parse_timestamp (field[6], NULL);
1025
1026   free (result->version);
1027   result->version  = strdup (field[7]);
1028   if (!result->version)
1029     return gpg_error_from_syserror ();
1030
1031   result->reldate  = _gpgme_parse_timestamp (field[8], NULL);
1032
1033   /* Set other flags.  */
1034   result->warning = !!ec;
1035   result->update = 0;
1036   result->noinfo = 0;
1037   result->unknown = 0;
1038   result->tooold = 0;
1039   result->error = 0;
1040
1041   switch (*field[2])
1042     {
1043     case '-': result->warning = 1; break;
1044     case '?': result->unknown = result->warning = 1; break;
1045     case 'u': result->update = 1; break;
1046     case 'c': break;
1047     case 'n': break;
1048     default:
1049       result->warning = 1;
1050       if (!ec)
1051         ec = GPG_ERR_INV_ENGINE;
1052       break;
1053     }
1054
1055   if (ec == GPG_ERR_TOO_OLD)
1056     result->tooold = 1;
1057   else if (ec == GPG_ERR_ENOENT)
1058     result->noinfo = 1;
1059   else if (ec)
1060     result->error = 1;
1061
1062
1063   return 0;
1064 }
1065
1066
1067 static gpgme_error_t
1068 gpgconf_query_swdb (void *engine,
1069                     const char *name, const char *iversion,
1070                     gpgme_query_swdb_result_t result)
1071 {
1072   struct engine_gpgconf *gpgconf = engine;
1073   gpgme_error_t err = 0;
1074   char *linebuf;
1075   size_t linebufsize;
1076   int linelen;
1077   char *argv[7];
1078   int argc = 0;
1079   int rp[2];
1080   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
1081                                    {-1, -1} };
1082   int status;
1083   int nread;
1084   char *mark = NULL;
1085
1086   if (!have_gpgconf_version (gpgconf, "2.1.16"))
1087     return gpg_error (GPG_ERR_ENGINE_TOO_OLD);
1088
1089   /* _gpgme_engine_new guarantees that this is not NULL.  */
1090   argv[argc++] = gpgconf->file_name;
1091
1092   if (gpgconf->home_dir)
1093     {
1094       argv[argc++] = (char*)"--homedir";
1095       argv[argc++] = gpgconf->home_dir;
1096     }
1097
1098   argv[argc++] = (char*)"--query-swdb";
1099   argv[argc++] = (char*)name;
1100   argv[argc++] = (char*)iversion;
1101   argv[argc] = NULL;
1102   assert (argc < DIM (argv));
1103
1104   if (_gpgme_io_pipe (rp, 1) < 0)
1105     return gpg_error_from_syserror ();
1106
1107   cfd[0].fd = rp[1];
1108
1109   status = _gpgme_io_spawn (gpgconf->file_name, argv,
1110                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
1111   if (status < 0)
1112     {
1113       _gpgme_io_close (rp[0]);
1114       _gpgme_io_close (rp[1]);
1115       return gpg_error_from_syserror ();
1116     }
1117
1118   linebufsize = 2048; /* Same as used by gpgconf.  */
1119   linebuf = malloc (linebufsize);
1120   if (!linebuf)
1121     {
1122       err = gpg_error_from_syserror ();
1123       goto leave;
1124     }
1125   linelen = 0;
1126
1127   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
1128                                   linebufsize - linelen - 1)))
1129     {
1130       char *line;
1131       const char *lastmark = NULL;
1132       size_t nused;
1133
1134       if (nread < 0)
1135         {
1136           err = gpg_error_from_syserror ();
1137           goto leave;
1138         }
1139
1140       linelen += nread;
1141       linebuf[linelen] = '\0';
1142
1143       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
1144         {
1145           lastmark = mark;
1146           if (mark > line && mark[-1] == '\r')
1147             mark[-1] = '\0';
1148           else
1149             mark[0] = '\0';
1150
1151           /* Got a full line.  Due to the CR removal code (which
1152              occurs only on Windows) we might be one-off and thus
1153              would see empty lines.  */
1154           if (*line)
1155             {
1156               err = parse_swdb_line (line, result);
1157               goto leave; /* Ready.  */
1158             }
1159           else /* empty line.  */
1160             err = 0;
1161         }
1162
1163       nused = lastmark? (lastmark + 1 - linebuf) : 0;
1164       memmove (linebuf, linebuf + nused, linelen - nused);
1165       linelen -= nused;
1166
1167       if (!(linelen < linebufsize - 1))
1168         {
1169           char *newlinebuf;
1170
1171           if (linelen <  8 * 1024 - 1)
1172             linebufsize = 8 * 1024;
1173           else if (linelen < 64 * 1024 - 1)
1174             linebufsize = 64 * 1024;
1175           else
1176             {
1177               /* We reached our limit - give up.  */
1178               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
1179               goto leave;
1180             }
1181
1182           newlinebuf = realloc (linebuf, linebufsize);
1183           if (!newlinebuf)
1184             {
1185               err = gpg_error_from_syserror ();
1186               goto leave;
1187             }
1188           linebuf = newlinebuf;
1189         }
1190     }
1191
1192  leave:
1193   free (linebuf);
1194   _gpgme_io_close (rp[0]);
1195   return err;
1196 }
1197
1198
1199 static void
1200 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1201 {
1202   (void)engine;
1203   (void)io_cbs;
1204   /* Nothing to do.  */
1205 }
1206
1207 \f
1208 /* Currently, we do not use the engine interface for the various
1209    operations.  */
1210 void
1211 _gpgme_conf_release (gpgme_conf_comp_t conf)
1212 {
1213   gpgconf_config_release (conf);
1214 }
1215
1216 \f
1217 struct engine_ops _gpgme_engine_ops_gpgconf =
1218   {
1219     /* Static functions.  */
1220     _gpgme_get_default_gpgconf_name,
1221     NULL,
1222     gpgconf_get_version,
1223     gpgconf_get_req_version,
1224     gpgconf_new,
1225
1226     /* Member functions.  */
1227     gpgconf_release,
1228     NULL,               /* reset */
1229     NULL,               /* set_status_cb */
1230     NULL,               /* set_status_handler */
1231     NULL,               /* set_command_handler */
1232     NULL,               /* set_colon_line_handler */
1233     NULL,               /* set_locale */
1234     NULL,               /* set_protocol */
1235     NULL,               /* decrypt */
1236     NULL,               /* decrypt_verify */
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,               /* keysign */
1248     NULL,               /* tofu_policy */
1249     NULL,               /* sign */
1250     NULL,               /* trustlist */
1251     NULL,               /* verify */
1252     NULL,               /* getauditlog */
1253     NULL,               /* opassuan_transact */
1254     gpgconf_conf_load,
1255     gpgconf_conf_save,
1256     gpgconf_query_swdb,
1257     gpgconf_set_io_cbs,
1258     NULL,               /* io_event */
1259     NULL,               /* cancel */
1260     NULL,               /* cancel_op */
1261     NULL,               /* passwd */
1262     NULL,               /* set_pinentry_mode */
1263     NULL                /* opspawn */
1264   };