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