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)
622 release_arg (opt->new_value, opt->alt_type);
626 opt->new_value = NULL;
627 opt->change_value = 0;
631 opt->new_value = arg;
632 opt->change_value = 1;
638 /* FIXME: Major problem: We don't get errors from gpgconf. */
641 gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
643 struct engine_gpgconf *gpgconf = engine;
644 gpgme_error_t err = 0;
648 char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
650 struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
654 /* FIXME: Deal with engine->home_dir. */
656 /* _gpgme_engine_new guarantees that this is not NULL. */
657 argv[0] = gpgconf->file_name;
658 argv[0] = "/nowhere/path-needs-to-be-fixed/gpgconf";
660 if (_gpgme_io_pipe (rp, 0) < 0)
661 return gpg_error_from_syserror ();
665 status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
668 _gpgme_io_close (rp[0]);
669 _gpgme_io_close (rp[1]);
670 return gpg_error_from_syserror ();
679 buflen = gpgme_data_read (conf, buf, BUFLEN);
681 while (buflen < 0 && errno == EAGAIN);
685 err = gpg_error_from_syserror ();
686 _gpgme_io_close (rp[1]);
689 else if (buflen == 0)
691 /* All is written. */
692 _gpgme_io_close (rp[1]);
699 nwrite = _gpgme_io_write (rp[1], buf, buflen);
701 while (nwrite < 0 && errno == EAGAIN);
707 memmove (&buf[0], &buf[nwrite], buflen);
711 _gpgme_io_close (rp[1]);
712 return gpg_error_from_syserror ();
721 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
723 gpgme_error_t err = 0;
727 while (amt >= 0 && arg)
729 switch (option->alt_type)
731 case GPGME_CONF_NONE:
732 case GPGME_CONF_UINT32:
734 snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
735 buf[sizeof (buf) - 1] = '\0';
736 amt = gpgme_data_write (conf, buf, strlen (buf));
739 case GPGME_CONF_INT32:
740 snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
741 buf[sizeof (buf) - 1] = '\0';
742 amt = gpgme_data_write (conf, buf, strlen (buf));
746 case GPGME_CONF_STRING:
747 /* The complex types below are only here to silent the
749 case GPGME_CONF_FILENAME:
750 case GPGME_CONF_LDAP_SERVER:
751 case GPGME_CONF_KEY_FPR:
752 case GPGME_CONF_PUB_KEY:
753 case GPGME_CONF_SEC_KEY:
754 case GPGME_CONF_ALIAS_LIST:
755 /* One quote character, and three times to allow
756 for percent escaping. */
758 char *ptr = arg->value.string;
759 amt = gpgme_data_write (conf, "\"", 1);
768 amt = gpgme_data_write (conf, "%25", 3);
772 amt = gpgme_data_write (conf, "%3a", 3);
776 amt = gpgme_data_write (conf, "%2c", 3);
780 amt = gpgme_data_write (conf, ptr, 1);
792 /* Comma separator. */
794 amt = gpgme_data_write (conf, ",", 1);
798 return gpg_error_from_syserror ();
805 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
809 /* We use a data object to store the new configuration. */
811 gpgme_conf_opt_t option;
812 int something_changed = 0;
814 err = gpgme_data_new (&conf);
818 option = comp->options;
819 while (!err && amt >= 0 && option)
821 if (option->change_value)
823 unsigned int flags = 0;
826 something_changed = 1;
828 amt = gpgme_data_write (conf, option->name, strlen (option->name));
830 amt = gpgme_data_write (conf, ":", 1);
834 if (!option->new_value)
835 flags |= GPGME_CONF_DEFAULT;
836 snprintf (buf, sizeof (buf), "%u", flags);
837 buf[sizeof (buf) - 1] = '\0';
839 amt = gpgme_data_write (conf, buf, strlen (buf));
841 amt = gpgme_data_write (conf, ":", 1);
845 if (option->new_value)
847 err = arg_to_data (conf, option, option->new_value);
851 amt = gpgme_data_write (conf, "\n", 1);
853 option = option->next;
856 err = gpg_error_from_syserror ();
857 if (err || !something_changed)
860 err = gpgme_data_seek (conf, 0, SEEK_SET);
864 err = gpgconf_write (engine, "--change-options", comp->name, conf);
866 gpgme_data_release (conf);
872 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
878 /* Currently, we do not use the engine interface for the various
881 _gpgme_conf_release (gpgme_conf_comp_t conf)
883 gpgconf_config_release (conf);
887 struct engine_ops _gpgme_engine_ops_gpgconf =
889 /* Static functions. */
890 _gpgme_get_gpgconf_path,
893 gpgconf_get_req_version,
896 /* Member functions. */
899 NULL, /* set_status_handler */
900 NULL, /* set_command_handler */
901 NULL, /* set_colon_line_handler */
902 NULL, /* set_locale */
903 NULL, /* set_protocol */
905 NULL, /* decrypt_verify */
909 NULL, /* encrypt_sign */
911 NULL, /* export_ext */
915 NULL, /* keylist_ext */
917 NULL, /* trustlist */
919 NULL, /* getauditlog */
920 NULL, /* opassuan_transact */