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