core: Cast away the common const problem with spawn and argv.
[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 \f
51 struct engine_gpgconf
52 {
53   char *file_name;
54   char *home_dir;
55 };
56
57 typedef struct engine_gpgconf *engine_gpgconf_t;
58
59 \f
60 static char *
61 gpgconf_get_version (const char *file_name)
62 {
63   return _gpgme_get_program_version (file_name ? file_name
64                                      : _gpgme_get_default_gpgconf_name ());
65 }
66
67
68 static const char *
69 gpgconf_get_req_version (void)
70 {
71   return "2.0.4";
72 }
73
74 \f
75 static void
76 gpgconf_release (void *engine)
77 {
78   engine_gpgconf_t gpgconf = engine;
79
80   if (!gpgconf)
81     return;
82
83   if (gpgconf->file_name)
84     free (gpgconf->file_name);
85   if (gpgconf->home_dir)
86     free (gpgconf->home_dir);
87
88   free (gpgconf);
89 }
90
91
92 static gpgme_error_t
93 gpgconf_new (void **engine, const char *file_name, const char *home_dir,
94              const char *version)
95 {
96   gpgme_error_t err = 0;
97   engine_gpgconf_t gpgconf;
98
99   (void)version; /* Not yet used.  */
100
101   gpgconf = calloc (1, sizeof *gpgconf);
102   if (!gpgconf)
103     return gpg_error_from_syserror ();
104
105   gpgconf->file_name = strdup (file_name ? file_name
106                                : _gpgme_get_default_gpgconf_name ());
107   if (!gpgconf->file_name)
108     err = gpg_error_from_syserror ();
109
110   if (!err && home_dir)
111     {
112       gpgconf->home_dir = strdup (home_dir);
113       if (!gpgconf->home_dir)
114         err = gpg_error_from_syserror ();
115     }
116
117   if (err)
118     gpgconf_release (gpgconf);
119   else
120     *engine = gpgconf;
121
122   return err;
123 }
124
125 \f
126 static void
127 release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
128 {
129   while (arg)
130     {
131       gpgme_conf_arg_t next = arg->next;
132
133       if (alt_type == GPGME_CONF_STRING)
134         free (arg->value.string);
135       free (arg);
136       arg = next;
137     }
138 }
139
140
141 static void
142 release_opt (gpgme_conf_opt_t opt)
143 {
144   if (opt->name)
145     free (opt->name);
146   if (opt->description)
147     free (opt->description);
148   if (opt->argname)
149     free (opt->argname);
150
151   release_arg (opt->default_value, opt->alt_type);
152   if (opt->default_description)
153     free (opt->default_description);
154
155   release_arg (opt->no_arg_value, opt->alt_type);
156   release_arg (opt->value, opt->alt_type);
157   release_arg (opt->new_value, opt->alt_type);
158
159   free (opt);
160 }
161
162
163 static void
164 release_comp (gpgme_conf_comp_t comp)
165 {
166   gpgme_conf_opt_t opt;
167
168   if (comp->name)
169     free (comp->name);
170   if (comp->description)
171     free (comp->description);
172   if (comp->program_name)
173     free (comp->program_name);
174
175   opt = comp->options;
176   while (opt)
177     {
178       gpgme_conf_opt_t next = opt->next;
179       release_opt (opt);
180       opt = next;
181     }
182
183   free (comp);
184 }
185
186
187 static void
188 gpgconf_config_release (gpgme_conf_comp_t conf)
189 {
190   while (conf)
191     {
192       gpgme_conf_comp_t next = conf->next;
193       release_comp (conf);
194       conf = next;
195     }
196 }
197
198 /* Read from gpgconf and pass line after line to the hook function.
199    We put a limit of 64 k on the maximum size for a line.  This should
200    allow for quite a long "group" line, which is usually the longest
201    line (mine is currently ~3k).  */
202 static gpgme_error_t
203 gpgconf_read (void *engine, const char *arg1, char *arg2,
204               gpgme_error_t (*cb) (void *hook, char *line),
205               void *hook)
206 {
207   struct engine_gpgconf *gpgconf = engine;
208   gpgme_error_t err = 0;
209   char *linebuf;
210   size_t linebufsize;
211   int linelen;
212   char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
213   int rp[2];
214   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
215                                    {-1, -1} };
216   int status;
217   int nread;
218   char *mark = NULL;
219
220   argv[1] = (char*)arg1;
221   argv[2] = arg2;
222
223
224   /* FIXME: Deal with engine->home_dir.  */
225
226   /* _gpgme_engine_new guarantees that this is not NULL.  */
227   argv[0] = gpgconf->file_name;
228
229   if (_gpgme_io_pipe (rp, 1) < 0)
230     return gpg_error_from_syserror ();
231
232   cfd[0].fd = rp[1];
233
234   status = _gpgme_io_spawn (gpgconf->file_name, argv,
235                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
236   if (status < 0)
237     {
238       _gpgme_io_close (rp[0]);
239       _gpgme_io_close (rp[1]);
240       return gpg_error_from_syserror ();
241     }
242
243   linebufsize = 1024; /* Usually enough for conf lines.  */
244   linebuf = malloc (linebufsize);
245   if (!linebuf)
246     {
247       err = gpg_error_from_syserror ();
248       goto leave;
249     }
250   linelen = 0;
251
252   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
253                                   linebufsize - linelen - 1)))
254     {
255       char *line;
256       const char *lastmark = NULL;
257       size_t nused;
258
259       if (nread < 0)
260         {
261           err = gpg_error_from_syserror ();
262           goto leave;
263         }
264
265       linelen += nread;
266       linebuf[linelen] = '\0';
267
268       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
269         {
270           lastmark = mark;
271           if (mark > line && mark[-1] == '\r')
272             mark[-1] = '\0';
273           else
274             mark[0] = '\0';
275
276           /* Got a full line.  Due to the CR removal code (which
277              occurs only on Windows) we might be one-off and thus
278              would see empty lines.  Don't pass them to the
279              callback. */
280           err = *line? (*cb) (hook, line) : 0;
281           if (err)
282             goto leave;
283         }
284
285       nused = lastmark? (lastmark + 1 - linebuf) : 0;
286       memmove (linebuf, linebuf + nused, linelen - nused);
287       linelen -= nused;
288
289       if (!(linelen < linebufsize - 1))
290         {
291           char *newlinebuf;
292
293           if (linelen <  8 * 1024 - 1)
294             linebufsize = 8 * 1024;
295           else if (linelen < 64 * 1024 - 1)
296             linebufsize = 64 * 1024;
297           else
298             {
299               /* We reached our limit - give up.  */
300               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
301               goto leave;
302             }
303
304           newlinebuf = realloc (linebuf, linebufsize);
305           if (!newlinebuf)
306             {
307               err = gpg_error_from_syserror ();
308               goto leave;
309             }
310           linebuf = newlinebuf;
311         }
312     }
313
314  leave:
315   free (linebuf);
316   _gpgme_io_close (rp[0]);
317   return err;
318 }
319
320
321 static gpgme_error_t
322 gpgconf_config_load_cb (void *hook, char *line)
323 {
324   gpgme_conf_comp_t *comp_p = hook;
325   gpgme_conf_comp_t comp = *comp_p;
326 #define NR_FIELDS 16
327   char *field[NR_FIELDS];
328   int fields = 0;
329
330   while (line && fields < NR_FIELDS)
331     {
332       field[fields++] = line;
333       line = strchr (line, ':');
334       if (line)
335         *(line++) = '\0';
336     }
337
338   /* We require at least the first 3 fields.  */
339   if (fields < 2)
340     return trace_gpg_error (GPG_ERR_INV_ENGINE);
341
342   /* Find the pointer to the new component in the list.  */
343   while (comp && comp->next)
344     comp = comp->next;
345   if (comp)
346     comp_p = &comp->next;
347
348   comp = calloc (1, sizeof (*comp));
349   if (!comp)
350     return gpg_error_from_syserror ();
351   /* Prepare return value.  */
352   comp->_last_opt_p = &comp->options;
353   *comp_p = comp;
354
355   comp->name = strdup (field[0]);
356   if (!comp->name)
357     return gpg_error_from_syserror ();
358
359   comp->description = strdup (field[1]);
360   if (!comp->description)
361     return gpg_error_from_syserror ();
362
363   if (fields >= 3)
364     {
365       comp->program_name = strdup (field[2]);
366       if (!comp->program_name)
367         return gpg_error_from_syserror ();
368     }
369
370   return 0;
371 }
372
373
374 static gpgme_error_t
375 gpgconf_parse_option (gpgme_conf_opt_t opt,
376                       gpgme_conf_arg_t *arg_p, char *line)
377 {
378   gpgme_error_t err;
379   char *mark;
380
381   if (!line[0])
382     return 0;
383
384   while (line)
385     {
386       gpgme_conf_arg_t arg;
387
388       mark = strchr (line, ',');
389       if (mark)
390         *mark = '\0';
391
392       arg = calloc (1, sizeof (*arg));
393       if (!arg)
394         return gpg_error_from_syserror ();
395       *arg_p = arg;
396       arg_p = &arg->next;
397
398       if (*line == '\0')
399         arg->no_arg = 1;
400       else
401         {
402           switch (opt->alt_type)
403             {
404               /* arg->value.count is an alias for arg->value.uint32.  */
405             case GPGME_CONF_NONE:
406             case GPGME_CONF_UINT32:
407               arg->value.uint32 = strtoul (line, NULL, 0);
408               break;
409
410             case GPGME_CONF_INT32:
411               arg->value.uint32 = strtol (line, NULL, 0);
412               break;
413
414             case GPGME_CONF_STRING:
415               /* The complex types below are only here to silent the
416                  compiler warning. */
417             case GPGME_CONF_FILENAME:
418             case GPGME_CONF_LDAP_SERVER:
419             case GPGME_CONF_KEY_FPR:
420             case GPGME_CONF_PUB_KEY:
421             case GPGME_CONF_SEC_KEY:
422             case GPGME_CONF_ALIAS_LIST:
423               /* Skip quote character.  */
424               line++;
425
426               err = _gpgme_decode_percent_string (line, &arg->value.string,
427                                                   0, 0);
428               if (err)
429                 return err;
430               break;
431             }
432         }
433
434       /* Find beginning of next value.  */
435       if (mark++ && *mark)
436         line = mark;
437       else
438         line = NULL;
439     }
440
441   return 0;
442 }
443
444
445 static gpgme_error_t
446 gpgconf_config_load_cb2 (void *hook, char *line)
447 {
448   gpgme_error_t err;
449   gpgme_conf_comp_t comp = hook;
450   gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
451   gpgme_conf_opt_t opt;
452 #define NR_FIELDS 16
453   char *field[NR_FIELDS];
454   int fields = 0;
455
456   while (line && fields < NR_FIELDS)
457     {
458       field[fields++] = line;
459       line = strchr (line, ':');
460       if (line)
461         *(line++) = '\0';
462     }
463
464   /* We require at least the first 10 fields.  */
465   if (fields < 10)
466     return trace_gpg_error (GPG_ERR_INV_ENGINE);
467
468   opt = calloc (1, sizeof (*opt));
469   if (!opt)
470     return gpg_error_from_syserror ();
471
472   comp->_last_opt_p = &opt->next;
473   *opt_p = opt;
474
475   if (field[0][0])
476     {
477       opt->name = strdup (field[0]);
478       if (!opt->name)
479         return gpg_error_from_syserror ();
480     }
481
482   opt->flags = strtoul (field[1], NULL, 0);
483
484   opt->level = strtoul (field[2], NULL, 0);
485
486   if (field[3][0])
487     {
488       opt->description = strdup (field[3]);
489       if (!opt->description)
490         return gpg_error_from_syserror ();
491     }
492
493   opt->type = strtoul (field[4], NULL, 0);
494
495   opt->alt_type = strtoul (field[5], NULL, 0);
496
497   if (field[6][0])
498     {
499       opt->argname = strdup (field[6]);
500       if (!opt->argname)
501         return gpg_error_from_syserror ();
502     }
503
504   if (opt->flags & GPGME_CONF_DEFAULT)
505     {
506       err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
507       if (err)
508         return err;
509     }
510   else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
511     {
512       opt->default_description = strdup (field[7]);
513       if (!opt->default_description)
514         return gpg_error_from_syserror ();
515     }
516
517   if (opt->flags & GPGME_CONF_NO_ARG_DESC)
518     {
519       opt->no_arg_description = strdup (field[8]);
520       if (!opt->no_arg_description)
521         return gpg_error_from_syserror ();
522     }
523   else
524     {
525       err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
526       if (err)
527         return err;
528     }
529
530   err = gpgconf_parse_option (opt, &opt->value, field[9]);
531   if (err)
532     return err;
533
534   return 0;
535 }
536
537
538 static gpgme_error_t
539 gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
540 {
541   gpgme_error_t err;
542   gpgme_conf_comp_t comp = NULL;
543   gpgme_conf_comp_t cur_comp;
544
545   *comp_p = NULL;
546
547   err = gpgconf_read (engine, "--list-components", NULL,
548                       gpgconf_config_load_cb, &comp);
549   if (err)
550     {
551       gpgconf_release (comp);
552       return err;
553     }
554
555   cur_comp = comp;
556   while (!err && cur_comp)
557     {
558       err = gpgconf_read (engine, "--list-options", cur_comp->name,
559                           gpgconf_config_load_cb2, cur_comp);
560       cur_comp = cur_comp->next;
561     }
562
563   if (err)
564     {
565       gpgconf_release (comp);
566       return err;
567     }
568
569   *comp_p = comp;
570   return 0;
571 }
572
573
574 \f
575 gpgme_error_t
576 _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
577                      gpgme_conf_type_t type, const void *value)
578 {
579   gpgme_conf_arg_t arg;
580
581   arg = calloc (1, sizeof (*arg));
582   if (!arg)
583     return gpg_error_from_syserror ();
584
585   if (!value)
586     arg->no_arg = 1;
587   else
588     {
589       /* We need to switch on type here because the alt-type is not
590          yet known.  */
591       switch (type)
592         {
593         case GPGME_CONF_NONE:
594         case GPGME_CONF_UINT32:
595           arg->value.uint32 = *((unsigned int *) value);
596           break;
597
598         case GPGME_CONF_INT32:
599           arg->value.int32 = *((int *) value);
600           break;
601
602         case GPGME_CONF_STRING:
603         case GPGME_CONF_FILENAME:
604         case GPGME_CONF_LDAP_SERVER:
605         case GPGME_CONF_KEY_FPR:
606         case GPGME_CONF_PUB_KEY:
607         case GPGME_CONF_SEC_KEY:
608         case GPGME_CONF_ALIAS_LIST:
609           arg->value.string = strdup (value);
610           if (!arg->value.string)
611             {
612               free (arg);
613               return gpg_error_from_syserror ();
614             }
615           break;
616
617         default:
618           free (arg);
619           return gpg_error (GPG_ERR_INV_VALUE);
620         }
621     }
622
623   *arg_p = arg;
624   return 0;
625 }
626
627
628 void
629 _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
630 {
631   /* Lacking the alt_type we need to switch on type here.  */
632   switch (type)
633     {
634     case GPGME_CONF_NONE:
635     case GPGME_CONF_UINT32:
636     case GPGME_CONF_INT32:
637     case GPGME_CONF_STRING:
638     default:
639       break;
640
641     case GPGME_CONF_FILENAME:
642     case GPGME_CONF_LDAP_SERVER:
643     case GPGME_CONF_KEY_FPR:
644     case GPGME_CONF_PUB_KEY:
645     case GPGME_CONF_SEC_KEY:
646     case GPGME_CONF_ALIAS_LIST:
647       type = GPGME_CONF_STRING;
648       break;
649     }
650
651   release_arg (arg, type);
652 }
653
654
655 gpgme_error_t
656 _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
657 {
658   if (reset)
659     {
660       if (opt->new_value)
661         release_arg (opt->new_value, opt->alt_type);
662       opt->new_value = NULL;
663       opt->change_value = 0;
664     }
665   else
666     {
667       /* Support self-assignment, for example for adding an item to an
668          existing list.  */
669       if (opt->new_value && arg != opt->new_value)
670         release_arg (opt->new_value, opt->alt_type);
671       opt->new_value = arg;
672       opt->change_value = 1;
673     }
674   return 0;
675 }
676
677 \f
678 /* FIXME: Major problem: We don't get errors from gpgconf.  */
679
680 static gpgme_error_t
681 gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
682 {
683   struct engine_gpgconf *gpgconf = engine;
684   gpgme_error_t err = 0;
685 #define BUFLEN 1024
686   char buf[BUFLEN];
687   int buflen = 0;
688   char *argv[] = { NULL /* file_name */, (char*)arg1, arg2, 0 };
689   int rp[2];
690   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
691   int status;
692   int nwrite;
693
694   /* FIXME: Deal with engine->home_dir.  */
695
696   /* _gpgme_engine_new guarantees that this is not NULL.  */
697   argv[0] = gpgconf->file_name;
698
699   if (_gpgme_io_pipe (rp, 0) < 0)
700     return gpg_error_from_syserror ();
701
702   cfd[0].fd = rp[0];
703
704   status = _gpgme_io_spawn (gpgconf->file_name, argv,
705                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
706   if (status < 0)
707     {
708       _gpgme_io_close (rp[0]);
709       _gpgme_io_close (rp[1]);
710       return gpg_error_from_syserror ();
711     }
712
713   for (;;)
714     {
715       if (buflen == 0)
716         {
717           do
718             {
719               buflen = gpgme_data_read (conf, buf, BUFLEN);
720             }
721           while (buflen < 0 && errno == EAGAIN);
722
723           if (buflen < 0)
724             {
725               err = gpg_error_from_syserror ();
726               _gpgme_io_close (rp[1]);
727               return err;
728             }
729           else if (buflen == 0)
730             {
731               /* All is written.  */
732               _gpgme_io_close (rp[1]);
733               return 0;
734             }
735         }
736
737       do
738         {
739           nwrite = _gpgme_io_write (rp[1], buf, buflen);
740         }
741       while (nwrite < 0 && errno == EAGAIN);
742
743       if (nwrite > 0)
744         {
745           buflen -= nwrite;
746           if (buflen > 0)
747             memmove (&buf[0], &buf[nwrite], buflen);
748         }
749       else if (nwrite < 0)
750         {
751           _gpgme_io_close (rp[1]);
752           return gpg_error_from_syserror ();
753         }
754     }
755
756   return 0;
757 }
758
759
760 static gpgme_error_t
761 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
762 {
763   gpgme_error_t err = 0;
764   int amt = 0;
765   char buf[16];
766
767   while (amt >= 0 && arg)
768     {
769       switch (option->alt_type)
770         {
771         case GPGME_CONF_NONE:
772         case GPGME_CONF_UINT32:
773         default:
774           snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
775           buf[sizeof (buf) - 1] = '\0';
776           amt = gpgme_data_write (conf, buf, strlen (buf));
777           break;
778
779         case GPGME_CONF_INT32:
780           snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
781           buf[sizeof (buf) - 1] = '\0';
782           amt = gpgme_data_write (conf, buf, strlen (buf));
783           break;
784
785
786         case GPGME_CONF_STRING:
787           /* The complex types below are only here to silent the
788              compiler warning. */
789         case GPGME_CONF_FILENAME:
790         case GPGME_CONF_LDAP_SERVER:
791         case GPGME_CONF_KEY_FPR:
792         case GPGME_CONF_PUB_KEY:
793         case GPGME_CONF_SEC_KEY:
794         case GPGME_CONF_ALIAS_LIST:
795           if (arg->value.string)
796             {
797               /* One quote character, and three times to allow for
798                  percent escaping.  */
799               char *ptr = arg->value.string;
800               amt = gpgme_data_write (conf, "\"", 1);
801               if (amt < 0)
802                 break;
803
804               while (!err && *ptr)
805                 {
806                   switch (*ptr)
807                     {
808                     case '%':
809                       amt = gpgme_data_write (conf, "%25", 3);
810                       break;
811
812                     case ':':
813                       amt = gpgme_data_write (conf, "%3a", 3);
814                       break;
815
816                     case ',':
817                       amt = gpgme_data_write (conf, "%2c", 3);
818                       break;
819
820                     default:
821                       amt = gpgme_data_write (conf, ptr, 1);
822                     }
823                   ptr++;
824                 }
825             }
826           break;
827         }
828
829       if (amt < 0)
830         break;
831
832       arg = arg->next;
833       /* Comma separator.  */
834       if (arg)
835         amt = gpgme_data_write (conf, ",", 1);
836     }
837
838   if (amt < 0)
839     return gpg_error_from_syserror ();
840
841   return 0;
842 }
843
844
845 static gpgme_error_t
846 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
847 {
848   gpgme_error_t err;
849   int amt = 0;
850   /* We use a data object to store the new configuration.  */
851   gpgme_data_t conf;
852   gpgme_conf_opt_t option;
853   int something_changed = 0;
854
855   err = gpgme_data_new (&conf);
856   if (err)
857     return err;
858
859   option = comp->options;
860   while (!err && amt >= 0 && option)
861     {
862       if (option->change_value)
863         {
864           unsigned int flags = 0;
865           char buf[16];
866
867           something_changed = 1;
868
869           amt = gpgme_data_write (conf, option->name, strlen (option->name));
870           if (amt >= 0)
871             amt = gpgme_data_write (conf, ":", 1);
872           if (amt < 0)
873             break;
874
875           if (!option->new_value)
876             flags |= GPGME_CONF_DEFAULT;
877           snprintf (buf, sizeof (buf), "%u", flags);
878           buf[sizeof (buf) - 1] = '\0';
879
880           amt = gpgme_data_write (conf, buf, strlen (buf));
881           if (amt >= 0)
882             amt = gpgme_data_write (conf, ":", 1);
883           if (amt < 0)
884             break;
885
886           if (option->new_value)
887             {
888               err = arg_to_data (conf, option, option->new_value);
889               if (err)
890                 break;
891             }
892           amt = gpgme_data_write (conf, "\n", 1);
893         }
894       option = option->next;
895     }
896   if (!err && amt < 0)
897     err = gpg_error_from_syserror ();
898   if (err || !something_changed)
899     goto bail;
900
901   err = gpgme_data_seek (conf, 0, SEEK_SET);
902   if (err)
903     goto bail;
904
905   err = gpgconf_write (engine, "--change-options", comp->name, conf);
906  bail:
907   gpgme_data_release (conf);
908   return err;
909 }
910
911
912 static void
913 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
914 {
915   (void)engine;
916   (void)io_cbs;
917   /* Nothing to do.  */
918 }
919
920 \f
921 /* Currently, we do not use the engine interface for the various
922    operations.  */
923 void
924 _gpgme_conf_release (gpgme_conf_comp_t conf)
925 {
926   gpgconf_config_release (conf);
927 }
928
929 \f
930 struct engine_ops _gpgme_engine_ops_gpgconf =
931   {
932     /* Static functions.  */
933     _gpgme_get_default_gpgconf_name,
934     NULL,
935     gpgconf_get_version,
936     gpgconf_get_req_version,
937     gpgconf_new,
938
939     /* Member functions.  */
940     gpgconf_release,
941     NULL,               /* reset */
942     NULL,               /* set_status_cb */
943     NULL,               /* set_status_handler */
944     NULL,               /* set_command_handler */
945     NULL,               /* set_colon_line_handler */
946     NULL,               /* set_locale */
947     NULL,               /* set_protocol */
948     NULL,               /* decrypt */
949     NULL,               /* decrypt_verify */
950     NULL,               /* delete */
951     NULL,               /* edit */
952     NULL,               /* encrypt */
953     NULL,               /* encrypt_sign */
954     NULL,               /* export */
955     NULL,               /* export_ext */
956     NULL,               /* genkey */
957     NULL,               /* import */
958     NULL,               /* keylist */
959     NULL,               /* keylist_ext */
960     NULL,               /* sign */
961     NULL,               /* trustlist */
962     NULL,               /* verify */
963     NULL,               /* getauditlog */
964     NULL,               /* opassuan_transact */
965     gpgconf_conf_load,
966     gpgconf_conf_save,
967     gpgconf_set_io_cbs,
968     NULL,               /* io_event */
969     NULL,               /* cancel */
970     NULL,               /* cancel_op */
971     NULL,               /* passwd */
972     NULL,               /* set_pinentry_mode */
973     NULL                /* opspawn */
974   };