2
// IMPLEMENT NO_ARG_DESC!!!!
4
/* engine-gpgconf.c - gpg-conf engine.
5
Copyright (C) 2000 Werner Koch (dd9jn)
6
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
8
This file is part of GPGME.
10
GPGME is free software; you can redistribute it and/or modify it
11
under the terms of the GNU Lesser General Public License as
12
published by the Free Software Foundation; either version 2.1 of
13
the License, or (at your option) any later version.
15
GPGME is distributed in the hope that it will be useful, but
16
WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
Lesser General Public License for more details.
20
You should have received a copy of the GNU Lesser General Public
21
License along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
31
#include <sys/types.h>
35
#include <fcntl.h> /* FIXME */
48
#include "engine-backend.h"
57
typedef struct engine_gpgconf *engine_gpgconf_t;
61
gpgconf_get_version (const char *file_name)
63
return _gpgme_get_program_version (file_name ? file_name
64
: _gpgme_get_gpgconf_path ());
69
gpgconf_get_req_version (void)
71
return NEED_GPGCONF_VERSION;
76
gpgconf_release (void *engine)
78
engine_gpgconf_t gpgconf = engine;
83
if (gpgconf->file_name)
84
free (gpgconf->file_name);
85
if (gpgconf->home_dir)
86
free (gpgconf->home_dir);
93
gpgconf_new (void **engine, const char *file_name, const char *home_dir)
95
gpgme_error_t err = 0;
96
engine_gpgconf_t gpgconf;
98
gpgconf = calloc (1, sizeof *gpgconf);
100
return gpg_error_from_errno (errno);
102
gpgconf->file_name = strdup (file_name ? file_name
103
: _gpgme_get_gpgconf_path ());
104
if (!gpgconf->file_name)
105
err = gpg_error_from_syserror ();
107
if (!err && home_dir)
109
gpgconf->home_dir = strdup (home_dir);
110
if (!gpgconf->home_dir)
111
err = gpg_error_from_syserror ();
115
gpgconf_release (gpgconf);
124
release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
128
gpgme_conf_arg_t next = arg->next;
130
if (alt_type == GPGME_CONF_STRING)
131
free (arg->value.string);
139
release_opt (gpgme_conf_opt_t opt)
143
if (opt->description)
144
free (opt->description);
148
release_arg (opt->default_value, opt->alt_type);
149
if (opt->default_description)
150
free (opt->default_description);
152
release_arg (opt->no_arg_value, opt->alt_type);
153
release_arg (opt->value, opt->alt_type);
154
release_arg (opt->new_value, opt->alt_type);
161
release_comp (gpgme_conf_comp_t comp)
163
gpgme_conf_opt_t opt;
167
if (comp->description)
168
free (comp->description);
169
if (comp->program_name)
170
free (comp->program_name);
175
gpgme_conf_opt_t next = opt->next;
185
gpgconf_config_release (gpgme_conf_comp_t conf)
189
gpgme_conf_comp_t next = conf->next;
197
gpgconf_read (void *engine, char *arg1, char *arg2,
198
gpgme_error_t (*cb) (void *hook, char *line),
201
struct engine_gpgconf *gpgconf = engine;
202
gpgme_error_t err = 0;
203
#define LINELENGTH 1024
204
char line[LINELENGTH] = "";
206
char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
208
struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} };
209
struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} };
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 ();
225
status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, pfd);
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], &line[linelen], LINELENGTH - linelen - 1);
238
line[linelen + nread] = '\0';
241
while ((mark = strchr (line, '\n')))
245
if (eol > &line[0] && *eol == '\r')
249
/* Got a full line. */
250
err = (*cb) (hook, line);
254
linelen -= mark - line;
255
memmove (line, eol + 1, linelen);
259
while (nread > 0 && linelen < LINELENGTH - 1);
261
if (!err && nread < 0)
262
err = gpg_error_from_syserror ();
263
if (!err && nread > 0)
264
err = gpg_error (GPG_ERR_LINE_TOO_LONG);
266
_gpgme_io_close (rp[0]);
273
gpgconf_config_load_cb (void *hook, char *line)
275
gpgme_conf_comp_t *comp_p = hook;
276
gpgme_conf_comp_t comp = *comp_p;
278
char *field[NR_FIELDS];
281
while (line && fields < NR_FIELDS)
283
field[fields++] = line;
284
line = strchr (line, ':');
289
/* We require at least the first 3 fields. */
291
return gpg_error (GPG_ERR_INV_ENGINE);
293
/* Find the pointer to the new component in the list. */
294
while (comp && comp->next)
297
comp_p = &comp->next;
299
comp = calloc (1, sizeof (*comp));
301
return gpg_error_from_syserror ();
302
/* Prepare return value. */
303
comp->_last_opt_p = &comp->options;
306
comp->name = strdup (field[0]);
308
return gpg_error_from_syserror ();
310
comp->description = strdup (field[1]);
311
if (!comp->description)
312
return gpg_error_from_syserror ();
316
comp->description = strdup (field[2]);
317
if (!comp->description)
318
return gpg_error_from_syserror ();
326
gpgconf_parse_option (gpgme_conf_opt_t opt,
327
gpgme_conf_arg_t *arg_p, char *line)
335
mark = strchr (line, ',');
341
gpgme_conf_arg_t arg = calloc (1, sizeof (*arg));
343
return gpg_error_from_syserror ();
351
switch (opt->alt_type)
353
/* arg->value.count is an alias for arg->value.uint32. */
354
case GPGME_CONF_NONE:
355
case GPGME_CONF_UINT32:
356
arg->value.uint32 = strtoul (line, NULL, 0);
359
case GPGME_CONF_INT32:
360
arg->value.uint32 = strtol (line, NULL, 0);
363
case GPGME_CONF_STRING:
364
case GPGME_CONF_PATHNAME:
365
case GPGME_CONF_LDAP_SERVER:
366
/* Skip quote character. */
369
err = _gpgme_decode_percent_string (line, &arg->value.string,
377
/* Find beginning of next value. */
389
gpgconf_config_load_cb2 (void *hook, char *line)
392
gpgme_conf_comp_t comp = hook;
393
gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
394
gpgme_conf_opt_t opt;
396
char *field[NR_FIELDS];
399
while (line && fields < NR_FIELDS)
401
field[fields++] = line;
402
line = strchr (line, ':');
407
/* We require at least the first 10 fields. */
409
return gpg_error (GPG_ERR_INV_ENGINE);
411
opt = calloc (1, sizeof (*opt));
413
return gpg_error_from_syserror ();
415
comp->_last_opt_p = &opt->next;
420
opt->name = strdup (field[0]);
422
return gpg_error_from_syserror ();
425
opt->flags = strtoul (field[1], NULL, 0);
427
opt->level = strtoul (field[2], NULL, 0);
431
opt->description = strdup (field[3]);
432
if (!opt->description)
433
return gpg_error_from_syserror ();
436
opt->type = strtoul (field[4], NULL, 0);
438
opt->alt_type = strtoul (field[5], NULL, 0);
442
opt->argname = strdup (field[6]);
444
return gpg_error_from_syserror ();
447
if (opt->flags & GPGME_CONF_DEFAULT)
449
err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
453
else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
455
opt->default_description = strdup (field[7]);
456
if (!opt->default_description)
457
return gpg_error_from_syserror ();
460
err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
464
err = gpgconf_parse_option (opt, &opt->value, field[9]);
473
gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
476
gpgme_conf_comp_t comp = NULL;
477
gpgme_conf_comp_t cur_comp;
481
err = gpgconf_read (engine, "--list-components", NULL,
482
gpgconf_config_load_cb, &comp);
485
gpgconf_release (comp);
490
while (!err && cur_comp)
492
err = gpgconf_read (engine, "--list-options", cur_comp->name,
493
gpgconf_config_load_cb2, cur_comp);
494
cur_comp = cur_comp->next;
499
gpgconf_release (comp);
510
_gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
511
gpgme_conf_type_t type, void *value)
513
gpgme_conf_arg_t arg;
515
arg = calloc (1, sizeof (*arg));
517
return gpg_error_from_syserror ();
525
case GPGME_CONF_NONE:
526
case GPGME_CONF_UINT32:
527
arg->value.uint32 = *((unsigned int *) value);
530
case GPGME_CONF_INT32:
531
arg->value.int32 = *((int *) value);
534
case GPGME_CONF_STRING:
535
case GPGME_CONF_PATHNAME:
536
case GPGME_CONF_LDAP_SERVER:
537
arg->value.string = strdup (value);
538
if (!arg->value.string)
541
return gpg_error_from_syserror ();
547
return gpg_error (GPG_ERR_INV_VALUE);
557
_gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
561
case GPGME_CONF_NONE:
562
case GPGME_CONF_UINT32:
563
case GPGME_CONF_INT32:
564
case GPGME_CONF_STRING:
568
case GPGME_CONF_PATHNAME:
569
case GPGME_CONF_LDAP_SERVER:
570
type = GPGME_CONF_STRING;
574
release_arg (arg, type);
579
_gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
582
release_arg (opt->new_value, opt->alt_type);
586
opt->new_value = NULL;
587
opt->change_value = 0;
591
opt->new_value = arg;
592
opt->change_value = 1;
598
/* FIXME: Major problem: We don't get errors from gpgconf. */
601
gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
603
struct engine_gpgconf *gpgconf = engine;
604
gpgme_error_t err = 0;
608
char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
610
struct spawn_fd_item_s pfd[] = { {1, -1}, {-1, -1} };
611
struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
615
/* FIXME: Deal with engine->home_dir. */
617
/* _gpgme_engine_new guarantees that this is not NULL. */
618
argv[0] = gpgconf->file_name;
619
argv[0] = "/home/marcus/g10/install/bin/gpgconf";
621
if (_gpgme_io_pipe (rp, 0) < 0)
622
return gpg_error_from_syserror ();
627
status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, pfd);
630
_gpgme_io_close (rp[0]);
631
_gpgme_io_close (rp[1]);
632
return gpg_error_from_syserror ();
641
buflen = gpgme_data_read (conf, buf, BUFLEN);
643
while (buflen < 0 && errno == EAGAIN);
647
err = gpg_error_from_syserror ();
648
_gpgme_io_close (rp[1]);
651
else if (buflen == 0)
653
/* All is written. */
654
_gpgme_io_close (rp[1]);
661
nwrite = _gpgme_io_write (rp[1], buf, buflen);
663
while (nwrite < 0 && errno == EAGAIN);
669
memmove (&buf[0], &buf[nwrite], buflen);
673
_gpgme_io_close (rp[1]);
674
return gpg_error_from_syserror ();
683
arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
685
gpgme_error_t err = 0;
689
while (amt >= 0 && arg)
691
switch (option->alt_type)
693
case GPGME_CONF_NONE:
694
case GPGME_CONF_UINT32:
696
snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
697
buf[sizeof (buf) - 1] = '\0';
698
amt = gpgme_data_write (conf, buf, strlen (buf));
701
case GPGME_CONF_INT32:
702
snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
703
buf[sizeof (buf) - 1] = '\0';
704
amt = gpgme_data_write (conf, buf, strlen (buf));
707
case GPGME_CONF_STRING:
708
case GPGME_CONF_PATHNAME:
709
case GPGME_CONF_LDAP_SERVER:
710
/* One quote character, and three times to allow
711
for percent escaping. */
713
char *ptr = arg->value.string;
714
amt = gpgme_data_write (conf, "\"", 1);
723
amt = gpgme_data_write (conf, "%25", 3);
727
amt = gpgme_data_write (conf, "%3a", 3);
731
amt = gpgme_data_write (conf, "%2c", 3);
735
amt = gpgme_data_write (conf, ptr, 1);
747
/* Comma separator. */
749
amt = gpgme_data_write (conf, ",", 1);
753
return gpg_error_from_syserror ();
760
gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
764
/* We use a data object to store the new configuration. */
766
gpgme_conf_opt_t option;
767
int something_changed = 0;
769
err = gpgme_data_new (&conf);
773
option = comp->options;
774
while (!err && amt >= 0 && option)
776
if (option->change_value)
778
unsigned int flags = 0;
781
something_changed = 1;
783
amt = gpgme_data_write (conf, option->name, strlen (option->name));
785
amt = gpgme_data_write (conf, ":", 1);
789
if (!option->new_value)
790
flags |= GPGME_CONF_DEFAULT;
791
snprintf (buf, sizeof (buf), "%u", flags);
792
buf[sizeof (buf) - 1] = '\0';
794
amt = gpgme_data_write (conf, buf, strlen (buf));
796
amt = gpgme_data_write (conf, ":", 1);
800
if (option->new_value)
802
err = arg_to_data (conf, option, option->new_value);
806
amt = gpgme_data_write (conf, "\n", 1);
808
option = option->next;
811
err = gpg_error_from_syserror ();
812
if (err || !something_changed)
815
err = gpgme_data_seek (conf, 0, SEEK_SET);
819
err = gpgconf_write (engine, "--change-options", comp->name, conf);
821
gpgme_data_release (conf);
827
gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
833
/* Currently, we do not use the engine interface for the various
836
_gpgme_conf_release (gpgme_conf_comp_t conf)
838
gpgconf_config_release (conf);
842
struct engine_ops _gpgme_engine_ops_gpgconf =
844
/* Static functions. */
845
_gpgme_get_gpgconf_path,
847
gpgconf_get_req_version,
850
/* Member functions. */
853
NULL, /* set_status_handler */
854
NULL, /* set_command_handler */
855
NULL, /* set_colon_line_handler */
856
NULL, /* set_locale */
861
NULL, /* encrypt_sign */
863
NULL, /* export_ext */
867
NULL, /* keylist_ext */
869
NULL, /* trustlist */
871
NULL, /* getauditlog */