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