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>
32 #include <fcntl.h> /* FIXME */
45 #include "engine-backend.h"
54 typedef struct engine_gpgconf *engine_gpgconf_t;
58 gpgconf_get_version (const char *file_name)
60 return _gpgme_get_program_version (file_name ? file_name
61 : _gpgme_get_gpgconf_path ());
66 gpgconf_get_req_version (void)
68 return NEED_GPGCONF_VERSION;
73 gpgconf_release (void *engine)
75 engine_gpgconf_t gpgconf = engine;
80 if (gpgconf->file_name)
81 free (gpgconf->file_name);
82 if (gpgconf->home_dir)
83 free (gpgconf->home_dir);
90 gpgconf_new (void **engine, const char *file_name, const char *home_dir)
92 gpgme_error_t err = 0;
93 engine_gpgconf_t gpgconf;
95 gpgconf = calloc (1, sizeof *gpgconf);
97 return gpg_error_from_errno (errno);
99 gpgconf->file_name = strdup (file_name ? file_name
100 : _gpgme_get_gpgconf_path ());
101 if (!gpgconf->file_name)
102 err = gpg_error_from_syserror ();
104 if (!err && home_dir)
106 gpgconf->home_dir = strdup (home_dir);
107 if (!gpgconf->home_dir)
108 err = gpg_error_from_syserror ();
112 gpgconf_release (gpgconf);
121 release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
125 gpgme_conf_arg_t next = arg->next;
127 if (alt_type == GPGME_CONF_STRING)
128 free (arg->value.string);
136 release_opt (gpgme_conf_opt_t opt)
140 if (opt->description)
141 free (opt->description);
145 release_arg (opt->default_value, opt->alt_type);
146 if (opt->default_description)
147 free (opt->default_description);
149 release_arg (opt->no_arg_value, opt->alt_type);
150 release_arg (opt->value, opt->alt_type);
151 release_arg (opt->new_value, opt->alt_type);
158 release_comp (gpgme_conf_comp_t comp)
160 gpgme_conf_opt_t opt;
164 if (comp->description)
165 free (comp->description);
166 if (comp->program_name)
167 free (comp->program_name);
172 gpgme_conf_opt_t next = opt->next;
182 gpgconf_config_release (gpgme_conf_comp_t conf)
186 gpgme_conf_comp_t next = conf->next;
194 gpgconf_read (void *engine, char *arg1, char *arg2,
195 gpgme_error_t (*cb) (void *hook, char *line),
198 struct engine_gpgconf *gpgconf = engine;
199 gpgme_error_t err = 0;
200 #define LINELENGTH 1024
201 char linebuf[LINELENGTH] = "";
203 char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
205 struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
215 /* FIXME: Deal with engine->home_dir. */
217 /* _gpgme_engine_new guarantees that this is not NULL. */
218 argv[0] = gpgconf->file_name;
220 if (_gpgme_io_pipe (rp, 1) < 0)
221 return gpg_error_from_syserror ();
225 status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
228 _gpgme_io_close (rp[0]);
229 _gpgme_io_close (rp[1]);
230 return gpg_error_from_syserror ();
235 nread = _gpgme_io_read (rp[0],
236 linebuf + linelen, LINELENGTH - linelen - 1);
240 const char *lastmark = NULL;
244 linebuf[linelen] = '\0';
246 for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
249 if (mark > line && mark[-1] == '\r')
254 /* Got a full line. Due to the CR removal code (which
255 occurs only on Windows) we might be one-off and thus
256 would see empty lines. Don't pass them to the
258 err = *line? (*cb) (hook, line) : 0;
263 nused = lastmark? (lastmark + 1 - linebuf) : 0;
264 memmove (linebuf, linebuf + nused, linelen - nused);
268 while (nread > 0 && linelen < LINELENGTH - 1);
270 if (!err && nread < 0)
271 err = gpg_error_from_syserror ();
272 if (!err && nread > 0)
273 err = gpg_error (GPG_ERR_LINE_TOO_LONG);
276 _gpgme_io_close (rp[0]);
283 gpgconf_config_load_cb (void *hook, char *line)
285 gpgme_conf_comp_t *comp_p = hook;
286 gpgme_conf_comp_t comp = *comp_p;
288 char *field[NR_FIELDS];
291 while (line && fields < NR_FIELDS)
293 field[fields++] = line;
294 line = strchr (line, ':');
299 /* We require at least the first 3 fields. */
301 return gpg_error (GPG_ERR_INV_ENGINE);
303 /* Find the pointer to the new component in the list. */
304 while (comp && comp->next)
307 comp_p = &comp->next;
309 comp = calloc (1, sizeof (*comp));
311 return gpg_error_from_syserror ();
312 /* Prepare return value. */
313 comp->_last_opt_p = &comp->options;
316 comp->name = strdup (field[0]);
318 return gpg_error_from_syserror ();
320 comp->description = strdup (field[1]);
321 if (!comp->description)
322 return gpg_error_from_syserror ();
326 comp->program_name = strdup (field[2]);
327 if (!comp->program_name)
328 return gpg_error_from_syserror ();
336 gpgconf_parse_option (gpgme_conf_opt_t opt,
337 gpgme_conf_arg_t *arg_p, char *line)
347 gpgme_conf_arg_t arg;
349 mark = strchr (line, ',');
353 arg = calloc (1, sizeof (*arg));
355 return gpg_error_from_syserror ();
363 switch (opt->alt_type)
365 /* arg->value.count is an alias for arg->value.uint32. */
366 case GPGME_CONF_NONE:
367 case GPGME_CONF_UINT32:
368 arg->value.uint32 = strtoul (line, NULL, 0);
371 case GPGME_CONF_INT32:
372 arg->value.uint32 = strtol (line, NULL, 0);
375 case GPGME_CONF_STRING:
376 /* The complex types below are only here to silent the
378 case GPGME_CONF_FILENAME:
379 case GPGME_CONF_LDAP_SERVER:
380 case GPGME_CONF_KEY_FPR:
381 case GPGME_CONF_PUB_KEY:
382 case GPGME_CONF_SEC_KEY:
383 case GPGME_CONF_ALIAS_LIST:
384 /* Skip quote character. */
387 err = _gpgme_decode_percent_string (line, &arg->value.string,
395 /* Find beginning of next value. */
407 gpgconf_config_load_cb2 (void *hook, char *line)
410 gpgme_conf_comp_t comp = hook;
411 gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
412 gpgme_conf_opt_t opt;
414 char *field[NR_FIELDS];
417 while (line && fields < NR_FIELDS)
419 field[fields++] = line;
420 line = strchr (line, ':');
425 /* We require at least the first 10 fields. */
427 return gpg_error (GPG_ERR_INV_ENGINE);
429 opt = calloc (1, sizeof (*opt));
431 return gpg_error_from_syserror ();
433 comp->_last_opt_p = &opt->next;
438 opt->name = strdup (field[0]);
440 return gpg_error_from_syserror ();
443 opt->flags = strtoul (field[1], NULL, 0);
445 opt->level = strtoul (field[2], NULL, 0);
449 opt->description = strdup (field[3]);
450 if (!opt->description)
451 return gpg_error_from_syserror ();
454 opt->type = strtoul (field[4], NULL, 0);
456 opt->alt_type = strtoul (field[5], NULL, 0);
460 opt->argname = strdup (field[6]);
462 return gpg_error_from_syserror ();
465 if (opt->flags & GPGME_CONF_DEFAULT)
467 err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
471 else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
473 opt->default_description = strdup (field[7]);
474 if (!opt->default_description)
475 return gpg_error_from_syserror ();
478 if (opt->flags & GPGME_CONF_NO_ARG_DESC)
480 opt->no_arg_description = strdup (field[8]);
481 if (!opt->no_arg_description)
482 return gpg_error_from_syserror ();
486 err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
491 err = gpgconf_parse_option (opt, &opt->value, field[9]);
500 gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
503 gpgme_conf_comp_t comp = NULL;
504 gpgme_conf_comp_t cur_comp;
508 err = gpgconf_read (engine, "--list-components", NULL,
509 gpgconf_config_load_cb, &comp);
512 gpgconf_release (comp);
517 while (!err && cur_comp)
519 err = gpgconf_read (engine, "--list-options", cur_comp->name,
520 gpgconf_config_load_cb2, cur_comp);
521 cur_comp = cur_comp->next;
526 gpgconf_release (comp);
537 _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
538 gpgme_conf_type_t type, void *value)
540 gpgme_conf_arg_t arg;
542 arg = calloc (1, sizeof (*arg));
544 return gpg_error_from_syserror ();
550 /* We need to switch on type here because the alt-type is not
554 case GPGME_CONF_NONE:
555 case GPGME_CONF_UINT32:
556 arg->value.uint32 = *((unsigned int *) value);
559 case GPGME_CONF_INT32:
560 arg->value.int32 = *((int *) value);
563 case GPGME_CONF_STRING:
564 case GPGME_CONF_FILENAME:
565 case GPGME_CONF_LDAP_SERVER:
566 case GPGME_CONF_KEY_FPR:
567 case GPGME_CONF_PUB_KEY:
568 case GPGME_CONF_SEC_KEY:
569 case GPGME_CONF_ALIAS_LIST:
570 arg->value.string = strdup (value);
571 if (!arg->value.string)
574 return gpg_error_from_syserror ();
580 return gpg_error (GPG_ERR_INV_VALUE);
590 _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
592 /* Lacking the alt_type we need to switch on type here. */
595 case GPGME_CONF_NONE:
596 case GPGME_CONF_UINT32:
597 case GPGME_CONF_INT32:
598 case GPGME_CONF_STRING:
602 case GPGME_CONF_FILENAME:
603 case GPGME_CONF_LDAP_SERVER:
604 case GPGME_CONF_KEY_FPR:
605 case GPGME_CONF_PUB_KEY:
606 case GPGME_CONF_SEC_KEY:
607 case GPGME_CONF_ALIAS_LIST:
608 type = GPGME_CONF_STRING;
612 release_arg (arg, type);
617 _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
620 release_arg (opt->new_value, opt->alt_type);
624 opt->new_value = NULL;
625 opt->change_value = 0;
629 opt->new_value = arg;
630 opt->change_value = 1;
636 /* FIXME: Major problem: We don't get errors from gpgconf. */
639 gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
641 struct engine_gpgconf *gpgconf = engine;
642 gpgme_error_t err = 0;
646 char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
648 struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
652 /* FIXME: Deal with engine->home_dir. */
654 /* _gpgme_engine_new guarantees that this is not NULL. */
655 argv[0] = gpgconf->file_name;
656 argv[0] = "/nowhere/path-needs-to-be-fixed/gpgconf";
658 if (_gpgme_io_pipe (rp, 0) < 0)
659 return gpg_error_from_syserror ();
663 status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
666 _gpgme_io_close (rp[0]);
667 _gpgme_io_close (rp[1]);
668 return gpg_error_from_syserror ();
677 buflen = gpgme_data_read (conf, buf, BUFLEN);
679 while (buflen < 0 && errno == EAGAIN);
683 err = gpg_error_from_syserror ();
684 _gpgme_io_close (rp[1]);
687 else if (buflen == 0)
689 /* All is written. */
690 _gpgme_io_close (rp[1]);
697 nwrite = _gpgme_io_write (rp[1], buf, buflen);
699 while (nwrite < 0 && errno == EAGAIN);
705 memmove (&buf[0], &buf[nwrite], buflen);
709 _gpgme_io_close (rp[1]);
710 return gpg_error_from_syserror ();
719 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
721 gpgme_error_t err = 0;
725 while (amt >= 0 && arg)
727 switch (option->alt_type)
729 case GPGME_CONF_NONE:
730 case GPGME_CONF_UINT32:
732 snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
733 buf[sizeof (buf) - 1] = '\0';
734 amt = gpgme_data_write (conf, buf, strlen (buf));
737 case GPGME_CONF_INT32:
738 snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
739 buf[sizeof (buf) - 1] = '\0';
740 amt = gpgme_data_write (conf, buf, strlen (buf));
744 case GPGME_CONF_STRING:
745 /* The complex types below are only here to silent the
747 case GPGME_CONF_FILENAME:
748 case GPGME_CONF_LDAP_SERVER:
749 case GPGME_CONF_KEY_FPR:
750 case GPGME_CONF_PUB_KEY:
751 case GPGME_CONF_SEC_KEY:
752 case GPGME_CONF_ALIAS_LIST:
753 /* One quote character, and three times to allow
754 for percent escaping. */
756 char *ptr = arg->value.string;
757 amt = gpgme_data_write (conf, "\"", 1);
766 amt = gpgme_data_write (conf, "%25", 3);
770 amt = gpgme_data_write (conf, "%3a", 3);
774 amt = gpgme_data_write (conf, "%2c", 3);
778 amt = gpgme_data_write (conf, ptr, 1);
790 /* Comma separator. */
792 amt = gpgme_data_write (conf, ",", 1);
796 return gpg_error_from_syserror ();
803 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
807 /* We use a data object to store the new configuration. */
809 gpgme_conf_opt_t option;
810 int something_changed = 0;
812 err = gpgme_data_new (&conf);
816 option = comp->options;
817 while (!err && amt >= 0 && option)
819 if (option->change_value)
821 unsigned int flags = 0;
824 something_changed = 1;
826 amt = gpgme_data_write (conf, option->name, strlen (option->name));
828 amt = gpgme_data_write (conf, ":", 1);
832 if (!option->new_value)
833 flags |= GPGME_CONF_DEFAULT;
834 snprintf (buf, sizeof (buf), "%u", flags);
835 buf[sizeof (buf) - 1] = '\0';
837 amt = gpgme_data_write (conf, buf, strlen (buf));
839 amt = gpgme_data_write (conf, ":", 1);
843 if (option->new_value)
845 err = arg_to_data (conf, option, option->new_value);
849 amt = gpgme_data_write (conf, "\n", 1);
851 option = option->next;
854 err = gpg_error_from_syserror ();
855 if (err || !something_changed)
858 err = gpgme_data_seek (conf, 0, SEEK_SET);
862 err = gpgconf_write (engine, "--change-options", comp->name, conf);
864 gpgme_data_release (conf);
870 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
876 /* Currently, we do not use the engine interface for the various
879 _gpgme_conf_release (gpgme_conf_comp_t conf)
881 gpgconf_config_release (conf);
885 struct engine_ops _gpgme_engine_ops_gpgconf =
887 /* Static functions. */
888 _gpgme_get_gpgconf_path,
891 gpgconf_get_req_version,
894 /* Member functions. */
897 NULL, /* set_status_handler */
898 NULL, /* set_command_handler */
899 NULL, /* set_colon_line_handler */
900 NULL, /* set_locale */
901 NULL, /* set_protocol */
903 NULL, /* decrypt_verify */
907 NULL, /* encrypt_sign */
909 NULL, /* export_ext */
913 NULL, /* keylist_ext */
915 NULL, /* trustlist */
917 NULL, /* getauditlog */
918 NULL, /* opassuan_transact */