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 #include <sys/types.h>
31 #include <fcntl.h> /* FIXME */
44 #include "engine-backend.h"
53 typedef struct engine_gpgconf *engine_gpgconf_t;
57 gpgconf_get_version (const char *file_name)
59 return _gpgme_get_program_version (file_name ? file_name
60 : _gpgme_get_gpgconf_path ());
65 gpgconf_get_req_version (void)
67 return NEED_GPGCONF_VERSION;
72 gpgconf_release (void *engine)
74 engine_gpgconf_t gpgconf = engine;
79 if (gpgconf->file_name)
80 free (gpgconf->file_name);
81 if (gpgconf->home_dir)
82 free (gpgconf->home_dir);
89 gpgconf_new (void **engine, const char *file_name, const char *home_dir)
91 gpgme_error_t err = 0;
92 engine_gpgconf_t gpgconf;
94 gpgconf = calloc (1, sizeof *gpgconf);
96 return gpg_error_from_errno (errno);
98 gpgconf->file_name = strdup (file_name ? file_name
99 : _gpgme_get_gpgconf_path ());
100 if (!gpgconf->file_name)
101 err = gpg_error_from_syserror ();
103 if (!err && home_dir)
105 gpgconf->home_dir = strdup (home_dir);
106 if (!gpgconf->home_dir)
107 err = gpg_error_from_syserror ();
111 gpgconf_release (gpgconf);
120 release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
124 gpgme_conf_arg_t next = arg->next;
126 if (alt_type == GPGME_CONF_STRING)
127 free (arg->value.string);
135 release_opt (gpgme_conf_opt_t opt)
139 if (opt->description)
140 free (opt->description);
144 release_arg (opt->default_value, opt->alt_type);
145 if (opt->default_description)
146 free (opt->default_description);
148 release_arg (opt->no_arg_value, opt->alt_type);
149 release_arg (opt->value, opt->alt_type);
150 release_arg (opt->new_value, opt->alt_type);
157 release_comp (gpgme_conf_comp_t comp)
159 gpgme_conf_opt_t opt;
163 if (comp->description)
164 free (comp->description);
165 if (comp->program_name)
166 free (comp->program_name);
171 gpgme_conf_opt_t next = opt->next;
181 gpgconf_config_release (gpgme_conf_comp_t conf)
185 gpgme_conf_comp_t next = conf->next;
193 gpgconf_read (void *engine, char *arg1, char *arg2,
194 gpgme_error_t (*cb) (void *hook, char *line),
197 struct engine_gpgconf *gpgconf = engine;
198 gpgme_error_t err = 0;
199 #define LINELENGTH 1024
200 char linebuf[LINELENGTH] = "";
202 char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
204 struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
214 /* FIXME: Deal with engine->home_dir. */
216 /* _gpgme_engine_new guarantees that this is not NULL. */
217 argv[0] = gpgconf->file_name;
219 if (_gpgme_io_pipe (rp, 1) < 0)
220 return gpg_error_from_syserror ();
224 status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, NULL);
227 _gpgme_io_close (rp[0]);
228 _gpgme_io_close (rp[1]);
229 return gpg_error_from_syserror ();
234 nread = _gpgme_io_read (rp[0],
235 linebuf + linelen, LINELENGTH - linelen - 1);
239 const char *lastmark = NULL;
243 linebuf[linelen] = '\0';
245 for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
248 if (mark > line && mark[-1] == '\r')
253 /* Got a full line. Due to the CR removal code (which
254 occurs only on Windows) we might be one-off and thus
255 would see empty lines. Don't pass them to the
257 err = *line? (*cb) (hook, line) : 0;
262 nused = lastmark? (lastmark + 1 - linebuf) : 0;
263 memmove (linebuf, linebuf + nused, linelen - nused);
267 while (nread > 0 && linelen < LINELENGTH - 1);
269 if (!err && nread < 0)
270 err = gpg_error_from_syserror ();
271 if (!err && nread > 0)
272 err = gpg_error (GPG_ERR_LINE_TOO_LONG);
275 _gpgme_io_close (rp[0]);
282 gpgconf_config_load_cb (void *hook, char *line)
284 gpgme_conf_comp_t *comp_p = hook;
285 gpgme_conf_comp_t comp = *comp_p;
287 char *field[NR_FIELDS];
290 while (line && fields < NR_FIELDS)
292 field[fields++] = line;
293 line = strchr (line, ':');
298 /* We require at least the first 3 fields. */
300 return gpg_error (GPG_ERR_INV_ENGINE);
302 /* Find the pointer to the new component in the list. */
303 while (comp && comp->next)
306 comp_p = &comp->next;
308 comp = calloc (1, sizeof (*comp));
310 return gpg_error_from_syserror ();
311 /* Prepare return value. */
312 comp->_last_opt_p = &comp->options;
315 comp->name = strdup (field[0]);
317 return gpg_error_from_syserror ();
319 comp->description = strdup (field[1]);
320 if (!comp->description)
321 return gpg_error_from_syserror ();
325 comp->program_name = strdup (field[2]);
326 if (!comp->program_name)
327 return gpg_error_from_syserror ();
335 gpgconf_parse_option (gpgme_conf_opt_t opt,
336 gpgme_conf_arg_t *arg_p, char *line)
346 gpgme_conf_arg_t arg;
348 mark = strchr (line, ',');
352 arg = calloc (1, sizeof (*arg));
354 return gpg_error_from_syserror ();
362 switch (opt->alt_type)
364 /* arg->value.count is an alias for arg->value.uint32. */
365 case GPGME_CONF_NONE:
366 case GPGME_CONF_UINT32:
367 arg->value.uint32 = strtoul (line, NULL, 0);
370 case GPGME_CONF_INT32:
371 arg->value.uint32 = strtol (line, NULL, 0);
374 case GPGME_CONF_STRING:
375 /* The complex types below are only here to silent the
377 case GPGME_CONF_FILENAME:
378 case GPGME_CONF_LDAP_SERVER:
379 case GPGME_CONF_KEY_FPR:
380 case GPGME_CONF_PUB_KEY:
381 case GPGME_CONF_SEC_KEY:
382 case GPGME_CONF_ALIAS_LIST:
383 /* Skip quote character. */
386 err = _gpgme_decode_percent_string (line, &arg->value.string,
394 /* Find beginning of next value. */
406 gpgconf_config_load_cb2 (void *hook, char *line)
409 gpgme_conf_comp_t comp = hook;
410 gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
411 gpgme_conf_opt_t opt;
413 char *field[NR_FIELDS];
416 while (line && fields < NR_FIELDS)
418 field[fields++] = line;
419 line = strchr (line, ':');
424 /* We require at least the first 10 fields. */
426 return gpg_error (GPG_ERR_INV_ENGINE);
428 opt = calloc (1, sizeof (*opt));
430 return gpg_error_from_syserror ();
432 comp->_last_opt_p = &opt->next;
437 opt->name = strdup (field[0]);
439 return gpg_error_from_syserror ();
442 opt->flags = strtoul (field[1], NULL, 0);
444 opt->level = strtoul (field[2], NULL, 0);
448 opt->description = strdup (field[3]);
449 if (!opt->description)
450 return gpg_error_from_syserror ();
453 opt->type = strtoul (field[4], NULL, 0);
455 opt->alt_type = strtoul (field[5], NULL, 0);
459 opt->argname = strdup (field[6]);
461 return gpg_error_from_syserror ();
464 if (opt->flags & GPGME_CONF_DEFAULT)
466 err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
470 else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
472 opt->default_description = strdup (field[7]);
473 if (!opt->default_description)
474 return gpg_error_from_syserror ();
477 if (opt->flags & GPGME_CONF_NO_ARG_DESC)
479 opt->no_arg_description = strdup (field[8]);
480 if (!opt->no_arg_description)
481 return gpg_error_from_syserror ();
485 err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
490 err = gpgconf_parse_option (opt, &opt->value, field[9]);
499 gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
502 gpgme_conf_comp_t comp = NULL;
503 gpgme_conf_comp_t cur_comp;
507 err = gpgconf_read (engine, "--list-components", NULL,
508 gpgconf_config_load_cb, &comp);
511 gpgconf_release (comp);
516 while (!err && cur_comp)
518 err = gpgconf_read (engine, "--list-options", cur_comp->name,
519 gpgconf_config_load_cb2, cur_comp);
520 cur_comp = cur_comp->next;
525 gpgconf_release (comp);
536 _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
537 gpgme_conf_type_t type, void *value)
539 gpgme_conf_arg_t arg;
541 arg = calloc (1, sizeof (*arg));
543 return gpg_error_from_syserror ();
549 /* We need to switch on type here because the alt-type is not
553 case GPGME_CONF_NONE:
554 case GPGME_CONF_UINT32:
555 arg->value.uint32 = *((unsigned int *) value);
558 case GPGME_CONF_INT32:
559 arg->value.int32 = *((int *) value);
562 case GPGME_CONF_STRING:
563 case GPGME_CONF_FILENAME:
564 case GPGME_CONF_LDAP_SERVER:
565 case GPGME_CONF_KEY_FPR:
566 case GPGME_CONF_PUB_KEY:
567 case GPGME_CONF_SEC_KEY:
568 case GPGME_CONF_ALIAS_LIST:
569 arg->value.string = strdup (value);
570 if (!arg->value.string)
573 return gpg_error_from_syserror ();
579 return gpg_error (GPG_ERR_INV_VALUE);
589 _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
591 /* Lacking the alt_type we need to switch on type here. */
594 case GPGME_CONF_NONE:
595 case GPGME_CONF_UINT32:
596 case GPGME_CONF_INT32:
597 case GPGME_CONF_STRING:
601 case GPGME_CONF_FILENAME:
602 case GPGME_CONF_LDAP_SERVER:
603 case GPGME_CONF_KEY_FPR:
604 case GPGME_CONF_PUB_KEY:
605 case GPGME_CONF_SEC_KEY:
606 case GPGME_CONF_ALIAS_LIST:
607 type = GPGME_CONF_STRING;
611 release_arg (arg, type);
616 _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
619 release_arg (opt->new_value, opt->alt_type);
623 opt->new_value = NULL;
624 opt->change_value = 0;
628 opt->new_value = arg;
629 opt->change_value = 1;
635 /* FIXME: Major problem: We don't get errors from gpgconf. */
638 gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
640 struct engine_gpgconf *gpgconf = engine;
641 gpgme_error_t err = 0;
645 char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
647 struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
651 /* FIXME: Deal with engine->home_dir. */
653 /* _gpgme_engine_new guarantees that this is not NULL. */
654 argv[0] = gpgconf->file_name;
655 argv[0] = "/nowhere/path-needs-to-be-fixed/gpgconf";
657 if (_gpgme_io_pipe (rp, 0) < 0)
658 return gpg_error_from_syserror ();
662 status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, NULL);
665 _gpgme_io_close (rp[0]);
666 _gpgme_io_close (rp[1]);
667 return gpg_error_from_syserror ();
676 buflen = gpgme_data_read (conf, buf, BUFLEN);
678 while (buflen < 0 && errno == EAGAIN);
682 err = gpg_error_from_syserror ();
683 _gpgme_io_close (rp[1]);
686 else if (buflen == 0)
688 /* All is written. */
689 _gpgme_io_close (rp[1]);
696 nwrite = _gpgme_io_write (rp[1], buf, buflen);
698 while (nwrite < 0 && errno == EAGAIN);
704 memmove (&buf[0], &buf[nwrite], buflen);
708 _gpgme_io_close (rp[1]);
709 return gpg_error_from_syserror ();
718 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
720 gpgme_error_t err = 0;
724 while (amt >= 0 && arg)
726 switch (option->alt_type)
728 case GPGME_CONF_NONE:
729 case GPGME_CONF_UINT32:
731 snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
732 buf[sizeof (buf) - 1] = '\0';
733 amt = gpgme_data_write (conf, buf, strlen (buf));
736 case GPGME_CONF_INT32:
737 snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
738 buf[sizeof (buf) - 1] = '\0';
739 amt = gpgme_data_write (conf, buf, strlen (buf));
743 case GPGME_CONF_STRING:
744 /* The complex types below are only here to silent the
746 case GPGME_CONF_FILENAME:
747 case GPGME_CONF_LDAP_SERVER:
748 case GPGME_CONF_KEY_FPR:
749 case GPGME_CONF_PUB_KEY:
750 case GPGME_CONF_SEC_KEY:
751 case GPGME_CONF_ALIAS_LIST:
752 /* One quote character, and three times to allow
753 for percent escaping. */
755 char *ptr = arg->value.string;
756 amt = gpgme_data_write (conf, "\"", 1);
765 amt = gpgme_data_write (conf, "%25", 3);
769 amt = gpgme_data_write (conf, "%3a", 3);
773 amt = gpgme_data_write (conf, "%2c", 3);
777 amt = gpgme_data_write (conf, ptr, 1);
789 /* Comma separator. */
791 amt = gpgme_data_write (conf, ",", 1);
795 return gpg_error_from_syserror ();
802 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
806 /* We use a data object to store the new configuration. */
808 gpgme_conf_opt_t option;
809 int something_changed = 0;
811 err = gpgme_data_new (&conf);
815 option = comp->options;
816 while (!err && amt >= 0 && option)
818 if (option->change_value)
820 unsigned int flags = 0;
823 something_changed = 1;
825 amt = gpgme_data_write (conf, option->name, strlen (option->name));
827 amt = gpgme_data_write (conf, ":", 1);
831 if (!option->new_value)
832 flags |= GPGME_CONF_DEFAULT;
833 snprintf (buf, sizeof (buf), "%u", flags);
834 buf[sizeof (buf) - 1] = '\0';
836 amt = gpgme_data_write (conf, buf, strlen (buf));
838 amt = gpgme_data_write (conf, ":", 1);
842 if (option->new_value)
844 err = arg_to_data (conf, option, option->new_value);
848 amt = gpgme_data_write (conf, "\n", 1);
850 option = option->next;
853 err = gpg_error_from_syserror ();
854 if (err || !something_changed)
857 err = gpgme_data_seek (conf, 0, SEEK_SET);
861 err = gpgconf_write (engine, "--change-options", comp->name, conf);
863 gpgme_data_release (conf);
869 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
875 /* Currently, we do not use the engine interface for the various
878 _gpgme_conf_release (gpgme_conf_comp_t conf)
880 gpgconf_config_release (conf);
884 struct engine_ops _gpgme_engine_ops_gpgconf =
886 /* Static functions. */
887 _gpgme_get_gpgconf_path,
889 gpgconf_get_req_version,
892 /* Member functions. */
895 NULL, /* set_status_handler */
896 NULL, /* set_command_handler */
897 NULL, /* set_colon_line_handler */
898 NULL, /* set_locale */
903 NULL, /* encrypt_sign */
905 NULL, /* export_ext */
909 NULL, /* keylist_ext */
911 NULL, /* trustlist */
913 NULL, /* getauditlog */