core: Add public function gpgme_get_ctx_flag.
[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 <http://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[6];
712   int argc = 0;
713   int rp[2];
714   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
715   int status;
716   int nwrite;
717
718   /* _gpgme_engine_new guarantees that this is not NULL.  */
719   argv[argc++] = gpgconf->file_name;
720
721   if (gpgconf->home_dir && have_gpgconf_version (gpgconf, "2.1.13"))
722     {
723       argv[argc++] = (char*)"--homedir";
724       argv[argc++] = gpgconf->home_dir;
725     }
726
727   argv[argc++] = (char*)arg1;
728   argv[argc++] = arg2;
729   argv[argc] = NULL;
730   assert (argc < DIM (argv));
731
732   if (_gpgme_io_pipe (rp, 0) < 0)
733     return gpg_error_from_syserror ();
734
735   cfd[0].fd = rp[0];
736
737   status = _gpgme_io_spawn (gpgconf->file_name, argv,
738                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
739   if (status < 0)
740     {
741       _gpgme_io_close (rp[0]);
742       _gpgme_io_close (rp[1]);
743       return gpg_error_from_syserror ();
744     }
745
746   for (;;)
747     {
748       if (buflen == 0)
749         {
750           do
751             {
752               buflen = gpgme_data_read (conf, buf, BUFLEN);
753             }
754           while (buflen < 0 && errno == EAGAIN);
755
756           if (buflen < 0)
757             {
758               err = gpg_error_from_syserror ();
759               _gpgme_io_close (rp[1]);
760               return err;
761             }
762           else if (buflen == 0)
763             {
764               /* All is written.  */
765               _gpgme_io_close (rp[1]);
766               return 0;
767             }
768         }
769
770       do
771         {
772           nwrite = _gpgme_io_write (rp[1], buf, buflen);
773         }
774       while (nwrite < 0 && errno == EAGAIN);
775
776       if (nwrite > 0)
777         {
778           buflen -= nwrite;
779           if (buflen > 0)
780             memmove (&buf[0], &buf[nwrite], buflen);
781         }
782       else if (nwrite < 0)
783         {
784           _gpgme_io_close (rp[1]);
785           return gpg_error_from_syserror ();
786         }
787     }
788
789   return 0;
790 }
791
792
793 static gpgme_error_t
794 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
795 {
796   gpgme_error_t err = 0;
797   int amt = 0;
798   char buf[16];
799
800   while (amt >= 0 && arg)
801     {
802       switch (option->alt_type)
803         {
804         case GPGME_CONF_NONE:
805         case GPGME_CONF_UINT32:
806         default:
807           snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
808           buf[sizeof (buf) - 1] = '\0';
809           amt = gpgme_data_write (conf, buf, strlen (buf));
810           break;
811
812         case GPGME_CONF_INT32:
813           snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
814           buf[sizeof (buf) - 1] = '\0';
815           amt = gpgme_data_write (conf, buf, strlen (buf));
816           break;
817
818
819         case GPGME_CONF_STRING:
820           /* The complex types below are only here to silent the
821              compiler warning. */
822         case GPGME_CONF_FILENAME:
823         case GPGME_CONF_LDAP_SERVER:
824         case GPGME_CONF_KEY_FPR:
825         case GPGME_CONF_PUB_KEY:
826         case GPGME_CONF_SEC_KEY:
827         case GPGME_CONF_ALIAS_LIST:
828           if (arg->value.string)
829             {
830               /* One quote character, and three times to allow for
831                  percent escaping.  */
832               char *ptr = arg->value.string;
833               amt = gpgme_data_write (conf, "\"", 1);
834               if (amt < 0)
835                 break;
836
837               while (!err && *ptr)
838                 {
839                   switch (*ptr)
840                     {
841                     case '%':
842                       amt = gpgme_data_write (conf, "%25", 3);
843                       break;
844
845                     case ':':
846                       amt = gpgme_data_write (conf, "%3a", 3);
847                       break;
848
849                     case ',':
850                       amt = gpgme_data_write (conf, "%2c", 3);
851                       break;
852
853                     default:
854                       amt = gpgme_data_write (conf, ptr, 1);
855                     }
856                   ptr++;
857                 }
858             }
859           break;
860         }
861
862       if (amt < 0)
863         break;
864
865       arg = arg->next;
866       /* Comma separator.  */
867       if (arg)
868         amt = gpgme_data_write (conf, ",", 1);
869     }
870
871   if (amt < 0)
872     return gpg_error_from_syserror ();
873
874   return 0;
875 }
876
877
878 static gpgme_error_t
879 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
880 {
881   gpgme_error_t err;
882   int amt = 0;
883   /* We use a data object to store the new configuration.  */
884   gpgme_data_t conf;
885   gpgme_conf_opt_t option;
886   int something_changed = 0;
887
888   err = gpgme_data_new (&conf);
889   if (err)
890     return err;
891
892   option = comp->options;
893   while (!err && amt >= 0 && option)
894     {
895       if (option->change_value)
896         {
897           unsigned int flags = 0;
898           char buf[16];
899
900           something_changed = 1;
901
902           amt = gpgme_data_write (conf, option->name, strlen (option->name));
903           if (amt >= 0)
904             amt = gpgme_data_write (conf, ":", 1);
905           if (amt < 0)
906             break;
907
908           if (!option->new_value)
909             flags |= GPGME_CONF_DEFAULT;
910           snprintf (buf, sizeof (buf), "%u", flags);
911           buf[sizeof (buf) - 1] = '\0';
912
913           amt = gpgme_data_write (conf, buf, strlen (buf));
914           if (amt >= 0)
915             amt = gpgme_data_write (conf, ":", 1);
916           if (amt < 0)
917             break;
918
919           if (option->new_value)
920             {
921               err = arg_to_data (conf, option, option->new_value);
922               if (err)
923                 break;
924             }
925           amt = gpgme_data_write (conf, "\n", 1);
926         }
927       option = option->next;
928     }
929   if (!err && amt < 0)
930     err = gpg_error_from_syserror ();
931   if (err || !something_changed)
932     goto bail;
933
934   err = gpgme_data_seek (conf, 0, SEEK_SET);
935   if (err)
936     goto bail;
937
938   err = gpgconf_write (engine, "--change-options", comp->name, conf);
939  bail:
940   gpgme_data_release (conf);
941   return err;
942 }
943
944
945 /* Parse a line received from gpgconf --query-swdb.  This function may
946  * modify LINE.  The result is stored at RESUL.  */
947 static gpg_error_t
948 parse_swdb_line (char *line, gpgme_query_swdb_result_t result)
949 {
950   char *field[9];
951   int fields = 0;
952   gpg_err_code_t ec;
953
954   while (line && fields < DIM (field))
955     {
956       field[fields++] = line;
957       line = strchr (line, ':');
958       if (line)
959         *line++ = 0;
960     }
961   /* We require that all fields exists - gpgme emits all these fields
962    * even on error.  They might be empty, though. */
963   if (fields < 9)
964     return gpg_error (GPG_ERR_INV_ENGINE);
965
966   free (result->name);
967   result->name = strdup (field[0]);
968   if (!result->name)
969     return gpg_error_from_syserror ();
970
971   free (result->iversion);
972   result->iversion = strdup (field[1]);
973   if (!result->iversion)
974     return gpg_error_from_syserror ();
975
976   result->urgent = (strtol (field[3], NULL, 10) > 0);
977
978   ec = gpg_err_code (strtoul (field[4], NULL, 10));
979
980   result->created  = _gpgme_parse_timestamp (field[5], NULL);
981   result->retrieved= _gpgme_parse_timestamp (field[6], NULL);
982
983   free (result->version);
984   result->version  = strdup (field[7]);
985   if (!result->version)
986     return gpg_error_from_syserror ();
987
988   result->reldate  = _gpgme_parse_timestamp (field[8], NULL);
989
990   /* Set other flags.  */
991   result->warning = !!ec;
992   result->update = 0;
993   result->noinfo = 0;
994   result->unknown = 0;
995   result->tooold = 0;
996   result->error = 0;
997
998   switch (*field[2])
999     {
1000     case '-': result->warning = 1; break;
1001     case '?': result->unknown = result->warning = 1; break;
1002     case 'u': result->update = 1; break;
1003     case 'c': break;
1004     case 'n': break;
1005     default:
1006       result->warning = 1;
1007       if (!ec)
1008         ec = GPG_ERR_INV_ENGINE;
1009       break;
1010     }
1011
1012   if (ec == GPG_ERR_TOO_OLD)
1013     result->tooold = 1;
1014   else if (ec == GPG_ERR_ENOENT)
1015     result->noinfo = 1;
1016   else if (ec)
1017     result->error = 1;
1018
1019
1020   return 0;
1021 }
1022
1023
1024 static gpgme_error_t
1025 gpgconf_query_swdb (void *engine,
1026                     const char *name, const char *iversion,
1027                     gpgme_query_swdb_result_t result)
1028 {
1029   struct engine_gpgconf *gpgconf = engine;
1030   gpgme_error_t err = 0;
1031   char *linebuf;
1032   size_t linebufsize;
1033   int linelen;
1034   char *argv[7];
1035   int argc = 0;
1036   int rp[2];
1037   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
1038                                    {-1, -1} };
1039   int status;
1040   int nread;
1041   char *mark = NULL;
1042
1043   if (!have_gpgconf_version (gpgconf, "2.1.16"))
1044     return gpg_error (GPG_ERR_ENGINE_TOO_OLD);
1045
1046   /* _gpgme_engine_new guarantees that this is not NULL.  */
1047   argv[argc++] = gpgconf->file_name;
1048
1049   if (gpgconf->home_dir)
1050     {
1051       argv[argc++] = (char*)"--homedir";
1052       argv[argc++] = gpgconf->home_dir;
1053     }
1054
1055   argv[argc++] = (char*)"--query-swdb";
1056   argv[argc++] = (char*)name;
1057   argv[argc++] = (char*)iversion;
1058   argv[argc] = NULL;
1059   assert (argc < DIM (argv));
1060
1061   if (_gpgme_io_pipe (rp, 1) < 0)
1062     return gpg_error_from_syserror ();
1063
1064   cfd[0].fd = rp[1];
1065
1066   status = _gpgme_io_spawn (gpgconf->file_name, argv,
1067                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
1068   if (status < 0)
1069     {
1070       _gpgme_io_close (rp[0]);
1071       _gpgme_io_close (rp[1]);
1072       return gpg_error_from_syserror ();
1073     }
1074
1075   linebufsize = 2048; /* Same as used by gpgconf.  */
1076   linebuf = malloc (linebufsize);
1077   if (!linebuf)
1078     {
1079       err = gpg_error_from_syserror ();
1080       goto leave;
1081     }
1082   linelen = 0;
1083
1084   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
1085                                   linebufsize - linelen - 1)))
1086     {
1087       char *line;
1088       const char *lastmark = NULL;
1089       size_t nused;
1090
1091       if (nread < 0)
1092         {
1093           err = gpg_error_from_syserror ();
1094           goto leave;
1095         }
1096
1097       linelen += nread;
1098       linebuf[linelen] = '\0';
1099
1100       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
1101         {
1102           lastmark = mark;
1103           if (mark > line && mark[-1] == '\r')
1104             mark[-1] = '\0';
1105           else
1106             mark[0] = '\0';
1107
1108           /* Got a full line.  Due to the CR removal code (which
1109              occurs only on Windows) we might be one-off and thus
1110              would see empty lines.  */
1111           if (*line)
1112             {
1113               err = parse_swdb_line (line, result);
1114               goto leave; /* Ready.  */
1115             }
1116           else /* empty line.  */
1117             err = 0;
1118         }
1119
1120       nused = lastmark? (lastmark + 1 - linebuf) : 0;
1121       memmove (linebuf, linebuf + nused, linelen - nused);
1122       linelen -= nused;
1123
1124       if (!(linelen < linebufsize - 1))
1125         {
1126           char *newlinebuf;
1127
1128           if (linelen <  8 * 1024 - 1)
1129             linebufsize = 8 * 1024;
1130           else if (linelen < 64 * 1024 - 1)
1131             linebufsize = 64 * 1024;
1132           else
1133             {
1134               /* We reached our limit - give up.  */
1135               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
1136               goto leave;
1137             }
1138
1139           newlinebuf = realloc (linebuf, linebufsize);
1140           if (!newlinebuf)
1141             {
1142               err = gpg_error_from_syserror ();
1143               goto leave;
1144             }
1145           linebuf = newlinebuf;
1146         }
1147     }
1148
1149  leave:
1150   free (linebuf);
1151   _gpgme_io_close (rp[0]);
1152   return err;
1153 }
1154
1155
1156 static void
1157 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1158 {
1159   (void)engine;
1160   (void)io_cbs;
1161   /* Nothing to do.  */
1162 }
1163
1164 \f
1165 /* Currently, we do not use the engine interface for the various
1166    operations.  */
1167 void
1168 _gpgme_conf_release (gpgme_conf_comp_t conf)
1169 {
1170   gpgconf_config_release (conf);
1171 }
1172
1173 \f
1174 struct engine_ops _gpgme_engine_ops_gpgconf =
1175   {
1176     /* Static functions.  */
1177     _gpgme_get_default_gpgconf_name,
1178     NULL,
1179     gpgconf_get_version,
1180     gpgconf_get_req_version,
1181     gpgconf_new,
1182
1183     /* Member functions.  */
1184     gpgconf_release,
1185     NULL,               /* reset */
1186     NULL,               /* set_status_cb */
1187     NULL,               /* set_status_handler */
1188     NULL,               /* set_command_handler */
1189     NULL,               /* set_colon_line_handler */
1190     NULL,               /* set_locale */
1191     NULL,               /* set_protocol */
1192     NULL,               /* decrypt */
1193     NULL,               /* decrypt_verify */
1194     NULL,               /* delete */
1195     NULL,               /* edit */
1196     NULL,               /* encrypt */
1197     NULL,               /* encrypt_sign */
1198     NULL,               /* export */
1199     NULL,               /* export_ext */
1200     NULL,               /* genkey */
1201     NULL,               /* import */
1202     NULL,               /* keylist */
1203     NULL,               /* keylist_ext */
1204     NULL,               /* keysign */
1205     NULL,               /* tofu_policy */
1206     NULL,               /* sign */
1207     NULL,               /* trustlist */
1208     NULL,               /* verify */
1209     NULL,               /* getauditlog */
1210     NULL,               /* opassuan_transact */
1211     gpgconf_conf_load,
1212     gpgconf_conf_save,
1213     gpgconf_query_swdb,
1214     gpgconf_set_io_cbs,
1215     NULL,               /* io_event */
1216     NULL,               /* cancel */
1217     NULL,               /* cancel_op */
1218     NULL,               /* passwd */
1219     NULL,               /* set_pinentry_mode */
1220     NULL                /* opspawn */
1221   };