Line data Source code
1 : /* engine-gpg.c - Gpg Engine.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
4 : 2009, 2010, 2012, 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 <https://www.gnu.org/licenses/>.
20 : */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 : #include <stdio.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #include <assert.h>
29 : #include <errno.h>
30 : #ifdef HAVE_UNISTD_H
31 : # include <unistd.h>
32 : #endif
33 : #ifdef HAVE_LOCALE_H
34 : #include <locale.h>
35 : #endif
36 :
37 : #include "gpgme.h"
38 : #include "util.h"
39 : #include "ops.h"
40 : #include "wait.h"
41 : #include "context.h" /*temp hack until we have GpmeData methods to do I/O */
42 : #include "priv-io.h"
43 : #include "sema.h"
44 : #include "debug.h"
45 : #include "data.h"
46 :
47 : #include "engine-backend.h"
48 :
49 :
50 : /* This type is used to build a list of gpg arguments and data
51 : sources/sinks. */
52 : struct arg_and_data_s
53 : {
54 : struct arg_and_data_s *next;
55 : gpgme_data_t data; /* If this is not NULL, use arg below. */
56 : int inbound; /* True if this is used for reading from gpg. */
57 : int dup_to;
58 : int print_fd; /* Print the fd number and not the special form of it. */
59 : int *arg_locp; /* Write back the argv idx of this argument when
60 : building command line to this location. */
61 : char arg[1]; /* Used if data above is not used. */
62 : };
63 :
64 :
65 : struct fd_data_map_s
66 : {
67 : gpgme_data_t data;
68 : int inbound; /* true if this is used for reading from gpg */
69 : int dup_to;
70 : int fd; /* the fd to use */
71 : int peer_fd; /* the other side of the pipe */
72 : int arg_loc; /* The index into the argv for translation purposes. */
73 : void *tag;
74 : };
75 :
76 :
77 : /* NB.: R_LINE is allocated an gpgrt function and thus gpgrt_free
78 : * shall be used to release it. This takes care of custom memory
79 : * allocators and avoids problems on Windows with different runtimes
80 : * used for libgpg-error/gpgrt and gpgme. */
81 : typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline);
82 :
83 : struct engine_gpg
84 : {
85 : char *file_name;
86 : char *version;
87 :
88 : char *lc_messages;
89 : char *lc_ctype;
90 :
91 : struct arg_and_data_s *arglist;
92 : struct arg_and_data_s **argtail;
93 :
94 : struct
95 : {
96 : int fd[2];
97 : int arg_loc;
98 : size_t bufsize;
99 : char *buffer;
100 : size_t readpos;
101 : int eof;
102 : engine_status_handler_t fnc;
103 : void *fnc_value;
104 : gpgme_status_cb_t mon_cb;
105 : void *mon_cb_value;
106 : void *tag;
107 : } status;
108 :
109 : /* This is a kludge - see the comment at colon_line_handler. */
110 : struct
111 : {
112 : int fd[2];
113 : int arg_loc;
114 : size_t bufsize;
115 : char *buffer;
116 : size_t readpos;
117 : int eof;
118 : engine_colon_line_handler_t fnc; /* this indicate use of this structrue */
119 : void *fnc_value;
120 : void *tag;
121 : colon_preprocessor_t preprocess_fnc;
122 : } colon;
123 :
124 : char **argv;
125 : struct fd_data_map_s *fd_data_map;
126 :
127 : /* stuff needed for interactive (command) mode */
128 : struct
129 : {
130 : int used;
131 : int fd;
132 : void *cb_data;
133 : int idx; /* Index in fd_data_map */
134 : gpgme_status_code_t code; /* last code */
135 : char *keyword; /* what has been requested (malloced) */
136 : engine_command_handler_t fnc;
137 : void *fnc_value;
138 : /* The kludges never end. This is used to couple command handlers
139 : with output data in edit key mode. */
140 : gpgme_data_t linked_data;
141 : int linked_idx;
142 : } cmd;
143 :
144 : struct gpgme_io_cbs io_cbs;
145 : gpgme_pinentry_mode_t pinentry_mode;
146 :
147 : /* NULL or the data object fed to --override_session_key-fd. */
148 : gpgme_data_t override_session_key;
149 : };
150 :
151 : typedef struct engine_gpg *engine_gpg_t;
152 :
153 :
154 : static void
155 2441 : gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
156 : {
157 2441 : engine_gpg_t gpg = engine;
158 :
159 2441 : TRACE3 (DEBUG_ENGINE, "gpgme:gpg_io_event", gpg,
160 : "event %p, type %d, type_data %p",
161 : gpg->io_cbs.event, type, type_data);
162 2441 : if (gpg->io_cbs.event)
163 2441 : (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
164 2441 : }
165 :
166 :
167 : static void
168 2992 : close_notify_handler (int fd, void *opaque)
169 : {
170 2992 : engine_gpg_t gpg = opaque;
171 2992 : assert (fd != -1);
172 :
173 2992 : if (gpg->status.fd[0] == fd)
174 : {
175 650 : if (gpg->status.tag)
176 650 : (*gpg->io_cbs.remove) (gpg->status.tag);
177 650 : gpg->status.fd[0] = -1;
178 : }
179 2342 : else if (gpg->status.fd[1] == fd)
180 648 : gpg->status.fd[1] = -1;
181 1694 : else if (gpg->colon.fd[0] == fd)
182 : {
183 268 : if (gpg->colon.tag)
184 268 : (*gpg->io_cbs.remove) (gpg->colon.tag);
185 268 : gpg->colon.fd[0] = -1;
186 : }
187 1426 : else if (gpg->colon.fd[1] == fd)
188 268 : gpg->colon.fd[1] = -1;
189 1158 : else if (gpg->cmd.fd == fd)
190 96 : gpg->cmd.fd = -1;
191 1062 : else if (gpg->fd_data_map)
192 : {
193 : int i;
194 :
195 1853 : for (i = 0; gpg->fd_data_map[i].data; i++)
196 : {
197 1853 : if (gpg->fd_data_map[i].fd == fd)
198 : {
199 482 : if (gpg->fd_data_map[i].tag)
200 482 : (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
201 482 : gpg->fd_data_map[i].fd = -1;
202 482 : break;
203 : }
204 1371 : if (gpg->fd_data_map[i].peer_fd == fd)
205 : {
206 580 : gpg->fd_data_map[i].peer_fd = -1;
207 580 : break;
208 : }
209 : }
210 : }
211 2992 : }
212 :
213 : /* If FRONT is true, push at the front of the list. Use this for
214 : options added late in the process. */
215 : static gpgme_error_t
216 12941 : _add_arg (engine_gpg_t gpg, const char *prefix, const char *arg, size_t arglen,
217 : int front, int *arg_locp)
218 : {
219 : struct arg_and_data_s *a;
220 12941 : size_t prefixlen = prefix? strlen (prefix) : 0;
221 :
222 12941 : assert (gpg);
223 12941 : assert (arg);
224 :
225 12941 : a = malloc (sizeof *a + prefixlen + arglen);
226 12941 : if (!a)
227 0 : return gpg_error_from_syserror ();
228 :
229 12941 : a->data = NULL;
230 12941 : a->dup_to = -1;
231 12941 : a->arg_locp = arg_locp;
232 :
233 12941 : if (prefixlen)
234 10 : memcpy (a->arg, prefix, prefixlen);
235 12941 : memcpy (a->arg + prefixlen, arg, arglen);
236 12941 : a->arg[prefixlen + arglen] = 0;
237 12941 : if (front)
238 : {
239 617 : a->next = gpg->arglist;
240 617 : if (!gpg->arglist)
241 : {
242 : /* If this is the first argument, we need to update the tail
243 : pointer. */
244 0 : gpg->argtail = &a->next;
245 : }
246 617 : gpg->arglist = a;
247 : }
248 : else
249 : {
250 12324 : a->next = NULL;
251 12324 : *gpg->argtail = a;
252 12324 : gpg->argtail = &a->next;
253 : }
254 :
255 12941 : return 0;
256 : }
257 :
258 :
259 : static gpgme_error_t
260 619 : add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
261 : {
262 619 : return _add_arg (gpg, NULL, arg, strlen (arg), front, NULL);
263 : }
264 :
265 : static gpgme_error_t
266 649 : add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
267 : {
268 649 : return _add_arg (gpg, NULL, arg, strlen (arg), 0, locp);
269 : }
270 :
271 : static gpgme_error_t
272 11653 : add_arg (engine_gpg_t gpg, const char *arg)
273 : {
274 11653 : return _add_arg (gpg, NULL, arg, strlen (arg), 0, NULL);
275 : }
276 :
277 : static gpgme_error_t
278 6 : add_arg_pfx (engine_gpg_t gpg, const char *prefix, const char *arg)
279 : {
280 6 : return _add_arg (gpg, prefix, arg, strlen (arg), 0, NULL);
281 : }
282 :
283 : static gpgme_error_t
284 4 : add_arg_len (engine_gpg_t gpg, const char *prefix,
285 : const char *arg, size_t arglen)
286 : {
287 4 : return _add_arg (gpg, prefix, arg, arglen, 0, NULL);
288 : }
289 :
290 :
291 : static gpgme_error_t
292 585 : add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
293 : {
294 : struct arg_and_data_s *a;
295 :
296 585 : assert (gpg);
297 585 : assert (data);
298 :
299 585 : a = malloc (sizeof *a - 1);
300 585 : if (!a)
301 0 : return gpg_error_from_syserror ();
302 585 : a->next = NULL;
303 585 : a->data = data;
304 585 : a->inbound = inbound;
305 585 : a->arg_locp = NULL;
306 :
307 585 : if (dup_to == -2)
308 : {
309 96 : a->print_fd = 1;
310 96 : a->dup_to = -1;
311 : }
312 : else
313 : {
314 489 : a->print_fd = 0;
315 489 : a->dup_to = dup_to;
316 : }
317 585 : *gpg->argtail = a;
318 585 : gpg->argtail = &a->next;
319 585 : return 0;
320 : }
321 :
322 :
323 : /* Return true if the engine's version is at least VERSION. */
324 : static int
325 1133 : have_gpg_version (engine_gpg_t gpg, const char *version)
326 : {
327 1133 : return _gpgme_compare_versions (gpg->version, version);
328 : }
329 :
330 :
331 :
332 : static char *
333 377 : gpg_get_version (const char *file_name)
334 : {
335 377 : return _gpgme_get_program_version (file_name ? file_name
336 : : _gpgme_get_default_gpg_name ());
337 : }
338 :
339 :
340 : static const char *
341 90 : gpg_get_req_version (void)
342 : {
343 90 : return "1.4.0";
344 : }
345 :
346 :
347 : static void
348 644 : free_argv (char **argv)
349 : {
350 : int i;
351 :
352 15952 : for (i = 0; argv[i]; i++)
353 15308 : free (argv[i]);
354 644 : free (argv);
355 644 : }
356 :
357 :
358 : static void
359 650 : free_fd_data_map (struct fd_data_map_s *fd_data_map)
360 : {
361 : int i;
362 :
363 650 : if (!fd_data_map)
364 0 : return;
365 :
366 1235 : for (i = 0; fd_data_map[i].data; i++)
367 : {
368 585 : if (fd_data_map[i].fd != -1)
369 23 : _gpgme_io_close (fd_data_map[i].fd);
370 585 : if (fd_data_map[i].peer_fd != -1)
371 0 : _gpgme_io_close (fd_data_map[i].peer_fd);
372 : /* Don't release data because this is only a reference. */
373 : }
374 650 : free (fd_data_map);
375 : }
376 :
377 :
378 : static gpgme_error_t
379 672 : gpg_cancel (void *engine)
380 : {
381 672 : engine_gpg_t gpg = engine;
382 :
383 672 : if (!gpg)
384 0 : return gpg_error (GPG_ERR_INV_VALUE);
385 :
386 : /* If gpg may be waiting for a cmd, close the cmd fd first. On
387 : Windows, close operations block on the reader/writer thread. */
388 672 : if (gpg->cmd.used)
389 : {
390 100 : if (gpg->cmd.fd != -1)
391 96 : _gpgme_io_close (gpg->cmd.fd);
392 4 : else if (gpg->fd_data_map
393 0 : && gpg->fd_data_map[gpg->cmd.idx].fd != -1)
394 0 : _gpgme_io_close (gpg->fd_data_map[gpg->cmd.idx].fd);
395 : }
396 :
397 672 : if (gpg->status.fd[0] != -1)
398 30 : _gpgme_io_close (gpg->status.fd[0]);
399 672 : if (gpg->status.fd[1] != -1)
400 0 : _gpgme_io_close (gpg->status.fd[1]);
401 672 : if (gpg->colon.fd[0] != -1)
402 6 : _gpgme_io_close (gpg->colon.fd[0]);
403 672 : if (gpg->colon.fd[1] != -1)
404 0 : _gpgme_io_close (gpg->colon.fd[1]);
405 672 : if (gpg->fd_data_map)
406 : {
407 650 : free_fd_data_map (gpg->fd_data_map);
408 650 : gpg->fd_data_map = NULL;
409 : }
410 :
411 672 : return 0;
412 : }
413 :
414 : static void
415 644 : gpg_release (void *engine)
416 : {
417 644 : engine_gpg_t gpg = engine;
418 :
419 644 : if (!gpg)
420 0 : return;
421 :
422 644 : gpg_cancel (engine);
423 :
424 644 : if (gpg->file_name)
425 644 : free (gpg->file_name);
426 644 : if (gpg->version)
427 644 : free (gpg->version);
428 :
429 644 : if (gpg->lc_messages)
430 156 : free (gpg->lc_messages);
431 644 : if (gpg->lc_ctype)
432 156 : free (gpg->lc_ctype);
433 :
434 14688 : while (gpg->arglist)
435 : {
436 13400 : struct arg_and_data_s *next = gpg->arglist->next;
437 :
438 13400 : free (gpg->arglist);
439 13400 : gpg->arglist = next;
440 : }
441 :
442 644 : if (gpg->status.buffer)
443 644 : free (gpg->status.buffer);
444 644 : if (gpg->colon.buffer)
445 268 : free (gpg->colon.buffer);
446 644 : if (gpg->argv)
447 644 : free_argv (gpg->argv);
448 644 : if (gpg->cmd.keyword)
449 40 : free (gpg->cmd.keyword);
450 :
451 644 : gpgme_data_release (gpg->override_session_key);
452 :
453 644 : free (gpg);
454 : }
455 :
456 :
457 : static gpgme_error_t
458 651 : gpg_new (void **engine, const char *file_name, const char *home_dir,
459 : const char *version)
460 : {
461 : engine_gpg_t gpg;
462 651 : gpgme_error_t rc = 0;
463 651 : char *dft_display = NULL;
464 : char dft_ttyname[64];
465 651 : char *dft_ttytype = NULL;
466 651 : char *env_tty = NULL;
467 :
468 651 : gpg = calloc (1, sizeof *gpg);
469 651 : if (!gpg)
470 0 : return gpg_error_from_syserror ();
471 :
472 651 : if (file_name)
473 : {
474 650 : gpg->file_name = strdup (file_name);
475 650 : if (!gpg->file_name)
476 : {
477 0 : rc = gpg_error_from_syserror ();
478 0 : goto leave;
479 : }
480 : }
481 :
482 651 : if (version)
483 : {
484 651 : gpg->version = strdup (version);
485 651 : if (!gpg->version)
486 : {
487 0 : rc = gpg_error_from_syserror ();
488 0 : goto leave;
489 : }
490 : }
491 :
492 651 : gpg->argtail = &gpg->arglist;
493 651 : gpg->status.fd[0] = -1;
494 651 : gpg->status.fd[1] = -1;
495 651 : gpg->colon.fd[0] = -1;
496 651 : gpg->colon.fd[1] = -1;
497 651 : gpg->cmd.fd = -1;
498 651 : gpg->cmd.idx = -1;
499 651 : gpg->cmd.linked_data = NULL;
500 651 : gpg->cmd.linked_idx = -1;
501 :
502 : /* Allocate the read buffer for the status pipe. */
503 651 : gpg->status.bufsize = 1024;
504 651 : gpg->status.readpos = 0;
505 651 : gpg->status.buffer = malloc (gpg->status.bufsize);
506 651 : if (!gpg->status.buffer)
507 : {
508 0 : rc = gpg_error_from_syserror ();
509 0 : goto leave;
510 : }
511 : /* In any case we need a status pipe - create it right here and
512 : don't handle it with our generic gpgme_data_t mechanism. */
513 651 : if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
514 : {
515 0 : rc = gpg_error_from_syserror ();
516 0 : goto leave;
517 : }
518 651 : if (_gpgme_io_set_close_notify (gpg->status.fd[0],
519 : close_notify_handler, gpg)
520 651 : || _gpgme_io_set_close_notify (gpg->status.fd[1],
521 : close_notify_handler, gpg))
522 : {
523 0 : rc = gpg_error (GPG_ERR_GENERAL);
524 0 : goto leave;
525 : }
526 651 : gpg->status.eof = 0;
527 :
528 651 : if (home_dir)
529 : {
530 224 : rc = add_arg (gpg, "--homedir");
531 224 : if (!rc)
532 224 : rc = add_arg (gpg, home_dir);
533 224 : if (rc)
534 0 : goto leave;
535 : }
536 :
537 651 : rc = add_arg (gpg, "--status-fd");
538 651 : if (rc)
539 0 : goto leave;
540 :
541 : {
542 : char buf[25];
543 651 : _gpgme_io_fd2str (buf, sizeof (buf), gpg->status.fd[1]);
544 649 : rc = add_arg_with_locp (gpg, buf, &gpg->status.arg_loc);
545 650 : if (rc)
546 0 : goto leave;
547 : }
548 :
549 650 : rc = add_arg (gpg, "--no-tty");
550 650 : if (!rc)
551 650 : rc = add_arg (gpg, "--charset");
552 651 : if (!rc)
553 651 : rc = add_arg (gpg, "utf8");
554 651 : if (!rc)
555 651 : rc = add_arg (gpg, "--enable-progress-filter");
556 651 : if (!rc && have_gpg_version (gpg, "2.1.11"))
557 649 : rc = add_arg (gpg, "--exit-on-status-write-error");
558 651 : if (rc)
559 0 : goto leave;
560 :
561 651 : rc = _gpgme_getenv ("DISPLAY", &dft_display);
562 650 : if (rc)
563 0 : goto leave;
564 650 : if (dft_display)
565 : {
566 650 : rc = add_arg (gpg, "--display");
567 651 : if (!rc)
568 651 : rc = add_arg (gpg, dft_display);
569 :
570 651 : free (dft_display);
571 651 : if (rc)
572 0 : goto leave;
573 : }
574 :
575 651 : rc = _gpgme_getenv ("GPG_TTY", &env_tty);
576 651 : if (isatty (1) || env_tty || rc)
577 : {
578 650 : int err = 0;
579 :
580 650 : if (rc)
581 0 : goto leave;
582 650 : else if (env_tty)
583 : {
584 0 : snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
585 0 : free (env_tty);
586 : }
587 : else
588 650 : err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
589 :
590 : /* Even though isatty() returns 1, ttyname_r() may fail in many
591 : ways, e.g., when /dev/pts is not accessible under chroot. */
592 651 : if (!err)
593 : {
594 651 : if (*dft_ttyname)
595 : {
596 651 : rc = add_arg (gpg, "--ttyname");
597 651 : if (!rc)
598 651 : rc = add_arg (gpg, dft_ttyname);
599 : }
600 : else
601 0 : rc = 0;
602 651 : if (!rc)
603 : {
604 651 : rc = _gpgme_getenv ("TERM", &dft_ttytype);
605 651 : if (rc)
606 0 : goto leave;
607 :
608 651 : if (dft_ttytype)
609 : {
610 651 : rc = add_arg (gpg, "--ttytype");
611 651 : if (!rc)
612 651 : rc = add_arg (gpg, dft_ttytype);
613 : }
614 :
615 651 : free (dft_ttytype);
616 : }
617 651 : if (rc)
618 0 : goto leave;
619 : }
620 : }
621 :
622 : leave:
623 651 : if (rc)
624 0 : gpg_release (gpg);
625 : else
626 651 : *engine = gpg;
627 651 : return rc;
628 : }
629 :
630 :
631 : static gpgme_error_t
632 1302 : gpg_set_locale (void *engine, int category, const char *value)
633 : {
634 1302 : engine_gpg_t gpg = engine;
635 :
636 : if (0)
637 : ;
638 : #ifdef LC_CTYPE
639 1302 : else if (category == LC_CTYPE)
640 : {
641 651 : if (gpg->lc_ctype)
642 : {
643 0 : free (gpg->lc_ctype);
644 0 : gpg->lc_ctype = NULL;
645 : }
646 651 : if (value)
647 : {
648 152 : gpg->lc_ctype = strdup (value);
649 152 : if (!gpg->lc_ctype)
650 0 : return gpg_error_from_syserror ();
651 : }
652 : }
653 : #endif
654 : #ifdef LC_MESSAGES
655 651 : else if (category == LC_MESSAGES)
656 : {
657 651 : if (gpg->lc_messages)
658 : {
659 0 : free (gpg->lc_messages);
660 0 : gpg->lc_messages = NULL;
661 : }
662 651 : if (value)
663 : {
664 155 : gpg->lc_messages = strdup (value);
665 155 : if (!gpg->lc_messages)
666 0 : return gpg_error_from_syserror ();
667 : }
668 : }
669 : #endif /* LC_MESSAGES */
670 : else
671 0 : return gpg_error (GPG_ERR_INV_VALUE);
672 :
673 1302 : return 0;
674 : }
675 :
676 : /* This sets a status callback for monitoring status lines before they
677 : * are passed to a caller set handler. */
678 : static void
679 4 : gpg_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
680 : {
681 4 : engine_gpg_t gpg = engine;
682 :
683 4 : gpg->status.mon_cb = cb;
684 4 : gpg->status.mon_cb_value = cb_value;
685 4 : }
686 :
687 :
688 : /* Note, that the status_handler is allowed to modifiy the args
689 : value. */
690 : static void
691 674 : gpg_set_status_handler (void *engine, engine_status_handler_t fnc,
692 : void *fnc_value)
693 : {
694 674 : engine_gpg_t gpg = engine;
695 :
696 674 : gpg->status.fnc = fnc;
697 674 : gpg->status.fnc_value = fnc_value;
698 674 : }
699 :
700 : /* Kludge to process --with-colon output. */
701 : static gpgme_error_t
702 268 : gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
703 : void *fnc_value)
704 : {
705 268 : engine_gpg_t gpg = engine;
706 :
707 268 : gpg->colon.bufsize = 1024;
708 268 : gpg->colon.readpos = 0;
709 268 : gpg->colon.buffer = malloc (gpg->colon.bufsize);
710 268 : if (!gpg->colon.buffer)
711 0 : return gpg_error_from_syserror ();
712 :
713 268 : if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1)
714 : {
715 0 : int saved_err = gpg_error_from_syserror ();
716 0 : free (gpg->colon.buffer);
717 0 : gpg->colon.buffer = NULL;
718 0 : return saved_err;
719 : }
720 268 : if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
721 268 : || _gpgme_io_set_close_notify (gpg->colon.fd[1],
722 : close_notify_handler, gpg))
723 0 : return gpg_error (GPG_ERR_GENERAL);
724 268 : gpg->colon.eof = 0;
725 268 : gpg->colon.fnc = fnc;
726 268 : gpg->colon.fnc_value = fnc_value;
727 268 : return 0;
728 : }
729 :
730 :
731 : static gpgme_error_t
732 83 : command_handler (void *opaque, int fd)
733 : {
734 83 : struct io_cb_data *data = (struct io_cb_data *) opaque;
735 83 : engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
736 : gpgme_error_t err;
737 83 : int processed = 0;
738 83 : assert (gpg->cmd.used);
739 83 : assert (gpg->cmd.code);
740 83 : assert (gpg->cmd.fnc);
741 :
742 83 : err = gpg->cmd.fnc (gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword, fd,
743 : &processed);
744 :
745 83 : gpg->cmd.code = 0;
746 : /* And sleep again until read_status will wake us up again. */
747 : /* XXX We must check if there are any more fds active after removing
748 : this one. */
749 83 : (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
750 83 : gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
751 83 : gpg->fd_data_map[gpg->cmd.idx].fd = -1;
752 :
753 83 : if (err)
754 6 : return err;
755 :
756 : /* We always need to send at least a newline character. */
757 77 : if (!processed)
758 0 : _gpgme_io_write (fd, "\n", 1);
759 :
760 77 : return 0;
761 : }
762 :
763 :
764 :
765 : /* The Fnc will be called to get a value for one of the commands with
766 : a key KEY. If the Code passed to FNC is 0, the function may release
767 : resources associated with the returned value from another call. To
768 : match such a second call to a first call, the returned value from
769 : the first call is passed as keyword. */
770 : static gpgme_error_t
771 96 : gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
772 : void *fnc_value, gpgme_data_t linked_data)
773 : {
774 96 : engine_gpg_t gpg = engine;
775 : gpgme_error_t rc;
776 :
777 96 : rc = add_arg (gpg, "--command-fd");
778 96 : if (rc)
779 0 : return rc;
780 :
781 : /* This is a hack. We don't have a real data object. The only
782 : thing that matters is that we use something unique, so we use the
783 : address of the cmd structure in the gpg object. */
784 96 : rc = add_data (gpg, (void *) &gpg->cmd, -2, 0);
785 96 : if (rc)
786 0 : return rc;
787 :
788 96 : gpg->cmd.fnc = fnc;
789 96 : gpg->cmd.cb_data = (void *) &gpg->cmd;
790 96 : gpg->cmd.fnc_value = fnc_value;
791 96 : gpg->cmd.linked_data = linked_data;
792 96 : gpg->cmd.used = 1;
793 96 : return 0;
794 : }
795 :
796 :
797 : static gpgme_error_t
798 651 : build_argv (engine_gpg_t gpg, const char *pgmname)
799 : {
800 : gpgme_error_t err;
801 : struct arg_and_data_s *a;
802 : struct fd_data_map_s *fd_data_map;
803 651 : size_t datac=0, argc=0;
804 : char **argv;
805 651 : int need_special = 0;
806 651 : int use_agent = 0;
807 : char *p;
808 :
809 651 : if (_gpgme_in_gpg_one_mode ())
810 : {
811 : /* In GnuPG-1 mode we don't want to use the agent with a
812 : malformed environment variable. This is only a very basic
813 : test but sufficient to make our life in the regression tests
814 : easier. With GnuPG-2 the agent is anyway required and on
815 : modern installations GPG_AGENT_INFO is optional. */
816 0 : err = _gpgme_getenv ("GPG_AGENT_INFO", &p);
817 0 : if (err)
818 0 : return err;
819 0 : use_agent = (p && strchr (p, ':'));
820 0 : if (p)
821 0 : free (p);
822 : }
823 :
824 651 : if (gpg->argv)
825 : {
826 0 : free_argv (gpg->argv);
827 0 : gpg->argv = NULL;
828 : }
829 651 : if (gpg->fd_data_map)
830 : {
831 0 : free_fd_data_map (gpg->fd_data_map);
832 0 : gpg->fd_data_map = NULL;
833 : }
834 :
835 651 : argc++; /* For argv[0]. */
836 14184 : for (a = gpg->arglist; a; a = a->next)
837 : {
838 13533 : argc++;
839 13533 : if (a->data)
840 : {
841 : /*fprintf (stderr, "build_argv: data\n" );*/
842 585 : datac++;
843 585 : if (a->dup_to == -1 && !a->print_fd)
844 266 : need_special = 1;
845 : }
846 : else
847 : {
848 : /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
849 : }
850 : }
851 651 : if (need_special)
852 242 : argc++;
853 651 : if (use_agent)
854 0 : argc++;
855 651 : if (gpg->pinentry_mode)
856 52 : argc++;
857 651 : if (!gpg->cmd.used)
858 555 : argc++; /* --batch */
859 651 : argc += 1; /* --no-sk-comments */
860 :
861 651 : argv = calloc (argc + 1, sizeof *argv);
862 651 : if (!argv)
863 0 : return gpg_error_from_syserror ();
864 651 : fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
865 651 : if (!fd_data_map)
866 : {
867 0 : int saved_err = gpg_error_from_syserror ();
868 0 : free_argv (argv);
869 0 : return saved_err;
870 : }
871 :
872 651 : argc = datac = 0;
873 651 : argv[argc] = strdup (_gpgme_get_basename (pgmname)); /* argv[0] */
874 651 : if (!argv[argc])
875 : {
876 0 : int saved_err = gpg_error_from_syserror ();
877 0 : free (fd_data_map);
878 0 : free_argv (argv);
879 0 : return saved_err;
880 : }
881 651 : argc++;
882 651 : if (need_special)
883 : {
884 242 : argv[argc] = strdup ("--enable-special-filenames");
885 242 : if (!argv[argc])
886 : {
887 0 : int saved_err = gpg_error_from_syserror ();
888 0 : free (fd_data_map);
889 0 : free_argv (argv);
890 0 : return saved_err;
891 : }
892 242 : argc++;
893 : }
894 651 : if (use_agent)
895 : {
896 0 : argv[argc] = strdup ("--use-agent");
897 0 : if (!argv[argc])
898 : {
899 0 : int saved_err = gpg_error_from_syserror ();
900 0 : free (fd_data_map);
901 0 : free_argv (argv);
902 0 : return saved_err;
903 : }
904 0 : argc++;
905 : }
906 :
907 651 : if (gpg->pinentry_mode && have_gpg_version (gpg, "2.1.0"))
908 : {
909 52 : const char *s = NULL;
910 52 : switch (gpg->pinentry_mode)
911 : {
912 0 : case GPGME_PINENTRY_MODE_DEFAULT: break;
913 0 : case GPGME_PINENTRY_MODE_ASK: s = "--pinentry-mode=ask"; break;
914 0 : case GPGME_PINENTRY_MODE_CANCEL: s = "--pinentry-mode=cancel"; break;
915 0 : case GPGME_PINENTRY_MODE_ERROR: s = "--pinentry-mode=error"; break;
916 52 : case GPGME_PINENTRY_MODE_LOOPBACK:s = "--pinentry-mode=loopback"; break;
917 : }
918 52 : if (s)
919 : {
920 52 : argv[argc] = strdup (s);
921 52 : if (!argv[argc])
922 : {
923 0 : int saved_err = gpg_error_from_syserror ();
924 0 : free (fd_data_map);
925 0 : free_argv (argv);
926 0 : return saved_err;
927 : }
928 52 : argc++;
929 : }
930 : }
931 :
932 651 : if (!gpg->cmd.used)
933 : {
934 555 : argv[argc] = strdup ("--batch");
935 555 : if (!argv[argc])
936 : {
937 0 : int saved_err = gpg_error_from_syserror ();
938 0 : free (fd_data_map);
939 0 : free_argv (argv);
940 0 : return saved_err;
941 : }
942 555 : argc++;
943 : }
944 651 : argv[argc] = strdup ("--no-sk-comments");
945 651 : if (!argv[argc])
946 : {
947 0 : int saved_err = gpg_error_from_syserror ();
948 0 : free (fd_data_map);
949 0 : free_argv (argv);
950 0 : return saved_err;
951 : }
952 651 : argc++;
953 14162 : for (a = gpg->arglist; a; a = a->next)
954 : {
955 13511 : if (a->arg_locp)
956 651 : *(a->arg_locp) = argc;
957 :
958 13511 : if (a->data)
959 : {
960 : /* Create a pipe to pass it down to gpg. */
961 579 : fd_data_map[datac].inbound = a->inbound;
962 :
963 : /* Create a pipe. */
964 : {
965 : int fds[2];
966 :
967 579 : if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
968 : == -1)
969 : {
970 0 : int saved_errno = errno;
971 0 : free (fd_data_map);
972 0 : free_argv (argv);
973 0 : return gpg_error (saved_errno);
974 : }
975 585 : if (_gpgme_io_set_close_notify (fds[0],
976 : close_notify_handler, gpg)
977 585 : || _gpgme_io_set_close_notify (fds[1],
978 : close_notify_handler,
979 : gpg))
980 : {
981 : /* We leak fd_data_map and the fds. This is not easy
982 : to avoid and given that we reach this here only
983 : after a malloc failure for a small object, it is
984 : probably better not to do anything. */
985 6 : return gpg_error (GPG_ERR_GENERAL);
986 : }
987 : /* If the data_type is FD, we have to do a dup2 here. */
988 579 : if (fd_data_map[datac].inbound)
989 : {
990 217 : fd_data_map[datac].fd = fds[0];
991 217 : fd_data_map[datac].peer_fd = fds[1];
992 : }
993 : else
994 : {
995 362 : fd_data_map[datac].fd = fds[1];
996 362 : fd_data_map[datac].peer_fd = fds[0];
997 : }
998 : }
999 :
1000 : /* Hack to get hands on the fd later. */
1001 579 : if (gpg->cmd.used)
1002 : {
1003 265 : if (gpg->cmd.cb_data == a->data)
1004 : {
1005 96 : assert (gpg->cmd.idx == -1);
1006 96 : gpg->cmd.idx = datac;
1007 : }
1008 169 : else if (gpg->cmd.linked_data == a->data)
1009 : {
1010 13 : assert (gpg->cmd.linked_idx == -1);
1011 13 : gpg->cmd.linked_idx = datac;
1012 : }
1013 : }
1014 :
1015 579 : fd_data_map[datac].data = a->data;
1016 579 : fd_data_map[datac].dup_to = a->dup_to;
1017 :
1018 579 : if (a->dup_to == -1)
1019 : {
1020 : char *ptr;
1021 362 : int buflen = 25;
1022 :
1023 362 : argv[argc] = malloc (buflen);
1024 362 : if (!argv[argc])
1025 : {
1026 0 : int saved_err = gpg_error_from_syserror ();
1027 0 : free (fd_data_map);
1028 0 : free_argv (argv);
1029 0 : return saved_err;
1030 : }
1031 :
1032 362 : ptr = argv[argc];
1033 362 : if (!a->print_fd)
1034 : {
1035 266 : *(ptr++) = '-';
1036 266 : *(ptr++) = '&';
1037 266 : buflen -= 2;
1038 : }
1039 :
1040 362 : _gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd);
1041 362 : fd_data_map[datac].arg_loc = argc;
1042 362 : argc++;
1043 : }
1044 579 : datac++;
1045 : }
1046 : else
1047 : {
1048 12932 : argv[argc] = strdup (a->arg);
1049 12932 : if (!argv[argc])
1050 : {
1051 0 : int saved_err = gpg_error_from_syserror ();
1052 0 : free (fd_data_map);
1053 0 : free_argv (argv);
1054 0 : return saved_err;
1055 : }
1056 12932 : argc++;
1057 : }
1058 : }
1059 :
1060 651 : gpg->argv = argv;
1061 651 : gpg->fd_data_map = fd_data_map;
1062 651 : return 0;
1063 : }
1064 :
1065 :
1066 : static gpgme_error_t
1067 1482 : add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
1068 : void **tag)
1069 : {
1070 : gpgme_error_t err;
1071 :
1072 1482 : err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
1073 1482 : if (err)
1074 0 : return err;
1075 1482 : if (!dir)
1076 : /* FIXME Kludge around poll() problem. */
1077 342 : err = _gpgme_io_set_nonblocking (fd);
1078 1482 : return err;
1079 : }
1080 :
1081 :
1082 : /* Handle the status output of GnuPG. This function does read entire
1083 : lines and passes them as C strings to the callback function (we can
1084 : use C Strings because the status output is always UTF-8 encoded).
1085 : Of course we have to buffer the lines to cope with long lines
1086 : e.g. with a large user ID. Note: We can optimize this to only cope
1087 : with status line code we know about and skip all other stuff
1088 : without buffering (i.e. without extending the buffer). */
1089 : static gpgme_error_t
1090 4219 : read_status (engine_gpg_t gpg)
1091 : {
1092 : char *p;
1093 : int nread;
1094 4219 : size_t bufsize = gpg->status.bufsize;
1095 4219 : char *buffer = gpg->status.buffer;
1096 4219 : size_t readpos = gpg->status.readpos;
1097 : gpgme_error_t err;
1098 :
1099 4219 : assert (buffer);
1100 4219 : if (bufsize - readpos < 256)
1101 : {
1102 : /* Need more room for the read. */
1103 0 : bufsize += 1024;
1104 0 : buffer = realloc (buffer, bufsize);
1105 0 : if (!buffer)
1106 0 : return gpg_error_from_syserror ();
1107 : }
1108 :
1109 8438 : nread = _gpgme_io_read (gpg->status.fd[0],
1110 4219 : buffer + readpos, bufsize-readpos);
1111 4217 : if (nread == -1)
1112 0 : return gpg_error_from_syserror ();
1113 :
1114 4217 : if (!nread)
1115 : {
1116 630 : err = 0;
1117 630 : gpg->status.eof = 1;
1118 630 : if (gpg->status.mon_cb)
1119 2 : err = gpg->status.mon_cb (gpg->status.mon_cb_value, "", "");
1120 630 : if (gpg->status.fnc)
1121 : {
1122 630 : char emptystring[1] = {0};
1123 630 : err = gpg->status.fnc (gpg->status.fnc_value,
1124 : GPGME_STATUS_EOF, emptystring);
1125 630 : if (gpg_err_code (err) == GPG_ERR_FALSE)
1126 0 : err = 0; /* Drop special error code. */
1127 : }
1128 :
1129 630 : return err;
1130 : }
1131 :
1132 12006 : while (nread > 0)
1133 : {
1134 214995 : for (p = buffer + readpos; nread; nread--, p++)
1135 : {
1136 214993 : if (*p == '\n')
1137 : {
1138 : /* (we require that the last line is terminated by a LF) */
1139 4840 : if (p > buffer && p[-1] == '\r')
1140 0 : p[-1] = 0;
1141 4840 : *p = 0;
1142 4840 : if (!strncmp (buffer, "[GNUPG:] ", 9)
1143 4842 : && buffer[9] >= 'A' && buffer[9] <= 'Z')
1144 : {
1145 : char *rest;
1146 : gpgme_status_code_t r;
1147 :
1148 4840 : rest = strchr (buffer + 9, ' ');
1149 4840 : if (!rest)
1150 395 : rest = p; /* Set to an empty string. */
1151 : else
1152 4445 : *rest++ = 0;
1153 :
1154 4840 : r = _gpgme_parse_status (buffer + 9);
1155 4842 : if (gpg->status.mon_cb && r != GPGME_STATUS_PROGRESS)
1156 : {
1157 : /* Note that we call the monitor even if we do
1158 : * not know the status code (r < 0). */
1159 20 : err = gpg->status.mon_cb (gpg->status.mon_cb_value,
1160 10 : buffer + 9, rest);
1161 10 : if (err)
1162 2 : return err;
1163 : }
1164 : if (r >= 0)
1165 : {
1166 4840 : if (gpg->cmd.used
1167 1091 : && (r == GPGME_STATUS_GET_BOOL
1168 1083 : || r == GPGME_STATUS_GET_LINE
1169 1039 : || r == GPGME_STATUS_GET_HIDDEN))
1170 : {
1171 83 : gpg->cmd.code = r;
1172 83 : if (gpg->cmd.keyword)
1173 41 : free (gpg->cmd.keyword);
1174 83 : gpg->cmd.keyword = strdup (rest);
1175 83 : if (!gpg->cmd.keyword)
1176 0 : return gpg_error_from_syserror ();
1177 : /* This should be the last thing we have
1178 : received and the next thing will be that
1179 : the command handler does its action. */
1180 83 : if (nread > 1)
1181 0 : TRACE0 (DEBUG_CTX, "gpgme:read_status", 0,
1182 : "error: unexpected data");
1183 :
1184 83 : add_io_cb (gpg, gpg->cmd.fd, 0,
1185 : command_handler, gpg,
1186 83 : &gpg->fd_data_map[gpg->cmd.idx].tag);
1187 83 : gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
1188 83 : gpg->cmd.fd = -1;
1189 : }
1190 4757 : else if (gpg->status.fnc)
1191 : {
1192 4757 : err = gpg->status.fnc (gpg->status.fnc_value,
1193 : r, rest);
1194 4757 : if (gpg_err_code (err) == GPG_ERR_FALSE)
1195 0 : err = 0; /* Drop special error code. */
1196 4757 : if (err)
1197 10 : return err;
1198 : }
1199 :
1200 4830 : if (r == GPGME_STATUS_END_STREAM)
1201 : {
1202 0 : if (gpg->cmd.used)
1203 : {
1204 : /* Before we can actually add the
1205 : command fd, we might have to flush
1206 : the linked output data pipe. */
1207 0 : if (gpg->cmd.linked_idx != -1
1208 0 : && gpg->fd_data_map[gpg->cmd.linked_idx].fd
1209 : != -1)
1210 : {
1211 : struct io_select_fd_s fds;
1212 0 : fds.fd =
1213 0 : gpg->fd_data_map[gpg->cmd.linked_idx].fd;
1214 0 : fds.for_read = 1;
1215 0 : fds.for_write = 0;
1216 0 : fds.opaque = NULL;
1217 : do
1218 : {
1219 0 : fds.signaled = 0;
1220 0 : _gpgme_io_select (&fds, 1, 1);
1221 0 : if (fds.signaled)
1222 0 : _gpgme_data_inbound_handler
1223 0 : (gpg->cmd.linked_data, fds.fd);
1224 : }
1225 0 : while (fds.signaled);
1226 : }
1227 :
1228 : /* XXX We must check if there are any
1229 : more fds active after removing this
1230 : one. */
1231 0 : (*gpg->io_cbs.remove)
1232 0 : (gpg->fd_data_map[gpg->cmd.idx].tag);
1233 0 : gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
1234 0 : gpg->fd_data_map[gpg->cmd.idx].fd = -1;
1235 : }
1236 : }
1237 : }
1238 : }
1239 : /* To reuse the buffer for the next line we have to
1240 : shift the remaining data to the buffer start and
1241 : restart the loop Hmmm: We can optimize this function
1242 : by looking forward in the buffer to see whether a
1243 : second complete line is available and in this case
1244 : avoid the memmove for this line. */
1245 4830 : nread--; p++;
1246 4830 : if (nread)
1247 1253 : memmove (buffer, p, nread);
1248 4830 : readpos = 0;
1249 4830 : break; /* the for loop */
1250 : }
1251 : else
1252 210153 : readpos++;
1253 : }
1254 : }
1255 :
1256 : /* Update the gpg object. */
1257 3577 : gpg->status.bufsize = bufsize;
1258 3577 : gpg->status.buffer = buffer;
1259 3577 : gpg->status.readpos = readpos;
1260 3577 : return 0;
1261 : }
1262 :
1263 :
1264 : static gpgme_error_t
1265 4219 : status_handler (void *opaque, int fd)
1266 : {
1267 4219 : struct io_cb_data *data = (struct io_cb_data *) opaque;
1268 4219 : engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
1269 : int err;
1270 :
1271 4219 : assert (fd == gpg->status.fd[0]);
1272 4219 : err = read_status (gpg);
1273 4219 : if (err)
1274 22 : return err;
1275 4197 : if (gpg->status.eof)
1276 620 : _gpgme_io_close (fd);
1277 4197 : return 0;
1278 : }
1279 :
1280 :
1281 : static gpgme_error_t
1282 774 : read_colon_line (engine_gpg_t gpg)
1283 : {
1284 : char *p;
1285 : int nread;
1286 774 : size_t bufsize = gpg->colon.bufsize;
1287 774 : char *buffer = gpg->colon.buffer;
1288 774 : size_t readpos = gpg->colon.readpos;
1289 :
1290 774 : assert (buffer);
1291 774 : if (bufsize - readpos < 256)
1292 : {
1293 : /* Need more room for the read. */
1294 0 : bufsize += 1024;
1295 0 : buffer = realloc (buffer, bufsize);
1296 0 : if (!buffer)
1297 0 : return gpg_error_from_syserror ();
1298 : }
1299 :
1300 774 : nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
1301 761 : if (nread == -1)
1302 0 : return gpg_error_from_syserror ();
1303 :
1304 761 : if (!nread)
1305 : {
1306 262 : gpg->colon.eof = 1;
1307 262 : assert (gpg->colon.fnc);
1308 262 : gpg->colon.fnc (gpg->colon.fnc_value, NULL);
1309 262 : return 0;
1310 : }
1311 :
1312 6655 : while (nread > 0)
1313 : {
1314 355116 : for (p = buffer + readpos; nread; nread--, p++)
1315 : {
1316 354854 : if ( *p == '\n' )
1317 : {
1318 : /* (we require that the last line is terminated by a LF)
1319 : and we skip empty lines. Note: we use UTF8 encoding
1320 : and escaping of special characters. We require at
1321 : least one colon to cope with some other printed
1322 : information. */
1323 5383 : *p = 0;
1324 5383 : if (*buffer && strchr (buffer, ':'))
1325 : {
1326 5383 : char *line = NULL;
1327 :
1328 5383 : if (gpg->colon.preprocess_fnc)
1329 : {
1330 : gpgme_error_t err;
1331 :
1332 0 : err = gpg->colon.preprocess_fnc (buffer, &line);
1333 0 : if (err)
1334 0 : return err;
1335 : }
1336 :
1337 5397 : assert (gpg->colon.fnc);
1338 5397 : if (line)
1339 : {
1340 0 : char *linep = line;
1341 : char *endp;
1342 :
1343 : do
1344 : {
1345 0 : endp = strchr (linep, '\n');
1346 0 : if (endp)
1347 0 : *endp++ = 0;
1348 0 : gpg->colon.fnc (gpg->colon.fnc_value, linep);
1349 0 : linep = endp;
1350 : }
1351 0 : while (linep && *linep);
1352 :
1353 0 : gpgrt_free (line);
1354 : }
1355 : else
1356 5397 : gpg->colon.fnc (gpg->colon.fnc_value, buffer);
1357 : }
1358 :
1359 : /* To reuse the buffer for the next line we have to
1360 : shift the remaining data to the buffer start and
1361 : restart the loop Hmmm: We can optimize this function
1362 : by looking forward in the buffer to see whether a
1363 : second complete line is available and in this case
1364 : avoid the memmove for this line. */
1365 5395 : nread--; p++;
1366 5395 : if (nread)
1367 5133 : memmove (buffer, p, nread);
1368 5395 : readpos = 0;
1369 5395 : break; /* The for loop. */
1370 : }
1371 : else
1372 349471 : readpos++;
1373 : }
1374 : }
1375 :
1376 : /* Update the gpg object. */
1377 511 : gpg->colon.bufsize = bufsize;
1378 511 : gpg->colon.buffer = buffer;
1379 511 : gpg->colon.readpos = readpos;
1380 511 : return 0;
1381 : }
1382 :
1383 :
1384 : /* This colonline handler thing is not the clean way to do it. It
1385 : might be better to enhance the gpgme_data_t object to act as a wrapper
1386 : for a callback. Same goes for the status thing. For now we use
1387 : this thing here because it is easier to implement. */
1388 : static gpgme_error_t
1389 774 : colon_line_handler (void *opaque, int fd)
1390 : {
1391 774 : struct io_cb_data *data = (struct io_cb_data *) opaque;
1392 774 : engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
1393 774 : gpgme_error_t rc = 0;
1394 :
1395 774 : assert (fd == gpg->colon.fd[0]);
1396 774 : rc = read_colon_line (gpg);
1397 773 : if (rc)
1398 0 : return rc;
1399 773 : if (gpg->colon.eof)
1400 262 : _gpgme_io_close (fd);
1401 773 : return 0;
1402 : }
1403 :
1404 :
1405 : static gpgme_error_t
1406 651 : start (engine_gpg_t gpg)
1407 : {
1408 : gpgme_error_t rc;
1409 : int i, n;
1410 : int status;
1411 : struct spawn_fd_item_s *fd_list;
1412 : pid_t pid;
1413 : const char *pgmname;
1414 :
1415 651 : if (!gpg)
1416 0 : return gpg_error (GPG_ERR_INV_VALUE);
1417 :
1418 651 : if (!gpg->file_name && !_gpgme_get_default_gpg_name ())
1419 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
1420 :
1421 651 : if (gpg->lc_ctype)
1422 : {
1423 155 : rc = add_arg_ext (gpg, gpg->lc_ctype, 1);
1424 155 : if (!rc)
1425 155 : rc = add_arg_ext (gpg, "--lc-ctype", 1);
1426 155 : if (rc)
1427 0 : return rc;
1428 : }
1429 :
1430 651 : if (gpg->lc_messages)
1431 : {
1432 155 : rc = add_arg_ext (gpg, gpg->lc_messages, 1);
1433 155 : if (!rc)
1434 155 : rc = add_arg_ext (gpg, "--lc-messages", 1);
1435 155 : if (rc)
1436 0 : return rc;
1437 : }
1438 :
1439 651 : pgmname = gpg->file_name ? gpg->file_name : _gpgme_get_default_gpg_name ();
1440 651 : rc = build_argv (gpg, pgmname);
1441 651 : if (rc)
1442 0 : return rc;
1443 :
1444 : /* status_fd, colon_fd and end of list. */
1445 651 : n = 3;
1446 1236 : for (i = 0; gpg->fd_data_map[i].data; i++)
1447 585 : n++;
1448 651 : fd_list = calloc (n, sizeof *fd_list);
1449 651 : if (! fd_list)
1450 0 : return gpg_error_from_syserror ();
1451 :
1452 : /* Build the fd list for the child. */
1453 651 : n = 0;
1454 651 : fd_list[n].fd = gpg->status.fd[1];
1455 651 : fd_list[n].dup_to = -1;
1456 651 : fd_list[n].arg_loc = gpg->status.arg_loc;
1457 651 : n++;
1458 651 : if (gpg->colon.fnc)
1459 : {
1460 268 : fd_list[n].fd = gpg->colon.fd[1];
1461 268 : fd_list[n].dup_to = 1;
1462 268 : n++;
1463 : }
1464 1236 : for (i = 0; gpg->fd_data_map[i].data; i++)
1465 : {
1466 585 : fd_list[n].fd = gpg->fd_data_map[i].peer_fd;
1467 585 : fd_list[n].dup_to = gpg->fd_data_map[i].dup_to;
1468 585 : fd_list[n].arg_loc = gpg->fd_data_map[i].arg_loc;
1469 585 : n++;
1470 : }
1471 651 : fd_list[n].fd = -1;
1472 651 : fd_list[n].dup_to = -1;
1473 :
1474 651 : status = _gpgme_io_spawn (pgmname, gpg->argv,
1475 : (IOSPAWN_FLAG_DETACHED |IOSPAWN_FLAG_ALLOW_SET_FG),
1476 : fd_list, NULL, NULL, &pid);
1477 : {
1478 648 : int saved_err = gpg_error_from_syserror ();
1479 648 : free (fd_list);
1480 648 : if (status == -1)
1481 0 : return saved_err;
1482 : }
1483 :
1484 : /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
1485 :
1486 648 : rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
1487 : &gpg->status.tag);
1488 648 : if (rc)
1489 : /* FIXME: kill the child */
1490 0 : return rc;
1491 :
1492 648 : if (gpg->colon.fnc)
1493 : {
1494 268 : assert (gpg->colon.fd[0] != -1);
1495 268 : rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
1496 : &gpg->colon.tag);
1497 268 : if (rc)
1498 : /* FIXME: kill the child */
1499 0 : return rc;
1500 : }
1501 :
1502 1228 : for (i = 0; gpg->fd_data_map[i].data; i++)
1503 : {
1504 580 : if (gpg->cmd.used && i == gpg->cmd.idx)
1505 : {
1506 : /* Park the cmd fd. */
1507 97 : gpg->cmd.fd = gpg->fd_data_map[i].fd;
1508 97 : gpg->fd_data_map[i].fd = -1;
1509 : }
1510 : else
1511 : {
1512 1449 : rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
1513 483 : gpg->fd_data_map[i].inbound,
1514 483 : gpg->fd_data_map[i].inbound
1515 : ? _gpgme_data_inbound_handler
1516 : : _gpgme_data_outbound_handler,
1517 966 : gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
1518 :
1519 483 : if (rc)
1520 : /* FIXME: kill the child */
1521 0 : return rc;
1522 : }
1523 : }
1524 :
1525 648 : gpg_io_event (gpg, GPGME_EVENT_START, NULL);
1526 :
1527 : /* fixme: check what data we can release here */
1528 648 : return 0;
1529 : }
1530 :
1531 :
1532 : /* Add the --input-size-hint option if requested. */
1533 : static gpgme_error_t
1534 228 : add_input_size_hint (engine_gpg_t gpg, gpgme_data_t data)
1535 : {
1536 : gpgme_error_t err;
1537 228 : gpgme_off_t value = _gpgme_data_get_size_hint (data);
1538 : char numbuf[50]; /* Large enough for even 2^128 in base-10. */
1539 : char *p;
1540 :
1541 228 : if (!value || !have_gpg_version (gpg, "2.1.15"))
1542 207 : return 0;
1543 :
1544 21 : err = add_arg (gpg, "--input-size-hint");
1545 21 : if (!err)
1546 : {
1547 21 : p = numbuf + sizeof numbuf;
1548 21 : *--p = 0;
1549 : do
1550 : {
1551 53 : *--p = '0' + (value % 10);
1552 53 : value /= 10;
1553 : }
1554 53 : while (value);
1555 21 : err = add_arg (gpg, p);
1556 : }
1557 21 : return err;
1558 : }
1559 :
1560 :
1561 : static gpgme_error_t
1562 50 : gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain,
1563 : int export_session_key, const char *override_session_key)
1564 : {
1565 50 : engine_gpg_t gpg = engine;
1566 : gpgme_error_t err;
1567 :
1568 50 : err = add_arg (gpg, "--decrypt");
1569 :
1570 50 : if (!err && export_session_key)
1571 0 : err = add_arg (gpg, "--show-session-key");
1572 :
1573 50 : if (!err && override_session_key && *override_session_key)
1574 : {
1575 0 : if (have_gpg_version (gpg, "2.1.16"))
1576 : {
1577 0 : gpgme_data_release (gpg->override_session_key);
1578 0 : TRACE2 (DEBUG_ENGINE, "override", gpg, "seskey='%s' len=%zu\n",
1579 : override_session_key,
1580 : strlen (override_session_key));
1581 :
1582 0 : err = gpgme_data_new_from_mem (&gpg->override_session_key,
1583 : override_session_key,
1584 : strlen (override_session_key), 1);
1585 0 : if (!err)
1586 : {
1587 0 : err = add_arg (gpg, "--override-session-key-fd");
1588 0 : if (!err)
1589 0 : err = add_data (gpg, gpg->override_session_key, -2, 0);
1590 : }
1591 : }
1592 : else
1593 : {
1594 : /* Using that option may leak the session key via ps(1). */
1595 0 : err = add_arg (gpg, "--override-session-key");
1596 0 : if (!err)
1597 0 : err = add_arg (gpg, override_session_key);
1598 : }
1599 : }
1600 :
1601 : /* Tell the gpg object about the data. */
1602 50 : if (!err)
1603 50 : err = add_arg (gpg, "--output");
1604 50 : if (!err)
1605 50 : err = add_arg (gpg, "-");
1606 50 : if (!err)
1607 50 : err = add_data (gpg, plain, 1, 1);
1608 50 : if (!err)
1609 50 : err = add_input_size_hint (gpg, ciph);
1610 50 : if (!err)
1611 50 : err = add_arg (gpg, "--");
1612 50 : if (!err)
1613 50 : err = add_data (gpg, ciph, -1, 0);
1614 :
1615 50 : if (!err)
1616 50 : err = start (gpg);
1617 51 : return err;
1618 : }
1619 :
1620 : static gpgme_error_t
1621 0 : gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
1622 : {
1623 0 : engine_gpg_t gpg = engine;
1624 : gpgme_error_t err;
1625 :
1626 0 : err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
1627 : : "--delete-key");
1628 0 : if (!err)
1629 0 : err = add_arg (gpg, "--");
1630 0 : if (!err)
1631 : {
1632 0 : if (!key->subkeys || !key->subkeys->fpr)
1633 0 : return gpg_error (GPG_ERR_INV_VALUE);
1634 : else
1635 0 : err = add_arg (gpg, key->subkeys->fpr);
1636 : }
1637 :
1638 0 : if (!err)
1639 0 : err = start (gpg);
1640 0 : return err;
1641 : }
1642 :
1643 :
1644 : static gpgme_error_t
1645 0 : gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1646 : {
1647 0 : engine_gpg_t gpg = engine;
1648 : gpgme_error_t err;
1649 :
1650 : (void)flags;
1651 :
1652 0 : if (!key || !key->subkeys || !key->subkeys->fpr)
1653 0 : return gpg_error (GPG_ERR_INV_CERT_OBJ);
1654 :
1655 0 : err = add_arg (gpg, "--passwd");
1656 0 : if (!err)
1657 0 : err = add_arg (gpg, key->subkeys->fpr);
1658 0 : if (!err)
1659 0 : err = start (gpg);
1660 0 : return err;
1661 : }
1662 :
1663 :
1664 : static gpgme_error_t
1665 83 : append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1666 : {
1667 83 : gpgme_error_t err = 0;
1668 : int i;
1669 : gpgme_key_t key;
1670 :
1671 137 : for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1672 : {
1673 54 : const char *s = key->subkeys ? key->subkeys->keyid : NULL;
1674 54 : if (s)
1675 : {
1676 54 : if (!err)
1677 54 : err = add_arg (gpg, "-u");
1678 54 : if (!err)
1679 54 : err = add_arg (gpg, s);
1680 : }
1681 54 : gpgme_key_unref (key);
1682 54 : if (err)
1683 0 : break;
1684 : }
1685 83 : return err;
1686 : }
1687 :
1688 :
1689 : static gpgme_error_t
1690 115 : append_args_from_sender (engine_gpg_t gpg, gpgme_ctx_t ctx)
1691 : {
1692 : gpgme_error_t err;
1693 :
1694 115 : if (ctx->sender && have_gpg_version (gpg, "2.1.15"))
1695 : {
1696 1 : err = add_arg (gpg, "--sender");
1697 2 : if (!err)
1698 1 : err = add_arg (gpg, ctx->sender);
1699 : }
1700 : else
1701 114 : err = 0;
1702 115 : return err;
1703 : }
1704 :
1705 :
1706 : static gpgme_error_t
1707 62 : append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1708 : {
1709 62 : gpgme_error_t err = 0;
1710 : gpgme_sig_notation_t notation;
1711 :
1712 62 : notation = gpgme_sig_notation_get (ctx);
1713 :
1714 133 : while (!err && notation)
1715 : {
1716 9 : if (notation->name
1717 6 : && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
1718 0 : err = gpg_error (GPG_ERR_INV_VALUE);
1719 9 : else if (notation->name)
1720 : {
1721 : char *arg;
1722 :
1723 : /* Maximum space needed is one byte for the "critical" flag,
1724 : the name, one byte for '=', the value, and a terminating
1725 : '\0'. */
1726 :
1727 6 : arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1);
1728 6 : if (!arg)
1729 0 : err = gpg_error_from_syserror ();
1730 :
1731 6 : if (!err)
1732 : {
1733 6 : char *argp = arg;
1734 :
1735 6 : if (notation->critical)
1736 3 : *(argp++) = '!';
1737 :
1738 6 : memcpy (argp, notation->name, notation->name_len);
1739 6 : argp += notation->name_len;
1740 :
1741 6 : *(argp++) = '=';
1742 :
1743 : /* We know that notation->name is '\0' terminated. */
1744 6 : strcpy (argp, notation->value);
1745 : }
1746 :
1747 6 : if (!err)
1748 6 : err = add_arg (gpg, "--sig-notation");
1749 6 : if (!err)
1750 6 : err = add_arg (gpg, arg);
1751 :
1752 6 : if (arg)
1753 6 : free (arg);
1754 : }
1755 : else
1756 : {
1757 : /* This is a policy URL. */
1758 :
1759 : char *value;
1760 :
1761 3 : if (notation->critical)
1762 : {
1763 0 : value = malloc (1 + notation->value_len + 1);
1764 0 : if (!value)
1765 0 : err = gpg_error_from_syserror ();
1766 : else
1767 : {
1768 0 : value[0] = '!';
1769 : /* We know that notation->value is '\0' terminated. */
1770 0 : strcpy (&value[1], notation->value);
1771 : }
1772 : }
1773 : else
1774 3 : value = notation->value;
1775 :
1776 3 : if (!err)
1777 3 : err = add_arg (gpg, "--sig-policy-url");
1778 3 : if (!err)
1779 3 : err = add_arg (gpg, value);
1780 :
1781 3 : if (value != notation->value)
1782 0 : free (value);
1783 : }
1784 :
1785 9 : notation = notation->next;
1786 : }
1787 62 : return err;
1788 : }
1789 :
1790 :
1791 : static gpgme_error_t
1792 13 : gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
1793 : gpgme_ctx_t ctx /* FIXME */)
1794 : {
1795 13 : engine_gpg_t gpg = engine;
1796 : gpgme_error_t err;
1797 :
1798 13 : err = add_arg (gpg, "--with-colons");
1799 13 : if (!err)
1800 13 : err = append_args_from_signers (gpg, ctx);
1801 13 : if (!err)
1802 13 : err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
1803 13 : if (!err)
1804 13 : err = add_data (gpg, out, 1, 1);
1805 13 : if (!err)
1806 13 : err = add_arg (gpg, "--");
1807 13 : if (!err && type == 0)
1808 : {
1809 13 : const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1810 13 : if (!s)
1811 0 : err = gpg_error (GPG_ERR_INV_VALUE);
1812 : else
1813 13 : err = add_arg (gpg, s);
1814 : }
1815 13 : if (!err)
1816 13 : err = start (gpg);
1817 :
1818 13 : return err;
1819 : }
1820 :
1821 :
1822 : static gpgme_error_t
1823 56 : append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
1824 : {
1825 56 : gpgme_error_t err = 0;
1826 56 : int i = 0;
1827 :
1828 206 : while (recp[i])
1829 : {
1830 94 : if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1831 0 : err = gpg_error (GPG_ERR_INV_VALUE);
1832 94 : if (!err)
1833 94 : err = add_arg (gpg, "-r");
1834 94 : if (!err)
1835 94 : err = add_arg (gpg, recp[i]->subkeys->fpr);
1836 94 : if (err)
1837 0 : break;
1838 94 : i++;
1839 : }
1840 56 : return err;
1841 : }
1842 :
1843 :
1844 : static gpgme_error_t
1845 63 : gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1846 : gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1847 : {
1848 63 : engine_gpg_t gpg = engine;
1849 63 : gpgme_error_t err = 0;
1850 :
1851 63 : if (recp)
1852 43 : err = add_arg (gpg, "--encrypt");
1853 :
1854 63 : if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
1855 21 : err = add_arg (gpg, "--symmetric");
1856 :
1857 63 : if (!err && use_armor)
1858 45 : err = add_arg (gpg, "--armor");
1859 :
1860 63 : if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
1861 0 : err = add_arg (gpg, "--compress-algo=none");
1862 :
1863 63 : if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
1864 0 : && have_gpg_version (gpg, "2.1.14"))
1865 0 : err = add_arg (gpg, "--mimemode");
1866 :
1867 63 : if (recp)
1868 : {
1869 : /* If we know that all recipients are valid (full or ultimate trust)
1870 : we can suppress further checks. */
1871 43 : if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1872 43 : err = add_arg (gpg, "--always-trust");
1873 :
1874 43 : if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
1875 6 : err = add_arg (gpg, "--no-encrypt-to");
1876 :
1877 43 : if (!err)
1878 43 : err = append_args_from_recipients (gpg, recp);
1879 : }
1880 :
1881 : /* Tell the gpg object about the data. */
1882 63 : if (!err)
1883 63 : err = add_arg (gpg, "--output");
1884 63 : if (!err)
1885 63 : err = add_arg (gpg, "-");
1886 63 : if (!err)
1887 63 : err = add_data (gpg, ciph, 1, 1);
1888 63 : if (gpgme_data_get_file_name (plain))
1889 : {
1890 3 : if (!err)
1891 3 : err = add_arg (gpg, "--set-filename");
1892 3 : if (!err)
1893 3 : err = add_arg (gpg, gpgme_data_get_file_name (plain));
1894 : }
1895 63 : if (!err)
1896 63 : err = add_input_size_hint (gpg, plain);
1897 63 : if (!err)
1898 63 : err = add_arg (gpg, "--");
1899 63 : if (!err)
1900 63 : err = add_data (gpg, plain, -1, 0);
1901 :
1902 63 : if (!err)
1903 63 : err = start (gpg);
1904 :
1905 63 : return err;
1906 : }
1907 :
1908 :
1909 : static gpgme_error_t
1910 16 : gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
1911 : gpgme_encrypt_flags_t flags, gpgme_data_t plain,
1912 : gpgme_data_t ciph, int use_armor,
1913 : gpgme_ctx_t ctx /* FIXME */)
1914 : {
1915 16 : engine_gpg_t gpg = engine;
1916 16 : gpgme_error_t err = 0;
1917 :
1918 16 : if (recp)
1919 13 : err = add_arg (gpg, "--encrypt");
1920 :
1921 16 : if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
1922 3 : err = add_arg (gpg, "--symmetric");
1923 :
1924 16 : if (!err)
1925 16 : err = add_arg (gpg, "--sign");
1926 16 : if (!err && use_armor)
1927 12 : err = add_arg (gpg, "--armor");
1928 :
1929 16 : if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
1930 0 : err = add_arg (gpg, "--compress-algo=none");
1931 :
1932 16 : if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
1933 0 : && have_gpg_version (gpg, "2.1.14"))
1934 0 : err = add_arg (gpg, "--mimemode");
1935 :
1936 16 : if (recp)
1937 : {
1938 : /* If we know that all recipients are valid (full or ultimate trust)
1939 : we can suppress further checks. */
1940 13 : if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1941 9 : err = add_arg (gpg, "--always-trust");
1942 :
1943 13 : if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
1944 10 : err = add_arg (gpg, "--no-encrypt-to");
1945 :
1946 13 : if (!err)
1947 13 : err = append_args_from_recipients (gpg, recp);
1948 : }
1949 :
1950 16 : if (!err)
1951 16 : err = append_args_from_signers (gpg, ctx);
1952 :
1953 16 : if (!err)
1954 16 : err = append_args_from_sender (gpg, ctx);
1955 :
1956 16 : if (!err)
1957 16 : err = append_args_from_sig_notations (gpg, ctx);
1958 :
1959 : /* Tell the gpg object about the data. */
1960 16 : if (!err)
1961 16 : err = add_arg (gpg, "--output");
1962 16 : if (!err)
1963 16 : err = add_arg (gpg, "-");
1964 16 : if (!err)
1965 16 : err = add_data (gpg, ciph, 1, 1);
1966 16 : if (gpgme_data_get_file_name (plain))
1967 : {
1968 0 : if (!err)
1969 0 : err = add_arg (gpg, "--set-filename");
1970 0 : if (!err)
1971 0 : err = add_arg (gpg, gpgme_data_get_file_name (plain));
1972 : }
1973 16 : if (!err)
1974 16 : err = add_input_size_hint (gpg, plain);
1975 16 : if (!err)
1976 16 : err = add_arg (gpg, "--");
1977 16 : if (!err)
1978 16 : err = add_data (gpg, plain, -1, 0);
1979 :
1980 16 : if (!err)
1981 16 : err = start (gpg);
1982 :
1983 16 : return err;
1984 : }
1985 :
1986 :
1987 : static gpgme_error_t
1988 6 : export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
1989 : gpgme_data_t keydata, int use_armor)
1990 : {
1991 6 : gpgme_error_t err = 0;
1992 :
1993 6 : if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
1994 : |GPGME_EXPORT_MODE_MINIMAL
1995 : |GPGME_EXPORT_MODE_SECRET)))
1996 0 : return gpg_error (GPG_ERR_NOT_SUPPORTED);
1997 :
1998 6 : if ((mode & GPGME_EXPORT_MODE_MINIMAL))
1999 0 : err = add_arg (gpg, "--export-options=export-minimal");
2000 :
2001 6 : if (err)
2002 : ;
2003 6 : else if ((mode & GPGME_EXPORT_MODE_EXTERN))
2004 : {
2005 0 : err = add_arg (gpg, "--send-keys");
2006 : }
2007 : else
2008 : {
2009 6 : if ((mode & GPGME_EXPORT_MODE_SECRET))
2010 0 : err = add_arg (gpg, "--export-secret-keys");
2011 : else
2012 6 : err = add_arg (gpg, "--export");
2013 6 : if (!err && use_armor)
2014 6 : err = add_arg (gpg, "--armor");
2015 6 : if (!err)
2016 6 : err = add_data (gpg, keydata, 1, 1);
2017 : }
2018 6 : if (!err)
2019 6 : err = add_arg (gpg, "--");
2020 :
2021 6 : return err;
2022 : }
2023 :
2024 :
2025 : static gpgme_error_t
2026 0 : gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
2027 : gpgme_data_t keydata, int use_armor)
2028 : {
2029 0 : engine_gpg_t gpg = engine;
2030 : gpgme_error_t err;
2031 :
2032 0 : err = export_common (gpg, mode, keydata, use_armor);
2033 :
2034 0 : if (!err && pattern && *pattern)
2035 0 : err = add_arg (gpg, pattern);
2036 :
2037 0 : if (!err)
2038 0 : err = start (gpg);
2039 :
2040 0 : return err;
2041 : }
2042 :
2043 :
2044 : static gpgme_error_t
2045 6 : gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
2046 : gpgme_data_t keydata, int use_armor)
2047 : {
2048 6 : engine_gpg_t gpg = engine;
2049 : gpgme_error_t err;
2050 :
2051 6 : err = export_common (gpg, mode, keydata, use_armor);
2052 :
2053 6 : if (pattern)
2054 : {
2055 24 : while (!err && *pattern && **pattern)
2056 12 : err = add_arg (gpg, *(pattern++));
2057 : }
2058 :
2059 6 : if (!err)
2060 6 : err = start (gpg);
2061 :
2062 6 : return err;
2063 : }
2064 :
2065 :
2066 :
2067 : /* Helper to add algo, usage, and expire to the list of args. */
2068 : static gpgme_error_t
2069 74 : gpg_add_algo_usage_expire (engine_gpg_t gpg,
2070 : const char *algo,
2071 : unsigned long expires,
2072 : unsigned int flags)
2073 : {
2074 : gpg_error_t err;
2075 :
2076 : /* This condition is only required to allow the use of gpg < 2.1.16 */
2077 74 : if (algo
2078 46 : || (flags & (GPGME_CREATE_SIGN | GPGME_CREATE_ENCR
2079 : | GPGME_CREATE_CERT | GPGME_CREATE_AUTH
2080 : | GPGME_CREATE_NOEXPIRE))
2081 14 : || expires)
2082 : {
2083 64 : err = add_arg (gpg, algo? algo : "default");
2084 64 : if (!err)
2085 : {
2086 : char tmpbuf[5*4+1];
2087 256 : snprintf (tmpbuf, sizeof tmpbuf, "%s%s%s%s",
2088 64 : (flags & GPGME_CREATE_SIGN)? " sign":"",
2089 64 : (flags & GPGME_CREATE_ENCR)? " encr":"",
2090 64 : (flags & GPGME_CREATE_CERT)? " cert":"",
2091 64 : (flags & GPGME_CREATE_AUTH)? " auth":"");
2092 64 : err = add_arg (gpg, *tmpbuf? tmpbuf : "default");
2093 : }
2094 128 : if (!err)
2095 : {
2096 64 : if ((flags & GPGME_CREATE_NOEXPIRE))
2097 4 : err = add_arg (gpg, "never");
2098 60 : else if (expires == 0)
2099 56 : err = add_arg (gpg, "-");
2100 : else
2101 : {
2102 : char tmpbuf[8+20];
2103 4 : snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
2104 4 : err = add_arg (gpg, tmpbuf);
2105 : }
2106 : }
2107 : }
2108 : else
2109 10 : err = 0;
2110 :
2111 74 : return err;
2112 : }
2113 :
2114 :
2115 : static gpgme_error_t
2116 4 : gpg_createkey_from_param (engine_gpg_t gpg,
2117 : gpgme_data_t help_data, unsigned int extraflags)
2118 : {
2119 : gpgme_error_t err;
2120 :
2121 4 : err = add_arg (gpg, "--gen-key");
2122 4 : if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
2123 0 : err = add_arg (gpg, "--armor");
2124 4 : if (!err)
2125 4 : err = add_arg (gpg, "--");
2126 4 : if (!err)
2127 4 : err = add_data (gpg, help_data, -1, 0);
2128 4 : if (!err)
2129 4 : err = start (gpg);
2130 4 : return err;
2131 : }
2132 :
2133 :
2134 : static gpgme_error_t
2135 48 : gpg_createkey (engine_gpg_t gpg,
2136 : const char *userid, const char *algo,
2137 : unsigned long expires,
2138 : unsigned int flags,
2139 : unsigned int extraflags)
2140 : {
2141 : gpgme_error_t err;
2142 :
2143 48 : err = add_arg (gpg, "--quick-gen-key");
2144 48 : if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
2145 0 : err = add_arg (gpg, "--armor");
2146 48 : if (!err && (flags & GPGME_CREATE_NOPASSWD))
2147 : {
2148 46 : err = add_arg (gpg, "--passphrase");
2149 46 : if (!err)
2150 46 : err = add_arg (gpg, "");
2151 46 : if (!err)
2152 46 : err = add_arg (gpg, "--batch");
2153 : }
2154 48 : if (!err && (flags & GPGME_CREATE_FORCE))
2155 2 : err = add_arg (gpg, "--yes");
2156 48 : if (!err)
2157 48 : err = add_arg (gpg, "--");
2158 48 : if (!err)
2159 48 : err = add_arg (gpg, userid);
2160 :
2161 48 : if (!err)
2162 48 : err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
2163 :
2164 48 : if (!err)
2165 48 : err = start (gpg);
2166 48 : return err;
2167 : }
2168 :
2169 :
2170 : static gpgme_error_t
2171 26 : gpg_addkey (engine_gpg_t gpg,
2172 : const char *algo,
2173 : unsigned long expires,
2174 : gpgme_key_t key,
2175 : unsigned int flags,
2176 : unsigned int extraflags)
2177 : {
2178 : gpgme_error_t err;
2179 :
2180 26 : if (!key || !key->fpr)
2181 0 : return gpg_error (GPG_ERR_INV_ARG);
2182 :
2183 26 : err = add_arg (gpg, "--quick-addkey");
2184 26 : if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
2185 0 : err = add_arg (gpg, "--armor");
2186 26 : if (!err && (flags & GPGME_CREATE_NOPASSWD))
2187 : {
2188 24 : err = add_arg (gpg, "--passphrase");
2189 24 : if (!err)
2190 24 : err = add_arg (gpg, "");
2191 24 : if (!err)
2192 24 : err = add_arg (gpg, "--batch");
2193 : }
2194 26 : if (!err)
2195 26 : err = add_arg (gpg, "--");
2196 26 : if (!err)
2197 26 : err = add_arg (gpg, key->fpr);
2198 :
2199 26 : if (!err)
2200 26 : err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
2201 :
2202 26 : if (!err)
2203 26 : err = start (gpg);
2204 26 : return err;
2205 : }
2206 :
2207 :
2208 : static gpgme_error_t
2209 28 : gpg_adduid (engine_gpg_t gpg,
2210 : gpgme_key_t key,
2211 : const char *userid,
2212 : unsigned int extraflags)
2213 : {
2214 : gpgme_error_t err;
2215 :
2216 28 : if (!key || !key->fpr || !userid)
2217 0 : return gpg_error (GPG_ERR_INV_ARG);
2218 :
2219 28 : if ((extraflags & GENKEY_EXTRAFLAG_REVOKE))
2220 7 : err = add_arg (gpg, "--quick-revuid");
2221 : else
2222 21 : err = add_arg (gpg, "--quick-adduid");
2223 :
2224 28 : if (!err)
2225 28 : err = add_arg (gpg, "--");
2226 28 : if (!err)
2227 28 : err = add_arg (gpg, key->fpr);
2228 28 : if (!err)
2229 28 : err = add_arg (gpg, userid);
2230 :
2231 28 : if (!err)
2232 28 : err = start (gpg);
2233 28 : return err;
2234 : }
2235 :
2236 :
2237 : static gpgme_error_t
2238 106 : gpg_genkey (void *engine,
2239 : const char *userid, const char *algo,
2240 : unsigned long reserved, unsigned long expires,
2241 : gpgme_key_t key, unsigned int flags,
2242 : gpgme_data_t help_data, unsigned int extraflags,
2243 : gpgme_data_t pubkey, gpgme_data_t seckey)
2244 : {
2245 106 : engine_gpg_t gpg = engine;
2246 : gpgme_error_t err;
2247 :
2248 : (void)reserved;
2249 :
2250 106 : if (!gpg)
2251 0 : return gpg_error (GPG_ERR_INV_VALUE);
2252 :
2253 : /* If HELP_DATA is given the use of the old interface
2254 : * (gpgme_op_genkey) has been requested. The other modes are:
2255 : *
2256 : * USERID && !KEY - Create a new keyblock.
2257 : * !USERID && KEY - Add a new subkey to KEY (gpg >= 2.1.14)
2258 : * USERID && KEY && !ALGO - Add a new user id to KEY (gpg >= 2.1.14).
2259 : *
2260 : */
2261 106 : if (help_data)
2262 : {
2263 : /* We need a special mechanism to get the fd of a pipe here, so
2264 : that we can use this for the %pubring and %secring
2265 : parameters. We don't have this yet, so we implement only the
2266 : adding to the standard keyrings. */
2267 4 : if (pubkey || seckey)
2268 0 : err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
2269 : else
2270 4 : err = gpg_createkey_from_param (gpg, help_data, extraflags);
2271 : }
2272 102 : else if (!have_gpg_version (gpg, "2.1.13"))
2273 0 : err = gpg_error (GPG_ERR_NOT_SUPPORTED);
2274 102 : else if (userid && !key)
2275 48 : err = gpg_createkey (gpg, userid, algo, expires, flags, extraflags);
2276 54 : else if (!userid && key)
2277 26 : err = gpg_addkey (gpg, algo, expires, key, flags, extraflags);
2278 28 : else if (userid && key && !algo)
2279 28 : err = gpg_adduid (gpg, key, userid, extraflags);
2280 : else
2281 0 : err = gpg_error (GPG_ERR_INV_VALUE);
2282 :
2283 106 : return err;
2284 : }
2285 :
2286 : /* Return the next DELIM delimited string from DATA as a C-string.
2287 : The caller needs to provide the address of a pointer variable which
2288 : he has to set to NULL before the first call. After the last call
2289 : to this function, this function needs to be called once more with
2290 : DATA set to NULL so that the function can release its internal
2291 : state. After that the pointer variable is free for use again.
2292 : Note that we use a delimiter and thus a trailing delimiter is not
2293 : required. DELIM may not be changed after the first call. */
2294 : static const char *
2295 0 : string_from_data (gpgme_data_t data, int delim,
2296 : void **helpptr, gpgme_error_t *r_err)
2297 : {
2298 : #define MYBUFLEN 2000 /* Fixme: We don't support URLs longer than that. */
2299 : struct {
2300 : int eof_seen;
2301 : int nbytes; /* Length of the last returned string including
2302 : the delimiter. */
2303 : int buflen; /* Valid length of BUF. */
2304 : char buf[MYBUFLEN+1]; /* Buffer with one byte extra space. */
2305 : } *self;
2306 : char *p;
2307 : int nread;
2308 :
2309 0 : *r_err = 0;
2310 0 : if (!data)
2311 : {
2312 0 : if (*helpptr)
2313 : {
2314 0 : free (*helpptr);
2315 0 : *helpptr = NULL;
2316 : }
2317 0 : return NULL;
2318 : }
2319 :
2320 0 : if (*helpptr)
2321 0 : self = *helpptr;
2322 : else
2323 : {
2324 0 : self = malloc (sizeof *self);
2325 0 : if (!self)
2326 : {
2327 0 : *r_err = gpg_error_from_syserror ();
2328 0 : return NULL;
2329 : }
2330 0 : *helpptr = self;
2331 0 : self->eof_seen = 0;
2332 0 : self->nbytes = 0;
2333 0 : self->buflen = 0;
2334 : }
2335 :
2336 0 : if (self->eof_seen)
2337 0 : return NULL;
2338 :
2339 0 : assert (self->nbytes <= self->buflen);
2340 0 : memmove (self->buf, self->buf + self->nbytes, self->buflen - self->nbytes);
2341 0 : self->buflen -= self->nbytes;
2342 0 : self->nbytes = 0;
2343 :
2344 : do
2345 : {
2346 : /* Fixme: This is fairly infective scanning because we may scan
2347 : the buffer several times. */
2348 0 : p = memchr (self->buf, delim, self->buflen);
2349 0 : if (p)
2350 : {
2351 0 : *p = 0;
2352 0 : self->nbytes = p - self->buf + 1;
2353 0 : return self->buf;
2354 : }
2355 :
2356 0 : if ( !(MYBUFLEN - self->buflen) )
2357 : {
2358 : /* Not enough space - URL too long. */
2359 0 : *r_err = gpg_error (GPG_ERR_TOO_LARGE);
2360 0 : return NULL;
2361 : }
2362 :
2363 0 : nread = gpgme_data_read (data, self->buf + self->buflen,
2364 0 : MYBUFLEN - self->buflen);
2365 0 : if (nread < 0)
2366 : {
2367 0 : *r_err = gpg_error_from_syserror ();
2368 0 : return NULL;
2369 : }
2370 0 : self->buflen += nread;
2371 : }
2372 0 : while (nread);
2373 :
2374 : /* EOF reached. If we have anything in the buffer, append a Nul and
2375 : return it. */
2376 0 : self->eof_seen = 1;
2377 0 : if (self->buflen)
2378 : {
2379 0 : self->buf[self->buflen] = 0; /* (we allocated one extra byte) */
2380 0 : return self->buf;
2381 : }
2382 0 : return NULL;
2383 : #undef MYBUFLEN
2384 : }
2385 :
2386 :
2387 :
2388 : static gpgme_error_t
2389 10 : gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
2390 : {
2391 10 : engine_gpg_t gpg = engine;
2392 : gpgme_error_t err;
2393 : int idx;
2394 : gpgme_data_encoding_t dataenc;
2395 :
2396 10 : if (keydata && keyarray)
2397 0 : return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
2398 :
2399 10 : dataenc = gpgme_data_get_encoding (keydata);
2400 :
2401 10 : if (keyarray)
2402 : {
2403 0 : err = add_arg (gpg, "--recv-keys");
2404 0 : if (!err)
2405 0 : err = add_arg (gpg, "--");
2406 0 : for (idx=0; !err && keyarray[idx]; idx++)
2407 : {
2408 0 : if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP)
2409 : ;
2410 0 : else if (!keyarray[idx]->subkeys)
2411 : ;
2412 0 : else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr)
2413 0 : err = add_arg (gpg, keyarray[idx]->subkeys->fpr);
2414 0 : else if (*keyarray[idx]->subkeys->keyid)
2415 0 : err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
2416 : }
2417 : }
2418 10 : else if (dataenc == GPGME_DATA_ENCODING_URL
2419 10 : || dataenc == GPGME_DATA_ENCODING_URL0)
2420 0 : {
2421 : void *helpptr;
2422 : const char *string;
2423 : gpgme_error_t xerr;
2424 0 : int delim = (dataenc == GPGME_DATA_ENCODING_URL)? '\n': 0;
2425 :
2426 : /* FIXME: --fetch-keys is probably not correct because it can't
2427 : grok all kinds of URLs. On Unix it should just work but on
2428 : Windows we will build the command line and that may fail for
2429 : some embedded control characters. It is anyway limited to
2430 : the maximum size of the command line. We need another
2431 : command which can take its input from a file. Maybe we
2432 : should use an option to gpg to modify such commands (ala
2433 : --multifile). */
2434 0 : err = add_arg (gpg, "--fetch-keys");
2435 0 : if (!err)
2436 0 : err = add_arg (gpg, "--");
2437 0 : helpptr = NULL;
2438 0 : while (!err
2439 0 : && (string = string_from_data (keydata, delim, &helpptr, &xerr)))
2440 0 : err = add_arg (gpg, string);
2441 0 : if (!err)
2442 0 : err = xerr;
2443 0 : string_from_data (NULL, delim, &helpptr, &xerr);
2444 : }
2445 10 : else if (dataenc == GPGME_DATA_ENCODING_URLESC)
2446 : {
2447 : /* Already escaped URLs are not yet supported. */
2448 0 : err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
2449 : }
2450 : else
2451 : {
2452 10 : err = add_arg (gpg, "--import");
2453 10 : if (!err)
2454 10 : err = add_arg (gpg, "--");
2455 10 : if (!err)
2456 10 : err = add_data (gpg, keydata, -1, 0);
2457 : }
2458 :
2459 10 : if (!err)
2460 10 : err = start (gpg);
2461 :
2462 10 : return err;
2463 : }
2464 :
2465 :
2466 : /* The output for external keylistings in GnuPG is different from all
2467 : the other key listings. We catch this here with a special
2468 : preprocessor that reformats the colon handler lines. */
2469 : static gpgme_error_t
2470 0 : gpg_keylist_preprocess (char *line, char **r_line)
2471 : {
2472 : enum
2473 : {
2474 : RT_NONE, RT_INFO, RT_PUB, RT_UID
2475 : }
2476 0 : rectype = RT_NONE;
2477 : #define NR_FIELDS 16
2478 : char *field[NR_FIELDS];
2479 0 : int fields = 0;
2480 : size_t n;
2481 :
2482 0 : *r_line = NULL;
2483 :
2484 0 : while (line && fields < NR_FIELDS)
2485 : {
2486 0 : field[fields++] = line;
2487 0 : line = strchr (line, ':');
2488 0 : if (line)
2489 0 : *(line++) = '\0';
2490 : }
2491 :
2492 0 : if (!strcmp (field[0], "info"))
2493 0 : rectype = RT_INFO;
2494 0 : else if (!strcmp (field[0], "pub"))
2495 0 : rectype = RT_PUB;
2496 0 : else if (!strcmp (field[0], "uid"))
2497 0 : rectype = RT_UID;
2498 : else
2499 0 : rectype = RT_NONE;
2500 :
2501 0 : switch (rectype)
2502 : {
2503 : case RT_INFO:
2504 : /* FIXME: Eventually, check the version number at least. */
2505 0 : return 0;
2506 :
2507 : case RT_PUB:
2508 0 : if (fields < 7)
2509 0 : return 0;
2510 :
2511 : /* The format is:
2512 :
2513 : pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
2514 :
2515 : as defined in 5.2. Machine Readable Indexes of the OpenPGP
2516 : HTTP Keyserver Protocol (draft). Modern versions of the SKS
2517 : keyserver return the fingerprint instead of the keyid. We
2518 : detect this here and use the v4 fingerprint format to convert
2519 : it to a key id.
2520 :
2521 : We want:
2522 : pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>::::::::
2523 : */
2524 :
2525 0 : n = strlen (field[1]);
2526 0 : if (n > 16)
2527 : {
2528 0 : if (gpgrt_asprintf (r_line,
2529 : "pub:o%s:%s:%s:%s:%s:%s::::::::\n"
2530 : "fpr:::::::::%s:",
2531 0 : field[6], field[3], field[2], field[1] + n - 16,
2532 : field[4], field[5], field[1]) < 0)
2533 0 : return gpg_error_from_syserror ();
2534 : }
2535 : else
2536 : {
2537 0 : if (gpgrt_asprintf (r_line,
2538 : "pub:o%s:%s:%s:%s:%s:%s::::::::",
2539 : field[6], field[3], field[2], field[1],
2540 : field[4], field[5]) < 0)
2541 0 : return gpg_error_from_syserror ();
2542 : }
2543 :
2544 0 : return 0;
2545 :
2546 : case RT_UID:
2547 : /* The format is:
2548 :
2549 : uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags>
2550 :
2551 : as defined in 5.2. Machine Readable Indexes of the OpenPGP
2552 : HTTP Keyserver Protocol (draft).
2553 :
2554 : We want:
2555 : uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>:
2556 : */
2557 :
2558 : {
2559 : /* The user ID is percent escaped, but we want c-coded.
2560 : Because we have to replace each '%HL' by '\xHL', we need at
2561 : most 4/3 th the number of bytes. But because we also need
2562 : to escape the backslashes we allocate twice as much. */
2563 0 : char *uid = malloc (2 * strlen (field[1]) + 1);
2564 : char *src;
2565 : char *dst;
2566 :
2567 0 : if (! uid)
2568 0 : return gpg_error_from_syserror ();
2569 0 : src = field[1];
2570 0 : dst = uid;
2571 0 : while (*src)
2572 : {
2573 0 : if (*src == '%')
2574 : {
2575 0 : *(dst++) = '\\';
2576 0 : *(dst++) = 'x';
2577 0 : src++;
2578 : /* Copy the next two bytes unconditionally. */
2579 0 : if (*src)
2580 0 : *(dst++) = *(src++);
2581 0 : if (*src)
2582 0 : *(dst++) = *(src++);
2583 : }
2584 0 : else if (*src == '\\')
2585 : {
2586 0 : *dst++ = '\\';
2587 0 : *dst++ = '\\';
2588 0 : src++;
2589 : }
2590 : else
2591 0 : *(dst++) = *(src++);
2592 : }
2593 0 : *dst = '\0';
2594 :
2595 0 : if (gpgrt_asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
2596 : field[4], field[2], field[3], uid) < 0)
2597 0 : return gpg_error_from_syserror ();
2598 : }
2599 0 : return 0;
2600 :
2601 : case RT_NONE:
2602 : /* Unknown record. */
2603 0 : break;
2604 : }
2605 0 : return 0;
2606 :
2607 : }
2608 :
2609 :
2610 : static gpg_error_t
2611 263 : gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
2612 : gpgme_keylist_mode_t mode)
2613 : {
2614 : gpg_error_t err;
2615 :
2616 263 : err = add_arg (gpg, "--with-colons");
2617 :
2618 : /* Since gpg 2.1.15 fingerprints are always printed, thus there is
2619 : * no more need to explicitly request them. */
2620 263 : if (!have_gpg_version (gpg, "2.1.15"))
2621 : {
2622 0 : if (!err)
2623 0 : err = add_arg (gpg, "--fixed-list-mode");
2624 0 : if (!err)
2625 0 : err = add_arg (gpg, "--with-fingerprint");
2626 0 : if (!err)
2627 0 : err = add_arg (gpg, "--with-fingerprint");
2628 : }
2629 :
2630 263 : if (!err && (mode & GPGME_KEYLIST_MODE_WITH_TOFU)
2631 23 : && have_gpg_version (gpg, "2.1.16"))
2632 23 : err = add_arg (gpg, "--with-tofu-info");
2633 :
2634 263 : if (!err && (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
2635 0 : err = add_arg (gpg, "--with-secret");
2636 :
2637 263 : if (!err
2638 263 : && (mode & GPGME_KEYLIST_MODE_SIGS)
2639 28 : && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
2640 : {
2641 8 : err = add_arg (gpg, "--list-options");
2642 8 : if (!err)
2643 8 : err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
2644 : }
2645 :
2646 263 : if (!err)
2647 : {
2648 263 : if ( (mode & GPGME_KEYLIST_MODE_EXTERN) )
2649 : {
2650 1 : if (secret_only)
2651 0 : err = gpg_error (GPG_ERR_NOT_SUPPORTED);
2652 1 : else if ( (mode & GPGME_KEYLIST_MODE_LOCAL))
2653 : {
2654 : /* The local+extern mode is special. It works only with
2655 : gpg >= 2.0.10. FIXME: We should check that we have
2656 : such a version to that we can return a proper error
2657 : code. The problem is that we don't know the context
2658 : here and thus can't access the cached version number
2659 : for the engine info structure. */
2660 1 : err = add_arg (gpg, "--locate-keys");
2661 1 : if ((mode & GPGME_KEYLIST_MODE_SIGS))
2662 1 : err = add_arg (gpg, "--with-sig-check");
2663 : }
2664 : else
2665 : {
2666 0 : err = add_arg (gpg, "--search-keys");
2667 0 : gpg->colon.preprocess_fnc = gpg_keylist_preprocess;
2668 : }
2669 : }
2670 : else
2671 : {
2672 475 : err = add_arg (gpg, secret_only ? "--list-secret-keys"
2673 213 : : ((mode & GPGME_KEYLIST_MODE_SIGS)
2674 213 : ? "--check-sigs" : "--list-keys"));
2675 : }
2676 : }
2677 :
2678 263 : if (!err)
2679 263 : err = add_arg (gpg, "--");
2680 :
2681 263 : return err;
2682 : }
2683 :
2684 :
2685 : static gpgme_error_t
2686 190 : gpg_keylist (void *engine, const char *pattern, int secret_only,
2687 : gpgme_keylist_mode_t mode, int engine_flags)
2688 : {
2689 190 : engine_gpg_t gpg = engine;
2690 : gpgme_error_t err;
2691 :
2692 : (void)engine_flags;
2693 :
2694 190 : err = gpg_keylist_build_options (gpg, secret_only, mode);
2695 :
2696 263 : if (!err && pattern && *pattern)
2697 229 : err = add_arg (gpg, pattern);
2698 :
2699 263 : if (!err)
2700 263 : err = start (gpg);
2701 :
2702 263 : return err;
2703 : }
2704 :
2705 :
2706 : static gpgme_error_t
2707 0 : gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
2708 : int reserved, gpgme_keylist_mode_t mode, int engine_flags)
2709 : {
2710 0 : engine_gpg_t gpg = engine;
2711 : gpgme_error_t err;
2712 :
2713 : (void)engine_flags;
2714 :
2715 0 : if (reserved)
2716 0 : return gpg_error (GPG_ERR_INV_VALUE);
2717 :
2718 0 : err = gpg_keylist_build_options (gpg, secret_only, mode);
2719 :
2720 0 : if (pattern)
2721 : {
2722 0 : while (!err && *pattern && **pattern)
2723 0 : err = add_arg (gpg, *(pattern++));
2724 : }
2725 :
2726 0 : if (!err)
2727 0 : err = start (gpg);
2728 :
2729 0 : return err;
2730 : }
2731 :
2732 :
2733 : static gpgme_error_t
2734 8 : gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
2735 : unsigned long expire, unsigned int flags,
2736 : gpgme_ctx_t ctx)
2737 : {
2738 8 : engine_gpg_t gpg = engine;
2739 : gpgme_error_t err;
2740 : const char *s;
2741 :
2742 8 : if (!key || !key->fpr)
2743 0 : return gpg_error (GPG_ERR_INV_ARG);
2744 :
2745 8 : if (!have_gpg_version (gpg, "2.1.12"))
2746 0 : return gpg_error (GPG_ERR_NOT_SUPPORTED);
2747 :
2748 8 : if ((flags & GPGME_KEYSIGN_LOCAL))
2749 6 : err = add_arg (gpg, "--quick-lsign-key");
2750 : else
2751 2 : err = add_arg (gpg, "--quick-sign-key");
2752 :
2753 8 : if (!err)
2754 8 : err = append_args_from_signers (gpg, ctx);
2755 :
2756 : /* If an expiration time has been given use that. If none has been
2757 : * given the default from gpg.conf is used. To make sure not to set
2758 : * an expiration time at all the flag GPGME_KEYSIGN_NOEXPIRE can be
2759 : * used. */
2760 8 : if (!err && (expire || (flags & GPGME_KEYSIGN_NOEXPIRE)))
2761 : {
2762 : char tmpbuf[8+20];
2763 :
2764 8 : if ((flags & GPGME_KEYSIGN_NOEXPIRE))
2765 4 : expire = 0;
2766 8 : snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expire);
2767 8 : err = add_arg (gpg, "--default-cert-expire");
2768 8 : if (!err)
2769 8 : err = add_arg (gpg, tmpbuf);
2770 : }
2771 :
2772 8 : if (!err)
2773 8 : err = add_arg (gpg, "--");
2774 :
2775 8 : if (!err)
2776 8 : err = add_arg (gpg, key->fpr);
2777 8 : if (!err && userid)
2778 : {
2779 6 : if ((flags & GPGME_KEYSIGN_LFSEP))
2780 : {
2781 8 : for (; !err && (s = strchr (userid, '\n')); userid = s + 1)
2782 4 : if ((s - userid))
2783 4 : err = add_arg_len (gpg, "=", userid, s - userid);
2784 4 : if (!err && *userid)
2785 4 : err = add_arg_pfx (gpg, "=", userid);
2786 : }
2787 : else
2788 2 : err = add_arg_pfx (gpg, "=", userid);
2789 : }
2790 :
2791 8 : if (!err)
2792 8 : err = start (gpg);
2793 :
2794 8 : return err;
2795 : }
2796 :
2797 :
2798 : static gpgme_error_t
2799 12 : gpg_tofu_policy (void *engine, gpgme_key_t key, gpgme_tofu_policy_t policy)
2800 : {
2801 12 : engine_gpg_t gpg = engine;
2802 : gpgme_error_t err;
2803 12 : const char *policystr = NULL;
2804 :
2805 12 : if (!key || !key->fpr)
2806 0 : return gpg_error (GPG_ERR_INV_ARG);
2807 :
2808 12 : switch (policy)
2809 : {
2810 0 : case GPGME_TOFU_POLICY_NONE: break;
2811 2 : case GPGME_TOFU_POLICY_AUTO: policystr = "auto"; break;
2812 3 : case GPGME_TOFU_POLICY_GOOD: policystr = "good"; break;
2813 3 : case GPGME_TOFU_POLICY_BAD: policystr = "bad"; break;
2814 2 : case GPGME_TOFU_POLICY_ASK: policystr = "ask"; break;
2815 2 : case GPGME_TOFU_POLICY_UNKNOWN: policystr = "unknown"; break;
2816 : }
2817 12 : if (!policystr)
2818 0 : return gpg_error (GPG_ERR_INV_VALUE);
2819 :
2820 12 : if (!have_gpg_version (gpg, "2.1.10"))
2821 0 : return gpg_error (GPG_ERR_NOT_SUPPORTED);
2822 :
2823 12 : err = add_arg (gpg, "--tofu-policy");
2824 12 : if (!err)
2825 12 : err = add_arg (gpg, "--");
2826 12 : if (!err)
2827 12 : err = add_arg (gpg, policystr);
2828 12 : if (!err)
2829 12 : err = add_arg (gpg, key->fpr);
2830 :
2831 12 : if (!err)
2832 12 : err = start (gpg);
2833 :
2834 12 : return err;
2835 : }
2836 :
2837 :
2838 : static gpgme_error_t
2839 46 : gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
2840 : gpgme_sig_mode_t mode, int use_armor, int use_textmode,
2841 : int include_certs, gpgme_ctx_t ctx /* FIXME */)
2842 : {
2843 46 : engine_gpg_t gpg = engine;
2844 : gpgme_error_t err;
2845 :
2846 : (void)include_certs;
2847 :
2848 46 : if (mode == GPGME_SIG_MODE_CLEAR)
2849 10 : err = add_arg (gpg, "--clearsign");
2850 : else
2851 : {
2852 36 : err = add_arg (gpg, "--sign");
2853 36 : if (!err && mode == GPGME_SIG_MODE_DETACH)
2854 10 : err = add_arg (gpg, "--detach");
2855 36 : if (!err && use_armor)
2856 20 : err = add_arg (gpg, "--armor");
2857 36 : if (!err)
2858 : {
2859 36 : if (gpgme_data_get_encoding (in) == GPGME_DATA_ENCODING_MIME
2860 0 : && have_gpg_version (gpg, "2.1.14"))
2861 0 : err = add_arg (gpg, "--mimemode");
2862 36 : else if (use_textmode)
2863 20 : err = add_arg (gpg, "--textmode");
2864 : }
2865 : }
2866 :
2867 46 : if (!err)
2868 46 : err = append_args_from_signers (gpg, ctx);
2869 46 : if (!err)
2870 46 : err = append_args_from_sender (gpg, ctx);
2871 46 : if (!err)
2872 46 : err = append_args_from_sig_notations (gpg, ctx);
2873 :
2874 46 : if (gpgme_data_get_file_name (in))
2875 : {
2876 0 : if (!err)
2877 0 : err = add_arg (gpg, "--set-filename");
2878 0 : if (!err)
2879 0 : err = add_arg (gpg, gpgme_data_get_file_name (in));
2880 : }
2881 :
2882 : /* Tell the gpg object about the data. */
2883 46 : if (!err)
2884 46 : err = add_input_size_hint (gpg, in);
2885 46 : if (!err)
2886 46 : err = add_arg (gpg, "--");
2887 46 : if (!err)
2888 46 : err = add_data (gpg, in, -1, 0);
2889 46 : if (!err)
2890 46 : err = add_data (gpg, out, 1, 1);
2891 :
2892 46 : if (!err)
2893 46 : err = start (gpg);
2894 :
2895 46 : return err;
2896 : }
2897 :
2898 : static gpgme_error_t
2899 5 : gpg_trustlist (void *engine, const char *pattern)
2900 : {
2901 5 : engine_gpg_t gpg = engine;
2902 : gpgme_error_t err;
2903 :
2904 5 : err = add_arg (gpg, "--with-colons");
2905 5 : if (!err)
2906 5 : err = add_arg (gpg, "--list-trust-path");
2907 :
2908 : /* Tell the gpg object about the data. */
2909 5 : if (!err)
2910 5 : err = add_arg (gpg, "--");
2911 5 : if (!err)
2912 5 : err = add_arg (gpg, pattern);
2913 :
2914 5 : if (!err)
2915 5 : err = start (gpg);
2916 :
2917 5 : return err;
2918 : }
2919 :
2920 :
2921 : static gpgme_error_t
2922 53 : gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
2923 : gpgme_data_t plaintext, gpgme_ctx_t ctx)
2924 : {
2925 53 : engine_gpg_t gpg = engine;
2926 : gpgme_error_t err;
2927 :
2928 53 : err = append_args_from_sender (gpg, ctx);
2929 53 : if (err)
2930 : ;
2931 53 : else if (plaintext)
2932 : {
2933 : /* Normal or cleartext signature. */
2934 29 : err = add_arg (gpg, "--output");
2935 29 : if (!err)
2936 29 : err = add_arg (gpg, "-");
2937 29 : if (!err)
2938 29 : err = add_input_size_hint (gpg, sig);
2939 29 : if (!err)
2940 29 : err = add_arg (gpg, "--");
2941 29 : if (!err)
2942 29 : err = add_data (gpg, sig, -1, 0);
2943 29 : if (!err)
2944 29 : err = add_data (gpg, plaintext, 1, 1);
2945 : }
2946 : else
2947 : {
2948 24 : err = add_arg (gpg, "--verify");
2949 24 : if (!err)
2950 24 : err = add_input_size_hint (gpg, signed_text);
2951 24 : if (!err)
2952 24 : err = add_arg (gpg, "--");
2953 24 : if (!err)
2954 24 : err = add_data (gpg, sig, -1, 0);
2955 24 : if (!err && signed_text)
2956 24 : err = add_data (gpg, signed_text, -1, 0);
2957 : }
2958 :
2959 53 : if (!err)
2960 53 : err = start (gpg);
2961 :
2962 49 : return err;
2963 : }
2964 :
2965 :
2966 : static void
2967 674 : gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
2968 : {
2969 674 : engine_gpg_t gpg = engine;
2970 :
2971 674 : gpg->io_cbs = *io_cbs;
2972 674 : }
2973 :
2974 :
2975 : static gpgme_error_t
2976 651 : gpg_set_pinentry_mode (void *engine, gpgme_pinentry_mode_t mode)
2977 : {
2978 651 : engine_gpg_t gpg = engine;
2979 :
2980 651 : gpg->pinentry_mode = mode;
2981 651 : return 0;
2982 : }
2983 :
2984 :
2985 :
2986 : struct engine_ops _gpgme_engine_ops_gpg =
2987 : {
2988 : /* Static functions. */
2989 : _gpgme_get_default_gpg_name,
2990 : NULL,
2991 : gpg_get_version,
2992 : gpg_get_req_version,
2993 : gpg_new,
2994 :
2995 : /* Member functions. */
2996 : gpg_release,
2997 : NULL, /* reset */
2998 : gpg_set_status_cb,
2999 : gpg_set_status_handler,
3000 : gpg_set_command_handler,
3001 : gpg_set_colon_line_handler,
3002 : gpg_set_locale,
3003 : NULL, /* set_protocol */
3004 : gpg_decrypt,
3005 : gpg_decrypt, /* decrypt_verify */
3006 : gpg_delete,
3007 : gpg_edit,
3008 : gpg_encrypt,
3009 : gpg_encrypt_sign,
3010 : gpg_export,
3011 : gpg_export_ext,
3012 : gpg_genkey,
3013 : gpg_import,
3014 : gpg_keylist,
3015 : gpg_keylist_ext,
3016 : gpg_keysign,
3017 : gpg_tofu_policy, /* tofu_policy */
3018 : gpg_sign,
3019 : gpg_trustlist,
3020 : gpg_verify,
3021 : NULL, /* getauditlog */
3022 : NULL, /* opassuan_transact */
3023 : NULL, /* conf_load */
3024 : NULL, /* conf_save */
3025 : NULL, /* query_swdb */
3026 : gpg_set_io_cbs,
3027 : gpg_io_event,
3028 : gpg_cancel,
3029 : NULL, /* cancel_op */
3030 : gpg_passwd,
3031 : gpg_set_pinentry_mode,
3032 : NULL /* opspawn */
3033 : };
|