1 /* engine-gpgconf.c - gpg-conf engine.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008 g10 Code GmbH
5 This file is part of GPGME.
7 GPGME is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
12 GPGME is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this program; if not, see <http://www.gnu.org/licenses/>.
27 #ifdef HAVE_SYS_TYPES_H
28 # include <sys/types.h>
34 #include <fcntl.h> /* FIXME */
47 #include "engine-backend.h"
56 typedef struct engine_gpgconf *engine_gpgconf_t;
60 gpgconf_get_version (const char *file_name)
62 return _gpgme_get_program_version (file_name ? file_name
63 : _gpgme_get_gpgconf_path ());
68 gpgconf_get_req_version (void)
70 return NEED_GPGCONF_VERSION;
75 gpgconf_release (void *engine)
77 engine_gpgconf_t gpgconf = engine;
82 if (gpgconf->file_name)
83 free (gpgconf->file_name);
84 if (gpgconf->home_dir)
85 free (gpgconf->home_dir);
92 gpgconf_new (void **engine, const char *file_name, const char *home_dir)
94 gpgme_error_t err = 0;
95 engine_gpgconf_t gpgconf;
97 gpgconf = calloc (1, sizeof *gpgconf);
99 return gpg_error_from_errno (errno);
101 gpgconf->file_name = strdup (file_name ? file_name
102 : _gpgme_get_gpgconf_path ());
103 if (!gpgconf->file_name)
104 err = gpg_error_from_syserror ();
106 if (!err && home_dir)
108 gpgconf->home_dir = strdup (home_dir);
109 if (!gpgconf->home_dir)
110 err = gpg_error_from_syserror ();
114 gpgconf_release (gpgconf);
123 release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
127 gpgme_conf_arg_t next = arg->next;
129 if (alt_type == GPGME_CONF_STRING)
130 free (arg->value.string);
138 release_opt (gpgme_conf_opt_t opt)
142 if (opt->description)
143 free (opt->description);
147 release_arg (opt->default_value, opt->alt_type);
148 if (opt->default_description)
149 free (opt->default_description);
151 release_arg (opt->no_arg_value, opt->alt_type);
152 release_arg (opt->value, opt->alt_type);
153 release_arg (opt->new_value, opt->alt_type);
160 release_comp (gpgme_conf_comp_t comp)
162 gpgme_conf_opt_t opt;
166 if (comp->description)
167 free (comp->description);
168 if (comp->program_name)
169 free (comp->program_name);
174 gpgme_conf_opt_t next = opt->next;
184 gpgconf_config_release (gpgme_conf_comp_t conf)
188 gpgme_conf_comp_t next = conf->next;
196 gpgconf_read (void *engine, char *arg1, char *arg2,
197 gpgme_error_t (*cb) (void *hook, char *line),
200 struct engine_gpgconf *gpgconf = engine;
201 gpgme_error_t err = 0;
202 #define LINELENGTH 1024
203 char linebuf[LINELENGTH] = "";
205 char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
207 struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
217 /* FIXME: Deal with engine->home_dir. */
219 /* _gpgme_engine_new guarantees that this is not NULL. */
220 argv[0] = gpgconf->file_name;
222 if (_gpgme_io_pipe (rp, 1) < 0)
223 return gpg_error_from_syserror ();
227 status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
230 _gpgme_io_close (rp[0]);
231 _gpgme_io_close (rp[1]);
232 return gpg_error_from_syserror ();
237 nread = _gpgme_io_read (rp[0],
238 linebuf + linelen, LINELENGTH - linelen - 1);
242 const char *lastmark = NULL;
246 linebuf[linelen] = '\0';
248 for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
251 if (mark > line && mark[-1] == '\r')
256 /* Got a full line. Due to the CR removal code (which
257 occurs only on Windows) we might be one-off and thus
258 would see empty lines. Don't pass them to the
260 err = *line? (*cb) (hook, line) : 0;
265 nused = lastmark? (lastmark + 1 - linebuf) : 0;
266 memmove (linebuf, linebuf + nused, linelen - nused);
270 while (nread > 0 && linelen < LINELENGTH - 1);
272 if (!err && nread < 0)
273 err = gpg_error_from_syserror ();
274 if (!err && nread > 0)
275 err = gpg_error (GPG_ERR_LINE_TOO_LONG);
278 _gpgme_io_close (rp[0]);
285 gpgconf_config_load_cb (void *hook, char *line)
287 gpgme_conf_comp_t *comp_p = hook;
288 gpgme_conf_comp_t comp = *comp_p;
290 char *field[NR_FIELDS];
293 while (line && fields < NR_FIELDS)
295 field[fields++] = line;
296 line = strchr (line, ':');
301 /* We require at least the first 3 fields. */
303 return gpg_error (GPG_ERR_INV_ENGINE);
305 /* Find the pointer to the new component in the list. */
306 while (comp && comp->next)
309 comp_p = &comp->next;
311 comp = calloc (1, sizeof (*comp));
313 return gpg_error_from_syserror ();
314 /* Prepare return value. */
315 comp->_last_opt_p = &comp->options;
318 comp->name = strdup (field[0]);
320 return gpg_error_from_syserror ();
322 comp->description = strdup (field[1]);
323 if (!comp->description)
324 return gpg_error_from_syserror ();
328 comp->program_name = strdup (field[2]);
329 if (!comp->program_name)
330 return gpg_error_from_syserror ();
338 gpgconf_parse_option (gpgme_conf_opt_t opt,
339 gpgme_conf_arg_t *arg_p, char *line)
349 gpgme_conf_arg_t arg;
351 mark = strchr (line, ',');
355 arg = calloc (1, sizeof (*arg));
357 return gpg_error_from_syserror ();
365 switch (opt->alt_type)
367 /* arg->value.count is an alias for arg->value.uint32. */
368 case GPGME_CONF_NONE:
369 case GPGME_CONF_UINT32:
370 arg->value.uint32 = strtoul (line, NULL, 0);
373 case GPGME_CONF_INT32:
374 arg->value.uint32 = strtol (line, NULL, 0);
377 case GPGME_CONF_STRING:
378 /* The complex types below are only here to silent the
380 case GPGME_CONF_FILENAME:
381 case GPGME_CONF_LDAP_SERVER:
382 case GPGME_CONF_KEY_FPR:
383 case GPGME_CONF_PUB_KEY:
384 case GPGME_CONF_SEC_KEY:
385 case GPGME_CONF_ALIAS_LIST:
386 /* Skip quote character. */
389 err = _gpgme_decode_percent_string (line, &arg->value.string,
397 /* Find beginning of next value. */
409 gpgconf_config_load_cb2 (void *hook, char *line)
412 gpgme_conf_comp_t comp = hook;
413 gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
414 gpgme_conf_opt_t opt;
416 char *field[NR_FIELDS];
419 while (line && fields < NR_FIELDS)
421 field[fields++] = line;
422 line = strchr (line, ':');
427 /* We require at least the first 10 fields. */
429 return gpg_error (GPG_ERR_INV_ENGINE);
431 opt = calloc (1, sizeof (*opt));
433 return gpg_error_from_syserror ();
435 comp->_last_opt_p = &opt->next;
440 opt->name = strdup (field[0]);
442 return gpg_error_from_syserror ();
445 opt->flags = strtoul (field[1], NULL, 0);
447 opt->level = strtoul (field[2], NULL, 0);
451 opt->description = strdup (field[3]);
452 if (!opt->description)
453 return gpg_error_from_syserror ();
456 opt->type = strtoul (field[4], NULL, 0);
458 opt->alt_type = strtoul (field[5], NULL, 0);
462 opt->argname = strdup (field[6]);
464 return gpg_error_from_syserror ();
467 if (opt->flags & GPGME_CONF_DEFAULT)
469 err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
473 else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
475 opt->default_description = strdup (field[7]);
476 if (!opt->default_description)
477 return gpg_error_from_syserror ();
480 if (opt->flags & GPGME_CONF_NO_ARG_DESC)
482 opt->no_arg_description = strdup (field[8]);
483 if (!opt->no_arg_description)
484 return gpg_error_from_syserror ();
488 err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
493 err = gpgconf_parse_option (opt, &opt->value, field[9]);
502 gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
505 gpgme_conf_comp_t comp = NULL;
506 gpgme_conf_comp_t cur_comp;
510 err = gpgconf_read (engine, "--list-components", NULL,
511 gpgconf_config_load_cb, &comp);
514 gpgconf_release (comp);
519 while (!err && cur_comp)
521 err = gpgconf_read (engine, "--list-options", cur_comp->name,
522 gpgconf_config_load_cb2, cur_comp);
523 cur_comp = cur_comp->next;
528 gpgconf_release (comp);
539 _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
540 gpgme_conf_type_t type, const void *value)
542 gpgme_conf_arg_t arg;
544 arg = calloc (1, sizeof (*arg));
546 return gpg_error_from_syserror ();
552 /* We need to switch on type here because the alt-type is not
556 case GPGME_CONF_NONE:
557 case GPGME_CONF_UINT32:
558 arg->value.uint32 = *((unsigned int *) value);
561 case GPGME_CONF_INT32:
562 arg->value.int32 = *((int *) value);
565 case GPGME_CONF_STRING:
566 case GPGME_CONF_FILENAME:
567 case GPGME_CONF_LDAP_SERVER:
568 case GPGME_CONF_KEY_FPR:
569 case GPGME_CONF_PUB_KEY:
570 case GPGME_CONF_SEC_KEY:
571 case GPGME_CONF_ALIAS_LIST:
572 arg->value.string = strdup (value);
573 if (!arg->value.string)
576 return gpg_error_from_syserror ();
582 return gpg_error (GPG_ERR_INV_VALUE);
592 _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
594 /* Lacking the alt_type we need to switch on type here. */
597 case GPGME_CONF_NONE:
598 case GPGME_CONF_UINT32:
599 case GPGME_CONF_INT32:
600 case GPGME_CONF_STRING:
604 case GPGME_CONF_FILENAME:
605 case GPGME_CONF_LDAP_SERVER:
606 case GPGME_CONF_KEY_FPR:
607 case GPGME_CONF_PUB_KEY:
608 case GPGME_CONF_SEC_KEY:
609 case GPGME_CONF_ALIAS_LIST:
610 type = GPGME_CONF_STRING;
614 release_arg (arg, type);
619 _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
624 release_arg (opt->new_value, opt->alt_type);
625 opt->new_value = NULL;
626 opt->change_value = 0;
630 /* Support self-assignment, for example for adding an item to an
632 if (opt->new_value && arg != opt->new_value)
633 release_arg (opt->new_value, opt->alt_type);
634 opt->new_value = arg;
635 opt->change_value = 1;
641 /* FIXME: Major problem: We don't get errors from gpgconf. */
644 gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
646 struct engine_gpgconf *gpgconf = engine;
647 gpgme_error_t err = 0;
651 char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
653 struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
657 /* FIXME: Deal with engine->home_dir. */
659 /* _gpgme_engine_new guarantees that this is not NULL. */
660 argv[0] = gpgconf->file_name;
662 if (_gpgme_io_pipe (rp, 0) < 0)
663 return gpg_error_from_syserror ();
667 status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
670 _gpgme_io_close (rp[0]);
671 _gpgme_io_close (rp[1]);
672 return gpg_error_from_syserror ();
681 buflen = gpgme_data_read (conf, buf, BUFLEN);
683 while (buflen < 0 && errno == EAGAIN);
687 err = gpg_error_from_syserror ();
688 _gpgme_io_close (rp[1]);
691 else if (buflen == 0)
693 /* All is written. */
694 _gpgme_io_close (rp[1]);
701 nwrite = _gpgme_io_write (rp[1], buf, buflen);
703 while (nwrite < 0 && errno == EAGAIN);
709 memmove (&buf[0], &buf[nwrite], buflen);
713 _gpgme_io_close (rp[1]);
714 return gpg_error_from_syserror ();
723 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
725 gpgme_error_t err = 0;
729 while (amt >= 0 && arg)
731 switch (option->alt_type)
733 case GPGME_CONF_NONE:
734 case GPGME_CONF_UINT32:
736 snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
737 buf[sizeof (buf) - 1] = '\0';
738 amt = gpgme_data_write (conf, buf, strlen (buf));
741 case GPGME_CONF_INT32:
742 snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
743 buf[sizeof (buf) - 1] = '\0';
744 amt = gpgme_data_write (conf, buf, strlen (buf));
748 case GPGME_CONF_STRING:
749 /* The complex types below are only here to silent the
751 case GPGME_CONF_FILENAME:
752 case GPGME_CONF_LDAP_SERVER:
753 case GPGME_CONF_KEY_FPR:
754 case GPGME_CONF_PUB_KEY:
755 case GPGME_CONF_SEC_KEY:
756 case GPGME_CONF_ALIAS_LIST:
757 if (arg->value.string)
759 /* One quote character, and three times to allow for
761 char *ptr = arg->value.string;
762 amt = gpgme_data_write (conf, "\"", 1);
771 amt = gpgme_data_write (conf, "%25", 3);
775 amt = gpgme_data_write (conf, "%3a", 3);
779 amt = gpgme_data_write (conf, "%2c", 3);
783 amt = gpgme_data_write (conf, ptr, 1);
795 /* Comma separator. */
797 amt = gpgme_data_write (conf, ",", 1);
801 return gpg_error_from_syserror ();
808 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
812 /* We use a data object to store the new configuration. */
814 gpgme_conf_opt_t option;
815 int something_changed = 0;
817 err = gpgme_data_new (&conf);
821 option = comp->options;
822 while (!err && amt >= 0 && option)
824 if (option->change_value)
826 unsigned int flags = 0;
829 something_changed = 1;
831 amt = gpgme_data_write (conf, option->name, strlen (option->name));
833 amt = gpgme_data_write (conf, ":", 1);
837 if (!option->new_value)
838 flags |= GPGME_CONF_DEFAULT;
839 snprintf (buf, sizeof (buf), "%u", flags);
840 buf[sizeof (buf) - 1] = '\0';
842 amt = gpgme_data_write (conf, buf, strlen (buf));
844 amt = gpgme_data_write (conf, ":", 1);
848 if (option->new_value)
850 err = arg_to_data (conf, option, option->new_value);
854 amt = gpgme_data_write (conf, "\n", 1);
856 option = option->next;
859 err = gpg_error_from_syserror ();
860 if (err || !something_changed)
863 err = gpgme_data_seek (conf, 0, SEEK_SET);
867 err = gpgconf_write (engine, "--change-options", comp->name, conf);
869 gpgme_data_release (conf);
875 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
881 /* Currently, we do not use the engine interface for the various
884 _gpgme_conf_release (gpgme_conf_comp_t conf)
886 gpgconf_config_release (conf);
890 struct engine_ops _gpgme_engine_ops_gpgconf =
892 /* Static functions. */
893 _gpgme_get_gpgconf_path,
896 gpgconf_get_req_version,
899 /* Member functions. */
902 NULL, /* set_status_handler */
903 NULL, /* set_command_handler */
904 NULL, /* set_colon_line_handler */
905 NULL, /* set_locale */
906 NULL, /* set_protocol */
908 NULL, /* decrypt_verify */
912 NULL, /* encrypt_sign */
914 NULL, /* export_ext */
918 NULL, /* keylist_ext */
920 NULL, /* trustlist */
922 NULL, /* getauditlog */
923 NULL, /* opassuan_transact */