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