Line data Source code
1 : /* engine-gpgconf.c - gpg-conf engine.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008,
4 : 2013 g10 Code GmbH
5 :
6 : This file is part of GPGME.
7 :
8 : GPGME is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as
10 : published by the Free Software Foundation; either version 2.1 of
11 : the License, or (at your option) any later version.
12 :
13 : GPGME is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public
19 : License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 :
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #ifdef HAVE_SYS_TYPES_H
29 : # include <sys/types.h>
30 : #endif
31 : #include <assert.h>
32 : #ifdef HAVE_UNISTD_H
33 : # include <unistd.h>
34 : #endif
35 : #include <fcntl.h> /* FIXME */
36 : #include <errno.h>
37 :
38 : #include "gpgme.h"
39 : #include "util.h"
40 : #include "ops.h"
41 : #include "wait.h"
42 : #include "priv-io.h"
43 : #include "sema.h"
44 :
45 : #include "assuan.h"
46 : #include "debug.h"
47 :
48 : #include "engine-backend.h"
49 :
50 :
51 : struct engine_gpgconf
52 : {
53 : char *file_name;
54 : char *home_dir;
55 : };
56 :
57 : typedef struct engine_gpgconf *engine_gpgconf_t;
58 :
59 :
60 : static char *
61 56 : gpgconf_get_version (const char *file_name)
62 : {
63 56 : return _gpgme_get_program_version (file_name ? file_name
64 : : _gpgme_get_default_gpgconf_name ());
65 : }
66 :
67 :
68 : static const char *
69 56 : gpgconf_get_req_version (void)
70 : {
71 56 : return "2.0.4";
72 : }
73 :
74 :
75 : static void
76 0 : gpgconf_release (void *engine)
77 : {
78 0 : engine_gpgconf_t gpgconf = engine;
79 :
80 0 : if (!gpgconf)
81 0 : return;
82 :
83 0 : if (gpgconf->file_name)
84 0 : free (gpgconf->file_name);
85 0 : if (gpgconf->home_dir)
86 0 : free (gpgconf->home_dir);
87 :
88 0 : free (gpgconf);
89 : }
90 :
91 :
92 : static gpgme_error_t
93 0 : gpgconf_new (void **engine, const char *file_name, const char *home_dir,
94 : const char *version)
95 : {
96 0 : gpgme_error_t err = 0;
97 : engine_gpgconf_t gpgconf;
98 :
99 : (void)version; /* Not yet used. */
100 :
101 0 : gpgconf = calloc (1, sizeof *gpgconf);
102 0 : if (!gpgconf)
103 0 : return gpg_error_from_syserror ();
104 :
105 0 : gpgconf->file_name = strdup (file_name ? file_name
106 : : _gpgme_get_default_gpgconf_name ());
107 0 : if (!gpgconf->file_name)
108 0 : err = gpg_error_from_syserror ();
109 :
110 0 : if (!err && home_dir)
111 : {
112 0 : gpgconf->home_dir = strdup (home_dir);
113 0 : if (!gpgconf->home_dir)
114 0 : err = gpg_error_from_syserror ();
115 : }
116 :
117 0 : if (err)
118 0 : gpgconf_release (gpgconf);
119 : else
120 0 : *engine = gpgconf;
121 :
122 0 : return err;
123 : }
124 :
125 :
126 : static void
127 0 : release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
128 : {
129 0 : while (arg)
130 : {
131 0 : gpgme_conf_arg_t next = arg->next;
132 :
133 0 : if (alt_type == GPGME_CONF_STRING)
134 0 : free (arg->value.string);
135 0 : free (arg);
136 0 : arg = next;
137 : }
138 0 : }
139 :
140 :
141 : static void
142 0 : release_opt (gpgme_conf_opt_t opt)
143 : {
144 0 : if (opt->name)
145 0 : free (opt->name);
146 0 : if (opt->description)
147 0 : free (opt->description);
148 0 : if (opt->argname)
149 0 : free (opt->argname);
150 :
151 0 : release_arg (opt->default_value, opt->alt_type);
152 0 : if (opt->default_description)
153 0 : free (opt->default_description);
154 :
155 0 : release_arg (opt->no_arg_value, opt->alt_type);
156 0 : release_arg (opt->value, opt->alt_type);
157 0 : release_arg (opt->new_value, opt->alt_type);
158 :
159 0 : free (opt);
160 0 : }
161 :
162 :
163 : static void
164 0 : release_comp (gpgme_conf_comp_t comp)
165 : {
166 : gpgme_conf_opt_t opt;
167 :
168 0 : if (comp->name)
169 0 : free (comp->name);
170 0 : if (comp->description)
171 0 : free (comp->description);
172 0 : if (comp->program_name)
173 0 : free (comp->program_name);
174 :
175 0 : opt = comp->options;
176 0 : while (opt)
177 : {
178 0 : gpgme_conf_opt_t next = opt->next;
179 0 : release_opt (opt);
180 0 : opt = next;
181 : }
182 :
183 0 : free (comp);
184 0 : }
185 :
186 :
187 : static void
188 0 : gpgconf_config_release (gpgme_conf_comp_t conf)
189 : {
190 0 : while (conf)
191 : {
192 0 : gpgme_conf_comp_t next = conf->next;
193 0 : release_comp (conf);
194 0 : conf = next;
195 : }
196 0 : }
197 :
198 : /* Read from gpgconf and pass line after line to the hook function.
199 : We put a limit of 64 k on the maximum size for a line. This should
200 : allow for quite a long "group" line, which is usually the longest
201 : line (mine is currently ~3k). */
202 : static gpgme_error_t
203 0 : gpgconf_read (void *engine, char *arg1, char *arg2,
204 : gpgme_error_t (*cb) (void *hook, char *line),
205 : void *hook)
206 : {
207 0 : struct engine_gpgconf *gpgconf = engine;
208 0 : gpgme_error_t err = 0;
209 : char *linebuf;
210 : size_t linebufsize;
211 : int linelen;
212 0 : char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
213 : int rp[2];
214 0 : struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
215 : {-1, -1} };
216 : int status;
217 : int nread;
218 0 : char *mark = NULL;
219 :
220 0 : argv[1] = arg1;
221 0 : argv[2] = arg2;
222 :
223 :
224 : /* FIXME: Deal with engine->home_dir. */
225 :
226 : /* _gpgme_engine_new guarantees that this is not NULL. */
227 0 : argv[0] = gpgconf->file_name;
228 :
229 0 : if (_gpgme_io_pipe (rp, 1) < 0)
230 0 : return gpg_error_from_syserror ();
231 :
232 0 : cfd[0].fd = rp[1];
233 :
234 0 : status = _gpgme_io_spawn (gpgconf->file_name, argv,
235 : IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
236 0 : if (status < 0)
237 : {
238 0 : _gpgme_io_close (rp[0]);
239 0 : _gpgme_io_close (rp[1]);
240 0 : return gpg_error_from_syserror ();
241 : }
242 :
243 0 : linebufsize = 1024; /* Usually enough for conf lines. */
244 0 : linebuf = malloc (linebufsize);
245 0 : if (!linebuf)
246 : {
247 0 : err = gpg_error_from_syserror ();
248 0 : goto leave;
249 : }
250 0 : linelen = 0;
251 :
252 0 : while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
253 0 : linebufsize - linelen - 1)))
254 : {
255 : char *line;
256 0 : const char *lastmark = NULL;
257 : size_t nused;
258 :
259 0 : if (nread < 0)
260 : {
261 0 : err = gpg_error_from_syserror ();
262 0 : goto leave;
263 : }
264 :
265 0 : linelen += nread;
266 0 : linebuf[linelen] = '\0';
267 :
268 0 : for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
269 : {
270 0 : lastmark = mark;
271 0 : if (mark > line && mark[-1] == '\r')
272 0 : mark[-1] = '\0';
273 : else
274 0 : mark[0] = '\0';
275 :
276 : /* Got a full line. Due to the CR removal code (which
277 : occurs only on Windows) we might be one-off and thus
278 : would see empty lines. Don't pass them to the
279 : callback. */
280 0 : err = *line? (*cb) (hook, line) : 0;
281 0 : if (err)
282 0 : goto leave;
283 : }
284 :
285 0 : nused = lastmark? (lastmark + 1 - linebuf) : 0;
286 0 : memmove (linebuf, linebuf + nused, linelen - nused);
287 0 : linelen -= nused;
288 :
289 0 : if (!(linelen < linebufsize - 1))
290 : {
291 : char *newlinebuf;
292 :
293 0 : if (linelen < 8 * 1024 - 1)
294 0 : linebufsize = 8 * 1024;
295 0 : else if (linelen < 64 * 1024 - 1)
296 0 : linebufsize = 64 * 1024;
297 : else
298 : {
299 : /* We reached our limit - give up. */
300 0 : err = gpg_error (GPG_ERR_LINE_TOO_LONG);
301 0 : goto leave;
302 : }
303 :
304 0 : newlinebuf = realloc (linebuf, linebufsize);
305 0 : if (!newlinebuf)
306 : {
307 0 : err = gpg_error_from_syserror ();
308 0 : goto leave;
309 : }
310 0 : linebuf = newlinebuf;
311 : }
312 : }
313 :
314 : leave:
315 0 : free (linebuf);
316 0 : _gpgme_io_close (rp[0]);
317 0 : return err;
318 : }
319 :
320 :
321 : static gpgme_error_t
322 0 : gpgconf_config_load_cb (void *hook, char *line)
323 : {
324 0 : gpgme_conf_comp_t *comp_p = hook;
325 0 : gpgme_conf_comp_t comp = *comp_p;
326 : #define NR_FIELDS 16
327 : char *field[NR_FIELDS];
328 0 : int fields = 0;
329 :
330 0 : while (line && fields < NR_FIELDS)
331 : {
332 0 : field[fields++] = line;
333 0 : line = strchr (line, ':');
334 0 : if (line)
335 0 : *(line++) = '\0';
336 : }
337 :
338 : /* We require at least the first 3 fields. */
339 0 : if (fields < 2)
340 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
341 :
342 : /* Find the pointer to the new component in the list. */
343 0 : while (comp && comp->next)
344 0 : comp = comp->next;
345 0 : if (comp)
346 0 : comp_p = &comp->next;
347 :
348 0 : comp = calloc (1, sizeof (*comp));
349 0 : if (!comp)
350 0 : return gpg_error_from_syserror ();
351 : /* Prepare return value. */
352 0 : comp->_last_opt_p = &comp->options;
353 0 : *comp_p = comp;
354 :
355 0 : comp->name = strdup (field[0]);
356 0 : if (!comp->name)
357 0 : return gpg_error_from_syserror ();
358 :
359 0 : comp->description = strdup (field[1]);
360 0 : if (!comp->description)
361 0 : return gpg_error_from_syserror ();
362 :
363 0 : if (fields >= 3)
364 : {
365 0 : comp->program_name = strdup (field[2]);
366 0 : if (!comp->program_name)
367 0 : return gpg_error_from_syserror ();
368 : }
369 :
370 0 : return 0;
371 : }
372 :
373 :
374 : static gpgme_error_t
375 0 : gpgconf_parse_option (gpgme_conf_opt_t opt,
376 : gpgme_conf_arg_t *arg_p, char *line)
377 : {
378 : gpgme_error_t err;
379 : char *mark;
380 :
381 0 : if (!line[0])
382 0 : return 0;
383 :
384 0 : while (line)
385 : {
386 : gpgme_conf_arg_t arg;
387 :
388 0 : mark = strchr (line, ',');
389 0 : if (mark)
390 0 : *mark = '\0';
391 :
392 0 : arg = calloc (1, sizeof (*arg));
393 0 : if (!arg)
394 0 : return gpg_error_from_syserror ();
395 0 : *arg_p = arg;
396 0 : arg_p = &arg->next;
397 :
398 0 : if (*line == '\0')
399 0 : arg->no_arg = 1;
400 : else
401 : {
402 0 : switch (opt->alt_type)
403 : {
404 : /* arg->value.count is an alias for arg->value.uint32. */
405 : case GPGME_CONF_NONE:
406 : case GPGME_CONF_UINT32:
407 0 : arg->value.uint32 = strtoul (line, NULL, 0);
408 0 : break;
409 :
410 : case GPGME_CONF_INT32:
411 0 : arg->value.uint32 = strtol (line, NULL, 0);
412 0 : break;
413 :
414 : case GPGME_CONF_STRING:
415 : /* The complex types below are only here to silent the
416 : compiler warning. */
417 : case GPGME_CONF_FILENAME:
418 : case GPGME_CONF_LDAP_SERVER:
419 : case GPGME_CONF_KEY_FPR:
420 : case GPGME_CONF_PUB_KEY:
421 : case GPGME_CONF_SEC_KEY:
422 : case GPGME_CONF_ALIAS_LIST:
423 : /* Skip quote character. */
424 0 : line++;
425 :
426 0 : err = _gpgme_decode_percent_string (line, &arg->value.string,
427 : 0, 0);
428 0 : if (err)
429 0 : return err;
430 0 : break;
431 : }
432 : }
433 :
434 : /* Find beginning of next value. */
435 0 : if (mark++ && *mark)
436 0 : line = mark;
437 : else
438 0 : line = NULL;
439 : }
440 :
441 0 : return 0;
442 : }
443 :
444 :
445 : static gpgme_error_t
446 0 : gpgconf_config_load_cb2 (void *hook, char *line)
447 : {
448 : gpgme_error_t err;
449 0 : gpgme_conf_comp_t comp = hook;
450 0 : gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
451 : gpgme_conf_opt_t opt;
452 : #define NR_FIELDS 16
453 : char *field[NR_FIELDS];
454 0 : int fields = 0;
455 :
456 0 : while (line && fields < NR_FIELDS)
457 : {
458 0 : field[fields++] = line;
459 0 : line = strchr (line, ':');
460 0 : if (line)
461 0 : *(line++) = '\0';
462 : }
463 :
464 : /* We require at least the first 10 fields. */
465 0 : if (fields < 10)
466 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
467 :
468 0 : opt = calloc (1, sizeof (*opt));
469 0 : if (!opt)
470 0 : return gpg_error_from_syserror ();
471 :
472 0 : comp->_last_opt_p = &opt->next;
473 0 : *opt_p = opt;
474 :
475 0 : if (field[0][0])
476 : {
477 0 : opt->name = strdup (field[0]);
478 0 : if (!opt->name)
479 0 : return gpg_error_from_syserror ();
480 : }
481 :
482 0 : opt->flags = strtoul (field[1], NULL, 0);
483 :
484 0 : opt->level = strtoul (field[2], NULL, 0);
485 :
486 0 : if (field[3][0])
487 : {
488 0 : opt->description = strdup (field[3]);
489 0 : if (!opt->description)
490 0 : return gpg_error_from_syserror ();
491 : }
492 :
493 0 : opt->type = strtoul (field[4], NULL, 0);
494 :
495 0 : opt->alt_type = strtoul (field[5], NULL, 0);
496 :
497 0 : if (field[6][0])
498 : {
499 0 : opt->argname = strdup (field[6]);
500 0 : if (!opt->argname)
501 0 : return gpg_error_from_syserror ();
502 : }
503 :
504 0 : if (opt->flags & GPGME_CONF_DEFAULT)
505 : {
506 0 : err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
507 0 : if (err)
508 0 : return err;
509 : }
510 0 : else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
511 : {
512 0 : opt->default_description = strdup (field[7]);
513 0 : if (!opt->default_description)
514 0 : return gpg_error_from_syserror ();
515 : }
516 :
517 0 : if (opt->flags & GPGME_CONF_NO_ARG_DESC)
518 : {
519 0 : opt->no_arg_description = strdup (field[8]);
520 0 : if (!opt->no_arg_description)
521 0 : return gpg_error_from_syserror ();
522 : }
523 : else
524 : {
525 0 : err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
526 0 : if (err)
527 0 : return err;
528 : }
529 :
530 0 : err = gpgconf_parse_option (opt, &opt->value, field[9]);
531 0 : if (err)
532 0 : return err;
533 :
534 0 : return 0;
535 : }
536 :
537 :
538 : static gpgme_error_t
539 0 : gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
540 : {
541 : gpgme_error_t err;
542 0 : gpgme_conf_comp_t comp = NULL;
543 : gpgme_conf_comp_t cur_comp;
544 :
545 0 : *comp_p = NULL;
546 :
547 0 : err = gpgconf_read (engine, "--list-components", NULL,
548 : gpgconf_config_load_cb, &comp);
549 0 : if (err)
550 : {
551 0 : gpgconf_release (comp);
552 0 : return err;
553 : }
554 :
555 0 : cur_comp = comp;
556 0 : while (!err && cur_comp)
557 : {
558 0 : err = gpgconf_read (engine, "--list-options", cur_comp->name,
559 : gpgconf_config_load_cb2, cur_comp);
560 0 : cur_comp = cur_comp->next;
561 : }
562 :
563 0 : if (err)
564 : {
565 0 : gpgconf_release (comp);
566 0 : return err;
567 : }
568 :
569 0 : *comp_p = comp;
570 0 : return 0;
571 : }
572 :
573 :
574 :
575 : gpgme_error_t
576 0 : _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
577 : gpgme_conf_type_t type, const void *value)
578 : {
579 : gpgme_conf_arg_t arg;
580 :
581 0 : arg = calloc (1, sizeof (*arg));
582 0 : if (!arg)
583 0 : return gpg_error_from_syserror ();
584 :
585 0 : if (!value)
586 0 : arg->no_arg = 1;
587 : else
588 : {
589 : /* We need to switch on type here because the alt-type is not
590 : yet known. */
591 0 : switch (type)
592 : {
593 : case GPGME_CONF_NONE:
594 : case GPGME_CONF_UINT32:
595 0 : arg->value.uint32 = *((unsigned int *) value);
596 0 : break;
597 :
598 : case GPGME_CONF_INT32:
599 0 : arg->value.int32 = *((int *) value);
600 0 : break;
601 :
602 : case GPGME_CONF_STRING:
603 : case GPGME_CONF_FILENAME:
604 : case GPGME_CONF_LDAP_SERVER:
605 : case GPGME_CONF_KEY_FPR:
606 : case GPGME_CONF_PUB_KEY:
607 : case GPGME_CONF_SEC_KEY:
608 : case GPGME_CONF_ALIAS_LIST:
609 0 : arg->value.string = strdup (value);
610 0 : if (!arg->value.string)
611 : {
612 0 : free (arg);
613 0 : return gpg_error_from_syserror ();
614 : }
615 0 : break;
616 :
617 : default:
618 0 : free (arg);
619 0 : return gpg_error (GPG_ERR_INV_VALUE);
620 : }
621 : }
622 :
623 0 : *arg_p = arg;
624 0 : return 0;
625 : }
626 :
627 :
628 : void
629 0 : _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
630 : {
631 : /* Lacking the alt_type we need to switch on type here. */
632 0 : switch (type)
633 : {
634 : case GPGME_CONF_NONE:
635 : case GPGME_CONF_UINT32:
636 : case GPGME_CONF_INT32:
637 : case GPGME_CONF_STRING:
638 : default:
639 0 : break;
640 :
641 : case GPGME_CONF_FILENAME:
642 : case GPGME_CONF_LDAP_SERVER:
643 : case GPGME_CONF_KEY_FPR:
644 : case GPGME_CONF_PUB_KEY:
645 : case GPGME_CONF_SEC_KEY:
646 : case GPGME_CONF_ALIAS_LIST:
647 0 : type = GPGME_CONF_STRING;
648 0 : break;
649 : }
650 :
651 0 : release_arg (arg, type);
652 0 : }
653 :
654 :
655 : gpgme_error_t
656 0 : _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
657 : {
658 0 : if (reset)
659 : {
660 0 : if (opt->new_value)
661 0 : release_arg (opt->new_value, opt->alt_type);
662 0 : opt->new_value = NULL;
663 0 : opt->change_value = 0;
664 : }
665 : else
666 : {
667 : /* Support self-assignment, for example for adding an item to an
668 : existing list. */
669 0 : if (opt->new_value && arg != opt->new_value)
670 0 : release_arg (opt->new_value, opt->alt_type);
671 0 : opt->new_value = arg;
672 0 : opt->change_value = 1;
673 : }
674 0 : return 0;
675 : }
676 :
677 :
678 : /* FIXME: Major problem: We don't get errors from gpgconf. */
679 :
680 : static gpgme_error_t
681 0 : gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
682 : {
683 0 : struct engine_gpgconf *gpgconf = engine;
684 0 : gpgme_error_t err = 0;
685 : #define BUFLEN 1024
686 : char buf[BUFLEN];
687 0 : int buflen = 0;
688 0 : char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
689 : int rp[2];
690 0 : struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
691 : int status;
692 : int nwrite;
693 :
694 : /* FIXME: Deal with engine->home_dir. */
695 :
696 : /* _gpgme_engine_new guarantees that this is not NULL. */
697 0 : argv[0] = gpgconf->file_name;
698 :
699 0 : if (_gpgme_io_pipe (rp, 0) < 0)
700 0 : return gpg_error_from_syserror ();
701 :
702 0 : cfd[0].fd = rp[0];
703 :
704 0 : status = _gpgme_io_spawn (gpgconf->file_name, argv,
705 : IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
706 0 : if (status < 0)
707 : {
708 0 : _gpgme_io_close (rp[0]);
709 0 : _gpgme_io_close (rp[1]);
710 0 : return gpg_error_from_syserror ();
711 : }
712 :
713 : for (;;)
714 : {
715 0 : if (buflen == 0)
716 : {
717 : do
718 : {
719 0 : buflen = gpgme_data_read (conf, buf, BUFLEN);
720 : }
721 0 : while (buflen < 0 && errno == EAGAIN);
722 :
723 0 : if (buflen < 0)
724 : {
725 0 : err = gpg_error_from_syserror ();
726 0 : _gpgme_io_close (rp[1]);
727 0 : return err;
728 : }
729 0 : else if (buflen == 0)
730 : {
731 : /* All is written. */
732 0 : _gpgme_io_close (rp[1]);
733 0 : return 0;
734 : }
735 : }
736 :
737 : do
738 : {
739 0 : nwrite = _gpgme_io_write (rp[1], buf, buflen);
740 : }
741 0 : while (nwrite < 0 && errno == EAGAIN);
742 :
743 0 : if (nwrite > 0)
744 : {
745 0 : buflen -= nwrite;
746 0 : if (buflen > 0)
747 0 : memmove (&buf[0], &buf[nwrite], buflen);
748 : }
749 0 : else if (nwrite < 0)
750 : {
751 0 : _gpgme_io_close (rp[1]);
752 0 : return gpg_error_from_syserror ();
753 : }
754 0 : }
755 :
756 : return 0;
757 : }
758 :
759 :
760 : static gpgme_error_t
761 0 : arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
762 : {
763 0 : gpgme_error_t err = 0;
764 0 : int amt = 0;
765 : char buf[16];
766 :
767 0 : while (amt >= 0 && arg)
768 : {
769 0 : switch (option->alt_type)
770 : {
771 : case GPGME_CONF_NONE:
772 : case GPGME_CONF_UINT32:
773 : default:
774 0 : snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
775 0 : buf[sizeof (buf) - 1] = '\0';
776 0 : amt = gpgme_data_write (conf, buf, strlen (buf));
777 0 : break;
778 :
779 : case GPGME_CONF_INT32:
780 0 : snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
781 0 : buf[sizeof (buf) - 1] = '\0';
782 0 : amt = gpgme_data_write (conf, buf, strlen (buf));
783 0 : break;
784 :
785 :
786 : case GPGME_CONF_STRING:
787 : /* The complex types below are only here to silent the
788 : compiler warning. */
789 : case GPGME_CONF_FILENAME:
790 : case GPGME_CONF_LDAP_SERVER:
791 : case GPGME_CONF_KEY_FPR:
792 : case GPGME_CONF_PUB_KEY:
793 : case GPGME_CONF_SEC_KEY:
794 : case GPGME_CONF_ALIAS_LIST:
795 0 : if (arg->value.string)
796 : {
797 : /* One quote character, and three times to allow for
798 : percent escaping. */
799 0 : char *ptr = arg->value.string;
800 0 : amt = gpgme_data_write (conf, "\"", 1);
801 0 : if (amt < 0)
802 0 : break;
803 :
804 0 : while (!err && *ptr)
805 : {
806 0 : switch (*ptr)
807 : {
808 : case '%':
809 0 : amt = gpgme_data_write (conf, "%25", 3);
810 0 : break;
811 :
812 : case ':':
813 0 : amt = gpgme_data_write (conf, "%3a", 3);
814 0 : break;
815 :
816 : case ',':
817 0 : amt = gpgme_data_write (conf, "%2c", 3);
818 0 : break;
819 :
820 : default:
821 0 : amt = gpgme_data_write (conf, ptr, 1);
822 : }
823 0 : ptr++;
824 : }
825 : }
826 0 : break;
827 : }
828 :
829 0 : if (amt < 0)
830 0 : break;
831 :
832 0 : arg = arg->next;
833 : /* Comma separator. */
834 0 : if (arg)
835 0 : amt = gpgme_data_write (conf, ",", 1);
836 : }
837 :
838 0 : if (amt < 0)
839 0 : return gpg_error_from_syserror ();
840 :
841 0 : return 0;
842 : }
843 :
844 :
845 : static gpgme_error_t
846 0 : gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
847 : {
848 : gpgme_error_t err;
849 0 : int amt = 0;
850 : /* We use a data object to store the new configuration. */
851 : gpgme_data_t conf;
852 : gpgme_conf_opt_t option;
853 0 : int something_changed = 0;
854 :
855 0 : err = gpgme_data_new (&conf);
856 0 : if (err)
857 0 : return err;
858 :
859 0 : option = comp->options;
860 0 : while (!err && amt >= 0 && option)
861 : {
862 0 : if (option->change_value)
863 : {
864 0 : unsigned int flags = 0;
865 : char buf[16];
866 :
867 0 : something_changed = 1;
868 :
869 0 : amt = gpgme_data_write (conf, option->name, strlen (option->name));
870 0 : if (amt >= 0)
871 0 : amt = gpgme_data_write (conf, ":", 1);
872 0 : if (amt < 0)
873 0 : break;
874 :
875 0 : if (!option->new_value)
876 0 : flags |= GPGME_CONF_DEFAULT;
877 0 : snprintf (buf, sizeof (buf), "%u", flags);
878 0 : buf[sizeof (buf) - 1] = '\0';
879 :
880 0 : amt = gpgme_data_write (conf, buf, strlen (buf));
881 0 : if (amt >= 0)
882 0 : amt = gpgme_data_write (conf, ":", 1);
883 0 : if (amt < 0)
884 0 : break;
885 :
886 0 : if (option->new_value)
887 : {
888 0 : err = arg_to_data (conf, option, option->new_value);
889 0 : if (err)
890 0 : break;
891 : }
892 0 : amt = gpgme_data_write (conf, "\n", 1);
893 : }
894 0 : option = option->next;
895 : }
896 0 : if (!err && amt < 0)
897 0 : err = gpg_error_from_syserror ();
898 0 : if (err || !something_changed)
899 : goto bail;
900 :
901 0 : err = gpgme_data_seek (conf, 0, SEEK_SET);
902 0 : if (err)
903 0 : goto bail;
904 :
905 0 : err = gpgconf_write (engine, "--change-options", comp->name, conf);
906 : bail:
907 0 : gpgme_data_release (conf);
908 0 : return err;
909 : }
910 :
911 :
912 : static void
913 0 : gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
914 : {
915 : /* Nothing to do. */
916 0 : }
917 :
918 :
919 : /* Currently, we do not use the engine interface for the various
920 : operations. */
921 : void
922 0 : _gpgme_conf_release (gpgme_conf_comp_t conf)
923 : {
924 0 : gpgconf_config_release (conf);
925 0 : }
926 :
927 :
928 : struct engine_ops _gpgme_engine_ops_gpgconf =
929 : {
930 : /* Static functions. */
931 : _gpgme_get_default_gpgconf_name,
932 : NULL,
933 : gpgconf_get_version,
934 : gpgconf_get_req_version,
935 : gpgconf_new,
936 :
937 : /* Member functions. */
938 : gpgconf_release,
939 : NULL, /* reset */
940 : NULL, /* set_status_cb */
941 : NULL, /* set_status_handler */
942 : NULL, /* set_command_handler */
943 : NULL, /* set_colon_line_handler */
944 : NULL, /* set_locale */
945 : NULL, /* set_protocol */
946 : NULL, /* decrypt */
947 : NULL, /* decrypt_verify */
948 : NULL, /* delete */
949 : NULL, /* edit */
950 : NULL, /* encrypt */
951 : NULL, /* encrypt_sign */
952 : NULL, /* export */
953 : NULL, /* export_ext */
954 : NULL, /* genkey */
955 : NULL, /* import */
956 : NULL, /* keylist */
957 : NULL, /* keylist_ext */
958 : NULL, /* sign */
959 : NULL, /* trustlist */
960 : NULL, /* verify */
961 : NULL, /* getauditlog */
962 : NULL, /* opassuan_transact */
963 : gpgconf_conf_load,
964 : gpgconf_conf_save,
965 : gpgconf_set_io_cbs,
966 : NULL, /* io_event */
967 : NULL, /* cancel */
968 : NULL, /* cancel_op */
969 : NULL, /* passwd */
970 : NULL, /* set_pinentry_mode */
971 : NULL /* opspawn */
972 : };
|