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, 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)
634 release_arg (opt->new_value, opt->alt_type);
635 opt->new_value = arg;
637 opt->change_value = 1;
643 /* FIXME: Major problem: We don't get errors from gpgconf. */
646 gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
648 struct engine_gpgconf *gpgconf = engine;
649 gpgme_error_t err = 0;
653 char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
655 struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
659 /* FIXME: Deal with engine->home_dir. */
661 /* _gpgme_engine_new guarantees that this is not NULL. */
662 argv[0] = gpgconf->file_name;
663 argv[0] = "/nowhere/path-needs-to-be-fixed/gpgconf";
665 if (_gpgme_io_pipe (rp, 0) < 0)
666 return gpg_error_from_syserror ();
670 status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
673 _gpgme_io_close (rp[0]);
674 _gpgme_io_close (rp[1]);
675 return gpg_error_from_syserror ();
684 buflen = gpgme_data_read (conf, buf, BUFLEN);
686 while (buflen < 0 && errno == EAGAIN);
690 err = gpg_error_from_syserror ();
691 _gpgme_io_close (rp[1]);
694 else if (buflen == 0)
696 /* All is written. */
697 _gpgme_io_close (rp[1]);
704 nwrite = _gpgme_io_write (rp[1], buf, buflen);
706 while (nwrite < 0 && errno == EAGAIN);
712 memmove (&buf[0], &buf[nwrite], buflen);
716 _gpgme_io_close (rp[1]);
717 return gpg_error_from_syserror ();
726 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
728 gpgme_error_t err = 0;
732 while (amt >= 0 && arg)
734 switch (option->alt_type)
736 case GPGME_CONF_NONE:
737 case GPGME_CONF_UINT32:
739 snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
740 buf[sizeof (buf) - 1] = '\0';
741 amt = gpgme_data_write (conf, buf, strlen (buf));
744 case GPGME_CONF_INT32:
745 snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
746 buf[sizeof (buf) - 1] = '\0';
747 amt = gpgme_data_write (conf, buf, strlen (buf));
751 case GPGME_CONF_STRING:
752 /* The complex types below are only here to silent the
754 case GPGME_CONF_FILENAME:
755 case GPGME_CONF_LDAP_SERVER:
756 case GPGME_CONF_KEY_FPR:
757 case GPGME_CONF_PUB_KEY:
758 case GPGME_CONF_SEC_KEY:
759 case GPGME_CONF_ALIAS_LIST:
760 /* One quote character, and three times to allow
761 for percent escaping. */
763 char *ptr = arg->value.string;
764 amt = gpgme_data_write (conf, "\"", 1);
773 amt = gpgme_data_write (conf, "%25", 3);
777 amt = gpgme_data_write (conf, "%3a", 3);
781 amt = gpgme_data_write (conf, "%2c", 3);
785 amt = gpgme_data_write (conf, ptr, 1);
797 /* Comma separator. */
799 amt = gpgme_data_write (conf, ",", 1);
803 return gpg_error_from_syserror ();
810 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
814 /* We use a data object to store the new configuration. */
816 gpgme_conf_opt_t option;
817 int something_changed = 0;
819 err = gpgme_data_new (&conf);
823 option = comp->options;
824 while (!err && amt >= 0 && option)
826 if (option->change_value)
828 unsigned int flags = 0;
831 something_changed = 1;
833 amt = gpgme_data_write (conf, option->name, strlen (option->name));
835 amt = gpgme_data_write (conf, ":", 1);
839 if (!option->new_value)
840 flags |= GPGME_CONF_DEFAULT;
841 snprintf (buf, sizeof (buf), "%u", flags);
842 buf[sizeof (buf) - 1] = '\0';
844 amt = gpgme_data_write (conf, buf, strlen (buf));
846 amt = gpgme_data_write (conf, ":", 1);
850 if (option->new_value)
852 err = arg_to_data (conf, option, option->new_value);
856 amt = gpgme_data_write (conf, "\n", 1);
858 option = option->next;
861 err = gpg_error_from_syserror ();
862 if (err || !something_changed)
865 err = gpgme_data_seek (conf, 0, SEEK_SET);
869 err = gpgconf_write (engine, "--change-options", comp->name, conf);
871 gpgme_data_release (conf);
877 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
883 /* Currently, we do not use the engine interface for the various
886 _gpgme_conf_release (gpgme_conf_comp_t conf)
888 gpgconf_config_release (conf);
892 struct engine_ops _gpgme_engine_ops_gpgconf =
894 /* Static functions. */
895 _gpgme_get_gpgconf_path,
898 gpgconf_get_req_version,
901 /* Member functions. */
904 NULL, /* set_status_handler */
905 NULL, /* set_command_handler */
906 NULL, /* set_colon_line_handler */
907 NULL, /* set_locale */
908 NULL, /* set_protocol */
910 NULL, /* decrypt_verify */
914 NULL, /* encrypt_sign */
916 NULL, /* export_ext */
920 NULL, /* keylist_ext */
922 NULL, /* trustlist */
924 NULL, /* getauditlog */
925 NULL, /* opassuan_transact */