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