Line data Source code
1 : /* gpgme-tool.c - Assuan server exposing GnuPG Made Easy operations.
2 : Copyright (C) 2009, 2010, 2012, 2013 g10 Code GmbH
3 : Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
4 :
5 : This file is part of GPGME.
6 :
7 : GPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : GPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, see <https://www.gnu.org/licenses/>.
19 : */
20 :
21 : #if HAVE_CONFIG_H
22 : #include <config.h>
23 : #endif
24 :
25 : #include <stdio.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #include <errno.h>
29 : #include <getopt.h>
30 : #include <ctype.h>
31 : #include <stdarg.h>
32 : #ifdef HAVE_LOCALE_H
33 : #include <locale.h>
34 : #endif
35 :
36 : #include <assuan.h>
37 :
38 : #include "argparse.h"
39 : #include "gpgme.h"
40 :
41 : /* GCC attributes. */
42 : #if __GNUC__ >= 4
43 : # define GT_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
44 : #else
45 : # define GT_GCC_A_SENTINEL(a)
46 : #endif
47 :
48 : #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
49 : # define GT_GCC_A_PRINTF(f, a) __attribute__ ((format (printf,f,a)))
50 : #else
51 : # define GT_GCC_A_PRINTF(f, a)
52 : #endif
53 :
54 : #define DIM(v) (sizeof(v)/sizeof((v)[0]))
55 : #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
56 : *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
57 : #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
58 :
59 :
60 :
61 : /* MEMBUF */
62 :
63 : /* A simple implementation of a dynamic buffer. Use init_membuf() to
64 : create a buffer, put_membuf to append bytes and get_membuf to
65 : release and return the buffer. Allocation errors are detected but
66 : only returned at the final get_membuf(), this helps not to clutter
67 : the code with out-of-core checks. */
68 :
69 : /* The definition of the structure is private, we only need it here,
70 : so it can be allocated on the stack. */
71 : struct private_membuf_s
72 : {
73 : size_t len;
74 : size_t size;
75 : char *buf;
76 : int out_of_core;
77 : };
78 :
79 : typedef struct private_membuf_s membuf_t;
80 :
81 : /* Return the current length of the membuf. */
82 : #define get_membuf_len(a) ((a)->len)
83 : #define is_membuf_ready(a) ((a)->buf || (a)->out_of_core)
84 : #define MEMBUF_ZERO { 0, 0, NULL, 0}
85 :
86 :
87 : static void
88 0 : init_membuf (membuf_t *mb, int initiallen)
89 : {
90 0 : mb->len = 0;
91 0 : mb->size = initiallen;
92 0 : mb->out_of_core = 0;
93 0 : mb->buf = malloc (initiallen);
94 0 : if (!mb->buf)
95 0 : mb->out_of_core = errno;
96 0 : }
97 :
98 :
99 : /* Shift the the content of the membuf MB by AMOUNT bytes. The next
100 : operation will then behave as if AMOUNT bytes had not been put into
101 : the buffer. If AMOUNT is greater than the actual accumulated
102 : bytes, the membuf is basically reset to its initial state. */
103 : #if 0 /* Not yet used. */
104 : static void
105 : clear_membuf (membuf_t *mb, size_t amount)
106 : {
107 : /* No need to clear if we are already out of core. */
108 : if (mb->out_of_core)
109 : return;
110 : if (amount >= mb->len)
111 : mb->len = 0;
112 : else
113 : {
114 : mb->len -= amount;
115 : memmove (mb->buf, mb->buf+amount, mb->len);
116 : }
117 : }
118 : #endif /* unused */
119 :
120 : static void
121 0 : put_membuf (membuf_t *mb, const void *buf, size_t len)
122 : {
123 0 : if (mb->out_of_core || !len)
124 0 : return;
125 :
126 0 : if (mb->len + len >= mb->size)
127 : {
128 : char *p;
129 :
130 0 : mb->size += len + 1024;
131 0 : p = realloc (mb->buf, mb->size);
132 0 : if (!p)
133 : {
134 0 : mb->out_of_core = errno ? errno : ENOMEM;
135 0 : return;
136 : }
137 0 : mb->buf = p;
138 : }
139 0 : memcpy (mb->buf + mb->len, buf, len);
140 0 : mb->len += len;
141 : }
142 :
143 :
144 : #if 0 /* Not yet used. */
145 : static void
146 : put_membuf_str (membuf_t *mb, const char *string)
147 : {
148 : put_membuf (mb, string, strlen (string));
149 : }
150 : #endif /* unused */
151 :
152 :
153 : static void *
154 0 : get_membuf (membuf_t *mb, size_t *len)
155 : {
156 : char *p;
157 :
158 0 : if (mb->out_of_core)
159 : {
160 0 : if (mb->buf)
161 : {
162 0 : free (mb->buf);
163 0 : mb->buf = NULL;
164 : }
165 0 : gpg_err_set_errno (mb->out_of_core);
166 0 : return NULL;
167 : }
168 :
169 0 : p = mb->buf;
170 0 : if (len)
171 0 : *len = mb->len;
172 0 : mb->buf = NULL;
173 0 : mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
174 0 : return p;
175 : }
176 :
177 :
178 : /* Peek at the membuf MB. On success a pointer to the buffer is
179 : returned which is valid until the next operation on MB. If LEN is
180 : not NULL the current LEN of the buffer is stored there. On error
181 : NULL is returned and ERRNO is set. */
182 : #if 0 /* Not yet used. */
183 : static const void *
184 : peek_membuf (membuf_t *mb, size_t *len)
185 : {
186 : const char *p;
187 :
188 : if (mb->out_of_core)
189 : {
190 : gpg_err_set_errno (mb->out_of_core);
191 : return NULL;
192 : }
193 :
194 : p = mb->buf;
195 : if (len)
196 : *len = mb->len;
197 : return p;
198 : }
199 : #endif /* unused */
200 :
201 :
202 :
203 : /* SUPPORT. */
204 : FILE *log_stream;
205 : char program_name[] = "gpgme-tool";
206 :
207 : #define spacep(p) (*(p) == ' ' || *(p) == '\t')
208 :
209 :
210 : void log_error (int status, gpg_error_t errnum,
211 : const char *fmt, ...) GT_GCC_A_PRINTF(3,4);
212 :
213 :
214 : void
215 0 : log_init (void)
216 : {
217 0 : log_stream = stderr;
218 0 : }
219 :
220 :
221 : void
222 0 : log_error (int status, gpg_error_t errnum, const char *fmt, ...)
223 : {
224 : va_list ap;
225 :
226 0 : fprintf (log_stream, "%s: ", program_name);
227 0 : va_start (ap, fmt);
228 0 : vfprintf (log_stream, fmt, ap);
229 0 : va_end (ap);
230 0 : if (errnum)
231 : {
232 0 : fprintf (log_stream, ": %s", gpg_strerror (errnum));
233 0 : if (gpg_err_source (errnum) != GPG_ERR_SOURCE_GPGME)
234 0 : fprintf (log_stream, " <%s>", gpg_strsource (errnum));
235 : }
236 0 : fprintf (log_stream, "\n");
237 0 : if (status)
238 0 : exit (status);
239 0 : }
240 :
241 :
242 : /* Note that it is sufficient to allocate the target string D as long
243 : as the source string S, i.e.: strlen(s)+1;. D == S is allowed. */
244 : static void
245 0 : strcpy_escaped_plus (char *d, const char *s)
246 : {
247 0 : while (*s)
248 : {
249 0 : if (*s == '%' && s[1] && s[2])
250 : {
251 0 : s++;
252 0 : *d++ = xtoi_2 (s);
253 0 : s += 2;
254 : }
255 0 : else if (*s == '+')
256 0 : *d++ = ' ', s++;
257 : else
258 0 : *d++ = *s++;
259 : }
260 0 : *d = 0;
261 0 : }
262 :
263 :
264 : /* Check whether the option NAME appears in LINE. */
265 : static int
266 0 : has_option (const char *line, const char *name)
267 : {
268 : const char *s;
269 0 : int n = strlen (name);
270 :
271 0 : s = strstr (line, name);
272 0 : return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
273 : }
274 :
275 : /* Skip over options. It is assumed that leading spaces have been
276 : removed (this is the case for lines passed to a handler from
277 : assuan). Blanks after the options are also removed. */
278 : static char *
279 0 : skip_options (char *line)
280 : {
281 0 : while ( *line == '-' && line[1] == '-' )
282 : {
283 0 : while (*line && !spacep (line))
284 0 : line++;
285 0 : while (spacep (line))
286 0 : line++;
287 : }
288 0 : return line;
289 : }
290 :
291 :
292 :
293 :
294 : typedef gpg_error_t (*result_xml_write_cb_t) (void *hook, const void *buf,
295 : size_t len);
296 :
297 : static char xml_preamble1[] = "<?xml version=\"1.0\" "
298 : "encoding=\"UTF-8\" standalone=\"yes\"?>\n";
299 : static const char xml_preamble2[] = "<gpgme>\n";
300 : static const char xml_end[] = "</gpgme>\n";
301 :
302 :
303 : struct result_xml_state
304 : {
305 : int indent;
306 : result_xml_write_cb_t cb;
307 : void *hook;
308 :
309 : #define MAX_TAGS 20
310 : int next_tag;
311 : const char *tag[MAX_TAGS];
312 : int had_data[MAX_TAGS];
313 : };
314 :
315 :
316 : void
317 0 : result_init (struct result_xml_state *state, int indent,
318 : result_xml_write_cb_t cb, void *hook)
319 : {
320 0 : memset (state, '\0', sizeof (*state));
321 0 : state->indent = indent;
322 0 : state->cb = cb;
323 0 : state->hook = hook;
324 0 : }
325 :
326 :
327 : gpg_error_t
328 0 : result_xml_indent (struct result_xml_state *state)
329 : {
330 0 : char spaces[state->indent + 1];
331 : int i;
332 0 : for (i = 0; i < state->indent; i++)
333 0 : spaces[i] = ' ';
334 0 : spaces[i] = '\0';
335 0 : return (*state->cb) (state->hook, spaces, i);
336 : }
337 :
338 :
339 : gpg_error_t
340 0 : result_xml_tag_start (struct result_xml_state *state, const char *name, ...)
341 : {
342 0 : result_xml_write_cb_t cb = state->cb;
343 0 : void *hook = state->hook;
344 : va_list ap;
345 : char *attr;
346 : char *attr_val;
347 0 : char string_null[] = "(null)";
348 :
349 0 : va_start (ap, name);
350 :
351 0 : if (state->next_tag > 0)
352 : {
353 0 : if (! state->had_data[state->next_tag - 1])
354 : {
355 0 : (*cb) (hook, ">\n", 2);
356 0 : (*cb) (hook, NULL, 0);
357 : }
358 0 : state->had_data[state->next_tag - 1] = 1;
359 : }
360 :
361 0 : result_xml_indent (state);
362 0 : (*cb) (hook, "<", 1);
363 0 : (*cb) (hook, name, strlen (name));
364 :
365 0 : state->tag[state->next_tag] = name;
366 0 : state->had_data[state->next_tag] = 0;
367 0 : state->indent += 2;
368 0 : state->next_tag++;
369 :
370 : while (1)
371 : {
372 0 : attr = va_arg (ap, char *);
373 0 : if (attr == NULL)
374 0 : break;
375 :
376 0 : attr_val = va_arg (ap, char *);
377 0 : if (attr_val == NULL)
378 0 : attr_val = string_null;
379 :
380 0 : (*cb) (hook, " ", 1);
381 0 : (*cb) (hook, attr, strlen (attr));
382 0 : (*cb) (hook, "=\"", 2);
383 0 : (*cb) (hook, attr_val, strlen (attr_val));
384 0 : (*cb) (hook, "\"", 1);
385 0 : }
386 0 : va_end (ap);
387 0 : return 0;
388 : }
389 :
390 : /* Return a constant string with an XML entity for C. */
391 : static const char *
392 0 : result_xml_escape_replacement(char c)
393 : {
394 0 : switch (c)
395 : {
396 : case '<':
397 0 : return "<";
398 : case '>':
399 0 : return ">";
400 : case '&':
401 0 : return "&";
402 : default:
403 0 : return NULL;
404 : }
405 : }
406 :
407 : /* Escape DATA by replacing certain characters with their XML
408 : entities. The result is stored in a newly allocated buffer which
409 : address will be stored at BUF. Returns 0 on success. */
410 : static gpg_error_t
411 0 : result_xml_escape (const char *data, char **buf)
412 : {
413 : int data_len, i;
414 : const char *r;
415 : membuf_t mb;
416 :
417 0 : init_membuf (&mb, 128);
418 0 : if (data)
419 : {
420 0 : data_len = strlen (data);
421 0 : for (i = 0; i < data_len; i++)
422 : {
423 0 : r = result_xml_escape_replacement (data[i]);
424 0 : if (r)
425 0 : put_membuf (&mb, r, strlen (r));
426 : else
427 0 : put_membuf (&mb, data+i, 1);
428 : }
429 : }
430 0 : put_membuf (&mb, "", 1);
431 0 : *buf = get_membuf (&mb, NULL);
432 0 : return *buf? 0 : gpg_error_from_syserror ();
433 : }
434 :
435 :
436 : gpg_error_t
437 0 : result_xml_tag_data (struct result_xml_state *state, const char *data)
438 : {
439 : gpg_error_t err;
440 0 : result_xml_write_cb_t cb = state->cb;
441 0 : void *hook = state->hook;
442 0 : char *buf = NULL;
443 :
444 0 : if (state->had_data[state->next_tag - 1])
445 : {
446 0 : (*cb) (hook, "\n", 2);
447 0 : (*cb) (hook, NULL, 0);
448 0 : result_xml_indent (state);
449 : }
450 : else
451 0 : (*cb) (hook, ">", 1);
452 0 : state->had_data[state->next_tag - 1] = 2;
453 :
454 0 : err = result_xml_escape (data, &buf);
455 0 : if (err)
456 0 : return err;
457 :
458 0 : (*cb) (hook, buf, strlen (buf));
459 :
460 0 : free (buf);
461 :
462 0 : return 0;
463 : }
464 :
465 :
466 : gpg_error_t
467 0 : result_xml_tag_end (struct result_xml_state *state)
468 : {
469 0 : result_xml_write_cb_t cb = state->cb;
470 0 : void *hook = state->hook;
471 :
472 0 : state->next_tag--;
473 0 : state->indent -= 2;
474 :
475 0 : if (state->had_data[state->next_tag])
476 : {
477 0 : if (state->had_data[state->next_tag] == 1)
478 0 : result_xml_indent (state);
479 0 : (*cb) (hook, "</", 2);
480 0 : (*cb) (hook, state->tag[state->next_tag],
481 0 : strlen (state->tag[state->next_tag]));
482 0 : (*cb) (hook, ">\n", 2);
483 0 : (*cb) (hook, NULL, 0);
484 : }
485 : else
486 : {
487 0 : (*cb) (hook, " />\n", 4);
488 0 : (*cb) (hook, NULL, 0);
489 : }
490 0 : return 0;
491 : }
492 :
493 :
494 : gpg_error_t
495 0 : result_add_error (struct result_xml_state *state,
496 : const char *name, gpg_error_t err)
497 : {
498 : char code[20];
499 : char msg[1024];
500 0 : snprintf (code, sizeof (code) - 1, "0x%x", err);
501 0 : snprintf (msg, sizeof (msg) - 1, "%s <%s>",
502 : gpg_strerror (err), gpg_strsource (err));
503 0 : result_xml_tag_start (state, name, "value", code, NULL);
504 0 : result_xml_tag_data (state, msg);
505 0 : result_xml_tag_end (state);
506 0 : return 0;
507 : }
508 :
509 :
510 : gpg_error_t
511 0 : result_add_pubkey_algo (struct result_xml_state *state,
512 : const char *name, gpgme_pubkey_algo_t algo)
513 : {
514 : char code[20];
515 : char msg[80];
516 0 : snprintf (code, sizeof (code) - 1, "0x%x", algo);
517 0 : snprintf (msg, sizeof (msg) - 1, "%s",
518 : gpgme_pubkey_algo_name (algo));
519 0 : result_xml_tag_start (state, name, "value", code, NULL);
520 0 : result_xml_tag_data (state, msg);
521 0 : result_xml_tag_end (state);
522 0 : return 0;
523 : }
524 :
525 :
526 : gpg_error_t
527 0 : result_add_hash_algo (struct result_xml_state *state,
528 : const char *name, gpgme_hash_algo_t algo)
529 : {
530 : char code[20];
531 : char msg[80];
532 :
533 0 : snprintf (code, sizeof (code) - 1, "0x%x", algo);
534 0 : snprintf (msg, sizeof (msg) - 1, "%s",
535 : gpgme_hash_algo_name (algo));
536 0 : result_xml_tag_start (state, name, "value", code, NULL);
537 0 : result_xml_tag_data (state, msg);
538 0 : result_xml_tag_end (state);
539 0 : return 0;
540 : }
541 :
542 :
543 : gpg_error_t
544 0 : result_add_keyid (struct result_xml_state *state,
545 : const char *name, const char *keyid)
546 : {
547 0 : result_xml_tag_start (state, name, NULL);
548 0 : result_xml_tag_data (state, keyid);
549 0 : result_xml_tag_end (state);
550 0 : return 0;
551 : }
552 :
553 :
554 : gpg_error_t
555 0 : result_add_fpr (struct result_xml_state *state,
556 : const char *name, const char *fpr)
557 : {
558 0 : result_xml_tag_start (state, name, NULL);
559 0 : result_xml_tag_data (state, fpr);
560 0 : result_xml_tag_end (state);
561 0 : return 0;
562 : }
563 :
564 :
565 : gpg_error_t
566 0 : result_add_timestamp (struct result_xml_state *state, const char *name,
567 : unsigned int timestamp)
568 : {
569 : char code[20];
570 :
571 0 : snprintf (code, sizeof (code) - 1, "%ui", timestamp);
572 0 : result_xml_tag_start (state, name, "unix", code, NULL);
573 0 : result_xml_tag_end (state);
574 0 : return 0;
575 : }
576 :
577 :
578 : gpg_error_t
579 0 : result_add_sig_mode (struct result_xml_state *state, const char *name,
580 : gpgme_sig_mode_t sig_mode)
581 : {
582 : const char *mode;
583 : char code[20];
584 :
585 0 : snprintf (code, sizeof (code) - 1, "%i", sig_mode);
586 0 : switch (sig_mode)
587 : {
588 : case GPGME_SIG_MODE_NORMAL:
589 0 : mode = "normal";
590 0 : break;
591 : case GPGME_SIG_MODE_DETACH:
592 0 : mode = "detach";
593 0 : break;
594 : case GPGME_SIG_MODE_CLEAR:
595 0 : mode = "clear";
596 0 : break;
597 : default:
598 0 : mode = "unknown";
599 : }
600 :
601 0 : result_xml_tag_start (state, name, "type", mode, "value", code, NULL);
602 0 : result_xml_tag_data (state, mode);
603 0 : result_xml_tag_end (state);
604 0 : return 0;
605 : }
606 :
607 :
608 : gpg_error_t
609 0 : result_add_protocol (struct result_xml_state *state, const char *name,
610 : gpgme_protocol_t protocol)
611 : {
612 : const char *str;
613 : char code[20];
614 :
615 0 : snprintf (code, sizeof (code) - 1, "%i", protocol);
616 0 : str = gpgme_get_protocol_name(protocol);
617 0 : if (!str)
618 0 : str = "invalid";
619 0 : result_xml_tag_start (state, name, "value", code, NULL);
620 0 : result_xml_tag_data (state, str);
621 0 : result_xml_tag_end (state);
622 0 : return 0;
623 : }
624 :
625 :
626 : gpg_error_t
627 0 : result_add_validity (struct result_xml_state *state, const char *name,
628 : gpgme_validity_t validity)
629 : {
630 : const char *str;
631 : char code[20];
632 :
633 0 : snprintf (code, sizeof (code) - 1, "%i", validity);
634 0 : switch (validity)
635 : {
636 : case GPGME_VALIDITY_UNDEFINED:
637 0 : str ="undefined";
638 0 : break;
639 : case GPGME_VALIDITY_NEVER:
640 0 : str ="never";
641 0 : break;
642 : case GPGME_VALIDITY_MARGINAL:
643 0 : str ="marginal";
644 0 : break;
645 : case GPGME_VALIDITY_FULL:
646 0 : str ="full";
647 0 : break;
648 : case GPGME_VALIDITY_ULTIMATE:
649 0 : str ="ultimate";
650 0 : break;
651 : default:
652 0 : str ="unknown";
653 : }
654 :
655 0 : result_xml_tag_start (state, name, "value", code, NULL);
656 0 : result_xml_tag_data (state, str);
657 0 : result_xml_tag_end (state);
658 0 : return 0;
659 : }
660 :
661 :
662 : gpg_error_t
663 0 : result_add_value (struct result_xml_state *state,
664 : const char *name, unsigned int val)
665 : {
666 : char code[20];
667 :
668 0 : snprintf (code, sizeof (code) - 1, "0x%x", val);
669 0 : result_xml_tag_start (state, name, "value", code, NULL);
670 0 : result_xml_tag_end (state);
671 0 : return 0;
672 : }
673 :
674 :
675 : gpg_error_t
676 0 : result_add_string (struct result_xml_state *state,
677 : const char *name, const char *str)
678 : {
679 0 : if (!str)
680 0 : str = "";
681 0 : result_xml_tag_start (state, name, NULL);
682 0 : result_xml_tag_data (state, str);
683 0 : result_xml_tag_end (state);
684 0 : return 0;
685 : }
686 :
687 :
688 : gpg_error_t
689 0 : result_encrypt_to_xml (gpgme_ctx_t ctx, int indent,
690 : result_xml_write_cb_t cb, void *hook)
691 : {
692 : struct result_xml_state state;
693 0 : gpgme_encrypt_result_t res = gpgme_op_encrypt_result (ctx);
694 : gpgme_invalid_key_t inv_recp;
695 :
696 0 : if (! res)
697 0 : return 0;
698 :
699 0 : result_init (&state, indent, cb, hook);
700 0 : result_xml_tag_start (&state, "encrypt-result", NULL);
701 :
702 0 : inv_recp = res->invalid_recipients;
703 0 : if (inv_recp)
704 : {
705 0 : result_xml_tag_start (&state, "invalid-recipients", NULL);
706 :
707 0 : while (inv_recp)
708 : {
709 0 : result_xml_tag_start (&state, "invalid-key", NULL);
710 0 : if (inv_recp->fpr)
711 0 : result_add_fpr (&state, "fpr", inv_recp->fpr);
712 0 : result_add_error (&state, "reason", inv_recp->reason);
713 0 : result_xml_tag_end (&state);
714 0 : inv_recp = inv_recp->next;
715 : }
716 0 : result_xml_tag_end (&state);
717 : }
718 0 : result_xml_tag_end (&state);
719 :
720 0 : return 0;
721 : }
722 :
723 :
724 : gpg_error_t
725 0 : result_decrypt_to_xml (gpgme_ctx_t ctx, int indent,
726 : result_xml_write_cb_t cb, void *hook)
727 : {
728 : struct result_xml_state state;
729 0 : gpgme_decrypt_result_t res = gpgme_op_decrypt_result (ctx);
730 : gpgme_recipient_t recp;
731 :
732 0 : if (! res)
733 0 : return 0;
734 :
735 0 : result_init (&state, indent, cb, hook);
736 0 : result_xml_tag_start (&state, "decrypt-result", NULL);
737 :
738 0 : if (res->file_name)
739 : {
740 0 : result_xml_tag_start (&state, "file-name", NULL);
741 0 : result_xml_tag_data (&state, res->file_name);
742 0 : result_xml_tag_end (&state);
743 : }
744 0 : if (res->unsupported_algorithm)
745 : {
746 0 : result_xml_tag_start (&state, "unsupported-alogorithm", NULL);
747 0 : result_xml_tag_data (&state, res->unsupported_algorithm);
748 0 : result_xml_tag_end (&state);
749 : }
750 0 : if (res->wrong_key_usage)
751 : {
752 0 : result_xml_tag_start (&state, "wrong-key-usage", NULL);
753 0 : result_xml_tag_end (&state);
754 : }
755 :
756 0 : recp = res->recipients;
757 0 : if (recp)
758 : {
759 0 : result_xml_tag_start (&state, "recipients", NULL);
760 0 : while (recp)
761 : {
762 0 : result_xml_tag_start (&state, "recipient", NULL);
763 0 : result_add_keyid (&state, "keyid", recp->keyid);
764 0 : result_add_pubkey_algo (&state, "pubkey-algo", recp->pubkey_algo);
765 0 : result_add_error (&state, "status", recp->status);
766 0 : result_xml_tag_end (&state);
767 0 : recp = recp->next;
768 : }
769 0 : result_xml_tag_end (&state);
770 : }
771 0 : result_xml_tag_end (&state);
772 :
773 0 : return 0;
774 : }
775 :
776 :
777 : gpg_error_t
778 0 : result_sign_to_xml (gpgme_ctx_t ctx, int indent,
779 : result_xml_write_cb_t cb, void *hook)
780 : {
781 : struct result_xml_state state;
782 0 : gpgme_sign_result_t res = gpgme_op_sign_result (ctx);
783 : gpgme_invalid_key_t inv_key;
784 : gpgme_new_signature_t new_sig;
785 :
786 0 : if (! res)
787 0 : return 0;
788 :
789 0 : result_init (&state, indent, cb, hook);
790 0 : result_xml_tag_start (&state, "sign-result", NULL);
791 :
792 0 : inv_key = res->invalid_signers;
793 0 : if (inv_key)
794 : {
795 0 : result_xml_tag_start (&state, "invalid-signers", NULL);
796 :
797 0 : while (inv_key)
798 : {
799 0 : result_xml_tag_start (&state, "invalid-key", NULL);
800 0 : if (inv_key->fpr)
801 0 : result_add_fpr (&state, "fpr", inv_key->fpr);
802 0 : result_add_error (&state, "reason", inv_key->reason);
803 0 : result_xml_tag_end (&state);
804 0 : inv_key = inv_key->next;
805 : }
806 0 : result_xml_tag_end (&state);
807 : }
808 :
809 0 : new_sig = res->signatures;
810 0 : if (new_sig)
811 : {
812 0 : result_xml_tag_start (&state, "signatures", NULL);
813 :
814 0 : while (new_sig)
815 : {
816 0 : result_xml_tag_start (&state, "new-signature", NULL);
817 0 : result_add_sig_mode (&state, "type", new_sig->type);
818 0 : result_add_pubkey_algo (&state, "pubkey-algo", new_sig->pubkey_algo);
819 0 : result_add_hash_algo (&state, "hash-algo", new_sig->hash_algo);
820 0 : result_add_timestamp (&state, "timestamp", new_sig->timestamp);
821 0 : if (new_sig->fpr)
822 0 : result_add_fpr (&state, "fpr", new_sig->fpr);
823 0 : result_add_value (&state, "sig-class", new_sig->sig_class);
824 :
825 0 : result_xml_tag_end (&state);
826 0 : new_sig = new_sig->next;
827 : }
828 0 : result_xml_tag_end (&state);
829 : }
830 :
831 0 : result_xml_tag_end (&state);
832 :
833 0 : return 0;
834 : }
835 :
836 :
837 : gpg_error_t
838 0 : result_verify_to_xml (gpgme_ctx_t ctx, int indent,
839 : result_xml_write_cb_t cb, void *hook)
840 : {
841 : struct result_xml_state state;
842 0 : gpgme_verify_result_t res = gpgme_op_verify_result (ctx);
843 : gpgme_signature_t sig;
844 :
845 0 : if (! res)
846 0 : return 0;
847 :
848 0 : result_init (&state, indent, cb, hook);
849 0 : result_xml_tag_start (&state, "verify-result", NULL);
850 :
851 0 : if (res->file_name)
852 : {
853 0 : result_xml_tag_start (&state, "file-name", NULL);
854 0 : result_xml_tag_data (&state, res->file_name);
855 0 : result_xml_tag_end (&state);
856 : }
857 :
858 0 : sig = res->signatures;
859 0 : if (sig)
860 : {
861 0 : result_xml_tag_start (&state, "signatures", NULL);
862 :
863 0 : while (sig)
864 : {
865 0 : result_xml_tag_start (&state, "signature", NULL);
866 :
867 : /* FIXME: Could be done better. */
868 0 : result_add_value (&state, "summary", sig->summary);
869 0 : if (sig->fpr)
870 0 : result_add_fpr (&state, "fpr", sig->fpr);
871 0 : result_add_error (&state, "status", sig->status);
872 : /* FIXME: notations */
873 0 : result_add_timestamp (&state, "timestamp", sig->timestamp);
874 0 : result_add_timestamp (&state, "exp-timestamp", sig->exp_timestamp);
875 0 : result_add_value (&state, "wrong-key-usage", sig->wrong_key_usage);
876 0 : result_add_value (&state, "pka-trust", sig->pka_trust);
877 0 : result_add_value (&state, "chain-model", sig->chain_model);
878 0 : result_add_value (&state, "validity", sig->validity);
879 0 : result_add_error (&state, "validity-reason", sig->validity_reason);
880 0 : result_add_pubkey_algo (&state, "pubkey-algo", sig->pubkey_algo);
881 0 : result_add_hash_algo (&state, "hash-algo", sig->hash_algo);
882 0 : if (sig->pka_address)
883 0 : result_add_string (&state, "pka_address", sig->pka_address);
884 :
885 0 : result_xml_tag_end (&state);
886 0 : sig = sig->next;
887 : }
888 0 : result_xml_tag_end (&state);
889 : }
890 :
891 0 : result_xml_tag_end (&state);
892 :
893 0 : return 0;
894 : }
895 :
896 :
897 : gpg_error_t
898 0 : result_import_to_xml (gpgme_ctx_t ctx, int indent,
899 : result_xml_write_cb_t cb, void *hook)
900 : {
901 : struct result_xml_state state;
902 0 : gpgme_import_result_t res = gpgme_op_import_result (ctx);
903 : gpgme_import_status_t stat;
904 :
905 0 : if (! res)
906 0 : return 0;
907 :
908 0 : result_init (&state, indent, cb, hook);
909 0 : result_xml_tag_start (&state, "import-result", NULL);
910 :
911 0 : result_add_value (&state, "considered", res->considered);
912 0 : result_add_value (&state, "no-user-id", res->no_user_id);
913 0 : result_add_value (&state, "imported", res->imported);
914 0 : result_add_value (&state, "imported-rsa", res->imported_rsa);
915 0 : result_add_value (&state, "unchanged", res->unchanged);
916 0 : result_add_value (&state, "new-user-ids", res->new_user_ids);
917 0 : result_add_value (&state, "new-sub-keys", res->new_sub_keys);
918 0 : result_add_value (&state, "new-signatures", res->new_signatures);
919 0 : result_add_value (&state, "new-revocations", res->new_revocations);
920 0 : result_add_value (&state, "secret-read", res->secret_read);
921 0 : result_add_value (&state, "secret-imported", res->secret_imported);
922 0 : result_add_value (&state, "secret-unchanged", res->secret_unchanged);
923 0 : result_add_value (&state, "skipped-new-keys", res->skipped_new_keys);
924 0 : result_add_value (&state, "not-imported", res->not_imported);
925 :
926 0 : stat = res->imports;
927 0 : if (stat)
928 : {
929 0 : result_xml_tag_start (&state, "imports", NULL);
930 :
931 0 : while (stat)
932 : {
933 0 : result_xml_tag_start (&state, "import-status", NULL);
934 :
935 0 : if (stat->fpr)
936 0 : result_add_fpr (&state, "fpr", stat->fpr);
937 0 : result_add_error (&state, "result", stat->result);
938 : /* FIXME: Could be done better. */
939 0 : result_add_value (&state, "status", stat->status);
940 :
941 0 : result_xml_tag_end (&state);
942 0 : stat = stat->next;
943 : }
944 0 : result_xml_tag_end (&state);
945 : }
946 :
947 0 : result_xml_tag_end (&state);
948 :
949 0 : return 0;
950 : }
951 :
952 :
953 : gpg_error_t
954 0 : result_genkey_to_xml (gpgme_ctx_t ctx, int indent,
955 : result_xml_write_cb_t cb, void *hook)
956 : {
957 : struct result_xml_state state;
958 0 : gpgme_genkey_result_t res = gpgme_op_genkey_result (ctx);
959 :
960 0 : if (! res)
961 0 : return 0;
962 :
963 0 : result_init (&state, indent, cb, hook);
964 0 : result_xml_tag_start (&state, "genkey-result", NULL);
965 :
966 0 : result_add_value (&state, "primary", res->primary);
967 0 : result_add_value (&state, "sub", res->sub);
968 0 : if (res->fpr)
969 0 : result_add_fpr (&state, "fpr", res->fpr);
970 :
971 0 : result_xml_tag_end (&state);
972 :
973 0 : return 0;
974 : }
975 :
976 :
977 : gpg_error_t
978 0 : result_keylist_to_xml (gpgme_ctx_t ctx, int indent,
979 : result_xml_write_cb_t cb, void *hook)
980 : {
981 : struct result_xml_state state;
982 0 : gpgme_keylist_result_t res = gpgme_op_keylist_result (ctx);
983 :
984 0 : if (! res)
985 0 : return 0;
986 :
987 0 : result_init (&state, indent, cb, hook);
988 0 : result_xml_tag_start (&state, "keylist-result", NULL);
989 :
990 0 : result_add_value (&state, "truncated", res->truncated);
991 :
992 0 : result_xml_tag_end (&state);
993 :
994 0 : return 0;
995 : }
996 :
997 :
998 : gpg_error_t
999 0 : result_vfs_mount_to_xml (gpgme_ctx_t ctx, int indent,
1000 : result_xml_write_cb_t cb, void *hook)
1001 : {
1002 : struct result_xml_state state;
1003 0 : gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result (ctx);
1004 :
1005 0 : if (! res)
1006 0 : return 0;
1007 :
1008 0 : result_init (&state, indent, cb, hook);
1009 0 : result_xml_tag_start (&state, "vfs-mount-result", NULL);
1010 :
1011 0 : result_add_string (&state, "mount-dir", res->mount_dir);
1012 :
1013 0 : result_xml_tag_end (&state);
1014 :
1015 0 : return 0;
1016 : }
1017 :
1018 :
1019 : typedef enum status
1020 : {
1021 : STATUS_PROTOCOL,
1022 : STATUS_PROGRESS,
1023 : STATUS_ENGINE,
1024 : STATUS_ARMOR,
1025 : STATUS_TEXTMODE,
1026 : STATUS_INCLUDE_CERTS,
1027 : STATUS_KEYLIST_MODE,
1028 : STATUS_RECIPIENT,
1029 : STATUS_ENCRYPT_RESULT,
1030 : STATUS_IDENTIFY_RESULT
1031 : } status_t;
1032 :
1033 : const char *status_string[] =
1034 : {
1035 : "PROTOCOL",
1036 : "PROGRESS",
1037 : "ENGINE",
1038 : "ARMOR",
1039 : "TEXTMODE",
1040 : "INCLUDE_CERTS",
1041 : "KEYLIST_MODE",
1042 : "RECIPIENT",
1043 : "ENCRYPT_RESULT",
1044 : "IDENTIFY_RESULT"
1045 : };
1046 :
1047 : struct gpgme_tool
1048 : {
1049 : gpgme_ctx_t ctx;
1050 : #define MAX_RECIPIENTS 10
1051 : gpgme_key_t recipients[MAX_RECIPIENTS + 1];
1052 : int recipients_nr;
1053 :
1054 : gpg_error_t (*write_status) (void *hook, const char *status, const char *msg);
1055 : void *write_status_hook;
1056 : gpg_error_t (*write_data) (void *hook, const void *buf, size_t len);
1057 : void *write_data_hook;
1058 : };
1059 : typedef struct gpgme_tool *gpgme_tool_t;
1060 :
1061 :
1062 : /* Forward declaration. */
1063 : void gt_write_status (gpgme_tool_t gt,
1064 : status_t status, ...) GT_GCC_A_SENTINEL(0);
1065 : static gpg_error_t
1066 : server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
1067 : int was_bad, int fd);
1068 :
1069 :
1070 : void
1071 0 : _gt_progress_cb (void *opaque, const char *what,
1072 : int type, int current, int total)
1073 : {
1074 0 : gpgme_tool_t gt = opaque;
1075 : char buf[100];
1076 :
1077 0 : snprintf (buf, sizeof (buf), "0x%02x %i %i", type, current, total);
1078 0 : gt_write_status (gt, STATUS_PROGRESS, what, buf, NULL);
1079 0 : }
1080 :
1081 :
1082 : gpg_error_t
1083 0 : _gt_gpgme_new (gpgme_tool_t gt, gpgme_ctx_t *ctx)
1084 : {
1085 : gpg_error_t err;
1086 :
1087 0 : err = gpgme_new (ctx);
1088 0 : if (err)
1089 0 : return err;
1090 0 : gpgme_set_progress_cb (*ctx, _gt_progress_cb, gt);
1091 0 : return 0;
1092 : }
1093 :
1094 :
1095 : void
1096 0 : gt_init (gpgme_tool_t gt)
1097 : {
1098 : gpg_error_t err;
1099 :
1100 0 : memset (gt, '\0', sizeof (*gt));
1101 :
1102 0 : err = _gt_gpgme_new (gt, >->ctx);
1103 0 : if (err)
1104 0 : log_error (1, err, "can't create gpgme context");
1105 0 : }
1106 :
1107 :
1108 : gpg_error_t
1109 0 : gt_signers_add (gpgme_tool_t gt, const char *fpr)
1110 : {
1111 : gpg_error_t err;
1112 : gpgme_key_t key;
1113 :
1114 0 : err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1115 0 : if (err)
1116 0 : return err;
1117 :
1118 0 : return gpgme_signers_add (gt->ctx, key);
1119 : }
1120 :
1121 :
1122 : gpg_error_t
1123 0 : gt_signers_clear (gpgme_tool_t gt)
1124 : {
1125 0 : gpgme_signers_clear (gt->ctx);
1126 0 : return 0;
1127 : }
1128 :
1129 :
1130 : gpg_error_t
1131 0 : gt_get_key (gpgme_tool_t gt, const char *pattern, gpgme_key_t *r_key)
1132 : {
1133 : gpgme_ctx_t ctx;
1134 : gpgme_ctx_t listctx;
1135 : gpgme_error_t err;
1136 : gpgme_key_t key;
1137 :
1138 0 : if (!gt || !r_key || !pattern)
1139 0 : return gpg_error (GPG_ERR_INV_VALUE);
1140 :
1141 0 : ctx = gt->ctx;
1142 :
1143 0 : err = gpgme_new (&listctx);
1144 0 : if (err)
1145 0 : return err;
1146 :
1147 : {
1148 : gpgme_protocol_t proto;
1149 : gpgme_engine_info_t info;
1150 :
1151 : /* Clone the relevant state. */
1152 0 : proto = gpgme_get_protocol (ctx);
1153 : /* The g13 protocol does not allow keylisting, we need to choose
1154 : something else. */
1155 0 : if (proto == GPGME_PROTOCOL_G13)
1156 0 : proto = GPGME_PROTOCOL_OpenPGP;
1157 :
1158 0 : gpgme_set_protocol (listctx, proto);
1159 0 : gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
1160 0 : info = gpgme_ctx_get_engine_info (ctx);
1161 0 : while (info && info->protocol != proto)
1162 0 : info = info->next;
1163 0 : if (info)
1164 0 : gpgme_ctx_set_engine_info (listctx, proto,
1165 0 : info->file_name, info->home_dir);
1166 : }
1167 :
1168 0 : err = gpgme_op_keylist_start (listctx, pattern, 0);
1169 0 : if (!err)
1170 0 : err = gpgme_op_keylist_next (listctx, r_key);
1171 0 : if (!err)
1172 : {
1173 : try_next_key:
1174 0 : err = gpgme_op_keylist_next (listctx, &key);
1175 0 : if (gpgme_err_code (err) == GPG_ERR_EOF)
1176 0 : err = 0;
1177 : else
1178 : {
1179 0 : if (!err
1180 0 : && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
1181 0 : && key && key->subkeys && key->subkeys->fpr
1182 0 : && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
1183 : {
1184 : /* The fingerprint is identical. We assume that this is
1185 : the same key and don't mark it as an ambiguous. This
1186 : problem may occur with corrupted keyrings and has
1187 : been noticed often with gpgsm. In fact gpgsm uses a
1188 : similar hack to sort out such duplicates but it can't
1189 : do that while listing keys. */
1190 0 : gpgme_key_unref (key);
1191 0 : goto try_next_key;
1192 : }
1193 0 : if (!err)
1194 : {
1195 0 : gpgme_key_unref (key);
1196 0 : err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
1197 : }
1198 0 : gpgme_key_unref (*r_key);
1199 : }
1200 : }
1201 0 : gpgme_release (listctx);
1202 :
1203 0 : if (! err)
1204 0 : gt_write_status (gt, STATUS_RECIPIENT,
1205 0 : ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
1206 0 : (*r_key)->subkeys->fpr : "invalid", NULL);
1207 0 : return err;
1208 : }
1209 :
1210 :
1211 : gpg_error_t
1212 0 : gt_recipients_add (gpgme_tool_t gt, const char *pattern)
1213 : {
1214 : gpg_error_t err;
1215 : gpgme_key_t key;
1216 :
1217 0 : if (gt->recipients_nr >= MAX_RECIPIENTS)
1218 0 : return gpg_error (GPG_ERR_ENOMEM);
1219 :
1220 0 : if (gpgme_get_protocol (gt->ctx) == GPGME_PROTOCOL_UISERVER)
1221 0 : err = gpgme_key_from_uid (&key, pattern);
1222 : else
1223 0 : err = gt_get_key (gt, pattern, &key);
1224 0 : if (err)
1225 0 : return err;
1226 :
1227 0 : gt->recipients[gt->recipients_nr++] = key;
1228 0 : return 0;
1229 : }
1230 :
1231 :
1232 : void
1233 0 : gt_recipients_clear (gpgme_tool_t gt)
1234 : {
1235 : int idx;
1236 :
1237 0 : for (idx = 0; idx < gt->recipients_nr; idx++)
1238 0 : gpgme_key_unref (gt->recipients[idx]);
1239 0 : memset (gt->recipients, '\0', gt->recipients_nr * sizeof (gpgme_key_t));
1240 0 : gt->recipients_nr = 0;
1241 0 : }
1242 :
1243 :
1244 : gpg_error_t
1245 0 : gt_reset (gpgme_tool_t gt)
1246 : {
1247 : gpg_error_t err;
1248 : gpgme_ctx_t ctx;
1249 :
1250 0 : err = _gt_gpgme_new (gt, &ctx);
1251 0 : if (err)
1252 0 : return err;
1253 :
1254 0 : gpgme_release (gt->ctx);
1255 0 : gt->ctx = ctx;
1256 0 : gt_recipients_clear (gt);
1257 0 : return 0;
1258 : }
1259 :
1260 :
1261 : void
1262 0 : gt_write_status (gpgme_tool_t gt, status_t status, ...)
1263 : {
1264 : va_list ap;
1265 : const char *text;
1266 : char buf[950];
1267 : char *p;
1268 : size_t n;
1269 : gpg_error_t err;
1270 :
1271 0 : va_start (ap, status);
1272 0 : p = buf;
1273 0 : n = 0;
1274 0 : while ((text = va_arg (ap, const char *)))
1275 : {
1276 0 : if (n)
1277 : {
1278 0 : *p++ = ' ';
1279 0 : n++;
1280 : }
1281 0 : while (*text && n < sizeof (buf) - 2)
1282 : {
1283 0 : *p++ = *text++;
1284 0 : n++;
1285 : }
1286 : }
1287 0 : *p = 0;
1288 0 : va_end (ap);
1289 :
1290 0 : err = gt->write_status (gt->write_status_hook, status_string[status], buf);
1291 0 : if (err)
1292 0 : log_error (1, err, "can't write status line");
1293 0 : }
1294 :
1295 :
1296 : gpg_error_t
1297 0 : gt_write_data (gpgme_tool_t gt, const void *buf, size_t len)
1298 : {
1299 0 : return gt->write_data (gt->write_data_hook, buf, len);
1300 : }
1301 :
1302 :
1303 : gpg_error_t
1304 0 : gt_get_engine_info (gpgme_tool_t gt, gpgme_protocol_t proto)
1305 : {
1306 : gpgme_engine_info_t info;
1307 0 : info = gpgme_ctx_get_engine_info (gt->ctx);
1308 0 : while (info)
1309 : {
1310 0 : if (proto == GPGME_PROTOCOL_UNKNOWN || proto == info->protocol)
1311 0 : gt_write_status (gt, STATUS_ENGINE,
1312 : gpgme_get_protocol_name (info->protocol),
1313 : info->file_name, info->version,
1314 : info->req_version, info->home_dir, NULL);
1315 0 : info = info->next;
1316 : }
1317 0 : return 0;
1318 : }
1319 :
1320 :
1321 : gpgme_protocol_t
1322 0 : gt_protocol_from_name (const char *name)
1323 : {
1324 0 : if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_OpenPGP)))
1325 0 : return GPGME_PROTOCOL_OpenPGP;
1326 0 : if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_CMS)))
1327 0 : return GPGME_PROTOCOL_CMS;
1328 0 : if (! strcasecmp (name,gpgme_get_protocol_name (GPGME_PROTOCOL_GPGCONF)))
1329 0 : return GPGME_PROTOCOL_GPGCONF;
1330 0 : if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_ASSUAN)))
1331 0 : return GPGME_PROTOCOL_ASSUAN;
1332 0 : if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_G13)))
1333 0 : return GPGME_PROTOCOL_G13;
1334 0 : if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_UISERVER)))
1335 0 : return GPGME_PROTOCOL_UISERVER;
1336 0 : if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_SPAWN)))
1337 0 : return GPGME_PROTOCOL_SPAWN;
1338 0 : if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_DEFAULT)))
1339 0 : return GPGME_PROTOCOL_DEFAULT;
1340 0 : return GPGME_PROTOCOL_UNKNOWN;
1341 : }
1342 :
1343 :
1344 : gpg_error_t
1345 0 : gt_set_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
1346 : {
1347 0 : return gpgme_set_protocol (gt->ctx, proto);
1348 : }
1349 :
1350 :
1351 : gpg_error_t
1352 0 : gt_get_protocol (gpgme_tool_t gt)
1353 : {
1354 0 : gpgme_protocol_t proto = gpgme_get_protocol (gt->ctx);
1355 :
1356 0 : gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
1357 : NULL);
1358 :
1359 0 : return 0;
1360 : }
1361 :
1362 :
1363 : gpg_error_t
1364 0 : gt_set_sub_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
1365 : {
1366 0 : return gpgme_set_sub_protocol (gt->ctx, proto);
1367 : }
1368 :
1369 :
1370 : gpg_error_t
1371 0 : gt_get_sub_protocol (gpgme_tool_t gt)
1372 : {
1373 0 : gpgme_protocol_t proto = gpgme_get_sub_protocol (gt->ctx);
1374 :
1375 0 : gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
1376 : NULL);
1377 :
1378 0 : return 0;
1379 : }
1380 :
1381 :
1382 : gpg_error_t
1383 0 : gt_set_pinentry_mode (gpgme_tool_t gt, gpgme_pinentry_mode_t mode, void *opaque)
1384 : {
1385 : gpg_error_t err;
1386 :
1387 0 : gpgme_set_passphrase_cb (gt->ctx, NULL, NULL);
1388 0 : err = gpgme_set_pinentry_mode (gt->ctx, mode);
1389 0 : if (!err && mode == GPGME_PINENTRY_MODE_LOOPBACK)
1390 0 : gpgme_set_passphrase_cb (gt->ctx, server_passphrase_cb, opaque);
1391 0 : return err;
1392 : }
1393 :
1394 :
1395 : gpg_error_t
1396 0 : gt_set_armor (gpgme_tool_t gt, int armor)
1397 : {
1398 0 : gpgme_set_armor (gt->ctx, armor);
1399 0 : return 0;
1400 : }
1401 :
1402 :
1403 : gpg_error_t
1404 0 : gt_get_armor (gpgme_tool_t gt)
1405 : {
1406 0 : gt_write_status (gt, STATUS_ARMOR,
1407 0 : gpgme_get_armor (gt->ctx) ? "true" : "false", NULL);
1408 :
1409 0 : return 0;
1410 : }
1411 :
1412 :
1413 : gpg_error_t
1414 0 : gt_set_textmode (gpgme_tool_t gt, int textmode)
1415 : {
1416 0 : gpgme_set_textmode (gt->ctx, textmode);
1417 0 : return 0;
1418 : }
1419 :
1420 :
1421 : gpg_error_t
1422 0 : gt_get_textmode (gpgme_tool_t gt)
1423 : {
1424 0 : gt_write_status (gt, STATUS_TEXTMODE,
1425 0 : gpgme_get_textmode (gt->ctx) ? "true" : "false", NULL);
1426 :
1427 0 : return 0;
1428 : }
1429 :
1430 :
1431 : gpg_error_t
1432 0 : gt_set_keylist_mode (gpgme_tool_t gt, gpgme_keylist_mode_t keylist_mode)
1433 : {
1434 0 : gpgme_set_keylist_mode (gt->ctx, keylist_mode);
1435 0 : return 0;
1436 : }
1437 :
1438 :
1439 : gpg_error_t
1440 0 : gt_get_keylist_mode (gpgme_tool_t gt)
1441 : {
1442 : #define NR_KEYLIST_MODES 6
1443 : const char *modes[NR_KEYLIST_MODES + 1];
1444 0 : int idx = 0;
1445 0 : gpgme_keylist_mode_t mode = gpgme_get_keylist_mode (gt->ctx);
1446 :
1447 0 : if (mode & GPGME_KEYLIST_MODE_LOCAL)
1448 0 : modes[idx++] = "local";
1449 0 : if (mode & GPGME_KEYLIST_MODE_EXTERN)
1450 0 : modes[idx++] = "extern";
1451 0 : if (mode & GPGME_KEYLIST_MODE_SIGS)
1452 0 : modes[idx++] = "sigs";
1453 0 : if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS)
1454 0 : modes[idx++] = "sig_notations";
1455 0 : if (mode & GPGME_KEYLIST_MODE_WITH_SECRET)
1456 0 : modes[idx++] = "with_secret";
1457 0 : if (mode & GPGME_KEYLIST_MODE_EPHEMERAL)
1458 0 : modes[idx++] = "ephemeral";
1459 0 : if (mode & GPGME_KEYLIST_MODE_VALIDATE)
1460 0 : modes[idx++] = "validate";
1461 0 : modes[idx++] = NULL;
1462 :
1463 0 : gt_write_status (gt, STATUS_KEYLIST_MODE, modes[0], modes[1], modes[2],
1464 : modes[3], modes[4], modes[5], modes[6], NULL);
1465 :
1466 0 : return 0;
1467 : }
1468 :
1469 :
1470 : gpg_error_t
1471 0 : gt_set_include_certs (gpgme_tool_t gt, int include_certs)
1472 : {
1473 0 : gpgme_set_include_certs (gt->ctx, include_certs);
1474 0 : return 0;
1475 : }
1476 :
1477 :
1478 : gpg_error_t
1479 0 : gt_get_include_certs (gpgme_tool_t gt)
1480 : {
1481 0 : int include_certs = gpgme_get_include_certs (gt->ctx);
1482 : char buf[100];
1483 :
1484 0 : if (include_certs == GPGME_INCLUDE_CERTS_DEFAULT)
1485 0 : strcpy (buf, "default");
1486 : else
1487 0 : snprintf (buf, sizeof (buf), "%i", include_certs);
1488 :
1489 0 : gt_write_status (gt, STATUS_INCLUDE_CERTS, buf, NULL);
1490 :
1491 0 : return 0;
1492 : }
1493 :
1494 :
1495 : gpg_error_t
1496 0 : gt_decrypt_verify (gpgme_tool_t gt, gpgme_data_t cipher, gpgme_data_t plain,
1497 : int verify)
1498 : {
1499 0 : if (verify)
1500 0 : return gpgme_op_decrypt_verify (gt->ctx, cipher, plain);
1501 : else
1502 0 : return gpgme_op_decrypt (gt->ctx, cipher, plain);
1503 : }
1504 :
1505 :
1506 : gpg_error_t
1507 0 : gt_sign_encrypt (gpgme_tool_t gt, gpgme_encrypt_flags_t flags,
1508 : gpgme_data_t plain, gpgme_data_t cipher, int sign)
1509 : {
1510 : gpg_error_t err;
1511 : gpgme_key_t *recp;
1512 :
1513 0 : recp = gt->recipients_nr? gt->recipients : NULL;
1514 :
1515 0 : if (sign)
1516 0 : err = gpgme_op_encrypt_sign (gt->ctx, recp, flags, plain, cipher);
1517 : else
1518 0 : err = gpgme_op_encrypt (gt->ctx, recp, flags, plain, cipher);
1519 :
1520 0 : gt_recipients_clear (gt);
1521 :
1522 0 : return err;
1523 : }
1524 :
1525 :
1526 : gpg_error_t
1527 0 : gt_sign (gpgme_tool_t gt, gpgme_data_t plain, gpgme_data_t sig,
1528 : gpgme_sig_mode_t mode)
1529 : {
1530 0 : return gpgme_op_sign (gt->ctx, plain, sig, mode);
1531 : }
1532 :
1533 :
1534 : gpg_error_t
1535 0 : gt_verify (gpgme_tool_t gt, gpgme_data_t sig, gpgme_data_t sig_text,
1536 : gpgme_data_t plain)
1537 : {
1538 0 : return gpgme_op_verify (gt->ctx, sig, sig_text, plain);
1539 : }
1540 :
1541 :
1542 : gpg_error_t
1543 0 : gt_import (gpgme_tool_t gt, gpgme_data_t data)
1544 : {
1545 0 : return gpgme_op_import (gt->ctx, data);
1546 : }
1547 :
1548 :
1549 : gpg_error_t
1550 0 : gt_export (gpgme_tool_t gt, const char *pattern[], gpgme_export_mode_t mode,
1551 : gpgme_data_t data)
1552 : {
1553 0 : return gpgme_op_export_ext (gt->ctx, pattern, mode, data);
1554 : }
1555 :
1556 :
1557 : gpg_error_t
1558 0 : gt_genkey (gpgme_tool_t gt, const char *parms, gpgme_data_t public,
1559 : gpgme_data_t secret)
1560 : {
1561 0 : return gpgme_op_genkey (gt->ctx, parms, public, secret);
1562 : }
1563 :
1564 :
1565 : gpg_error_t
1566 0 : gt_import_keys (gpgme_tool_t gt, char *fpr[])
1567 : {
1568 0 : gpg_error_t err = 0;
1569 : int cnt;
1570 : int idx;
1571 : gpgme_key_t *keys;
1572 :
1573 0 : cnt = 0;
1574 0 : while (fpr[cnt])
1575 0 : cnt++;
1576 :
1577 0 : if (! cnt)
1578 0 : return gpg_error (GPG_ERR_INV_VALUE);
1579 :
1580 0 : keys = malloc ((cnt + 1) * sizeof (gpgme_key_t));
1581 0 : if (! keys)
1582 0 : return gpg_error_from_syserror ();
1583 :
1584 0 : for (idx = 0; idx < cnt; idx++)
1585 : {
1586 0 : err = gpgme_get_key (gt->ctx, fpr[idx], &keys[idx], 0);
1587 0 : if (err)
1588 0 : break;
1589 : }
1590 0 : if (! err)
1591 : {
1592 0 : keys[cnt] = NULL;
1593 0 : err = gpgme_op_import_keys (gt->ctx, keys);
1594 : }
1595 :
1596 : /* Rollback. */
1597 0 : while (--idx >= 0)
1598 0 : gpgme_key_unref (keys[idx]);
1599 0 : free (keys);
1600 :
1601 0 : return err;
1602 : }
1603 :
1604 :
1605 : gpg_error_t
1606 0 : gt_delete (gpgme_tool_t gt, char *fpr, int allow_secret)
1607 : {
1608 : gpg_error_t err;
1609 : gpgme_key_t key;
1610 :
1611 0 : err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1612 0 : if (err)
1613 0 : return err;
1614 :
1615 0 : err = gpgme_op_delete (gt->ctx, key, allow_secret);
1616 0 : gpgme_key_unref (key);
1617 0 : return err;
1618 : }
1619 :
1620 :
1621 : gpg_error_t
1622 0 : gt_keylist_start (gpgme_tool_t gt, const char *pattern[], int secret_only)
1623 : {
1624 0 : return gpgme_op_keylist_ext_start (gt->ctx, pattern, secret_only, 0);
1625 : }
1626 :
1627 :
1628 : gpg_error_t
1629 0 : gt_keylist_next (gpgme_tool_t gt, gpgme_key_t *key)
1630 : {
1631 0 : return gpgme_op_keylist_next (gt->ctx, key);
1632 : }
1633 :
1634 :
1635 : gpg_error_t
1636 0 : gt_getauditlog (gpgme_tool_t gt, gpgme_data_t output, unsigned int flags)
1637 : {
1638 0 : return gpgme_op_getauditlog (gt->ctx, output, flags);
1639 : }
1640 :
1641 :
1642 : gpg_error_t
1643 0 : gt_vfs_mount (gpgme_tool_t gt, const char *container_file,
1644 : const char *mount_dir, int flags)
1645 : {
1646 : gpg_error_t err;
1647 : gpg_error_t op_err;
1648 0 : err = gpgme_op_vfs_mount (gt->ctx, container_file, mount_dir, flags, &op_err);
1649 0 : return err ? err : op_err;
1650 : }
1651 :
1652 :
1653 : gpg_error_t
1654 0 : gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
1655 : {
1656 : gpg_error_t err;
1657 : gpg_error_t op_err;
1658 0 : err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file,
1659 : flags, &op_err);
1660 0 : gt_recipients_clear (gt);
1661 0 : return err ? err : op_err;
1662 : }
1663 :
1664 :
1665 : gpg_error_t
1666 0 : gt_passwd (gpgme_tool_t gt, char *fpr)
1667 : {
1668 : gpg_error_t err;
1669 : gpgme_key_t key;
1670 :
1671 0 : err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1672 0 : if (err)
1673 0 : return gpg_err_code (err) == GPG_ERR_EOF? gpg_error (GPG_ERR_NO_PUBKEY):err;
1674 :
1675 0 : err = gpgme_op_passwd (gt->ctx, key, 0);
1676 0 : gpgme_key_unref (key);
1677 0 : return err;
1678 : }
1679 :
1680 :
1681 : gpg_error_t
1682 0 : gt_identify (gpgme_tool_t gt, gpgme_data_t data)
1683 : {
1684 0 : const char *s = "?";
1685 :
1686 0 : switch (gpgme_data_identify (data, 0))
1687 : {
1688 0 : case GPGME_DATA_TYPE_INVALID: return gpg_error (GPG_ERR_GENERAL);
1689 0 : case GPGME_DATA_TYPE_UNKNOWN : s = "unknown"; break;
1690 0 : case GPGME_DATA_TYPE_PGP_SIGNED : s = "PGP-signed"; break;
1691 0 : case GPGME_DATA_TYPE_PGP_SIGNATURE: s = "PGP-signature"; break;
1692 0 : case GPGME_DATA_TYPE_PGP_ENCRYPTED: s = "PGP-encrypted"; break;
1693 0 : case GPGME_DATA_TYPE_PGP_OTHER : s = "PGP"; break;
1694 0 : case GPGME_DATA_TYPE_PGP_KEY : s = "PGP-key"; break;
1695 0 : case GPGME_DATA_TYPE_CMS_SIGNED : s = "CMS-signed"; break;
1696 0 : case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
1697 0 : case GPGME_DATA_TYPE_CMS_OTHER : s = "CMS"; break;
1698 0 : case GPGME_DATA_TYPE_X509_CERT : s = "X.509"; break;
1699 0 : case GPGME_DATA_TYPE_PKCS12 : s = "PKCS12"; break;
1700 : }
1701 0 : gt_write_status (gt, STATUS_IDENTIFY_RESULT, s, NULL);
1702 0 : return 0;
1703 : }
1704 :
1705 :
1706 : gpg_error_t
1707 0 : gt_spawn (gpgme_tool_t gt, const char *pgm,
1708 : gpgme_data_t inp, gpgme_data_t outp)
1709 : {
1710 : gpg_error_t err;
1711 :
1712 0 : err = gpgme_op_spawn (gt->ctx, pgm, NULL, inp, outp, outp, 0);
1713 :
1714 0 : return err;
1715 : }
1716 :
1717 :
1718 : #define GT_RESULT_ENCRYPT 0x1
1719 : #define GT_RESULT_DECRYPT 0x2
1720 : #define GT_RESULT_SIGN 0x4
1721 : #define GT_RESULT_VERIFY 0x8
1722 : #define GT_RESULT_IMPORT 0x10
1723 : #define GT_RESULT_GENKEY 0x20
1724 : #define GT_RESULT_KEYLIST 0x40
1725 : #define GT_RESULT_VFS_MOUNT 0x80
1726 : #define GT_RESULT_ALL (~0U)
1727 :
1728 : gpg_error_t
1729 0 : gt_result (gpgme_tool_t gt, unsigned int flags)
1730 : {
1731 0 : int indent = 2;
1732 :
1733 0 : gt_write_data (gt, xml_preamble1, strlen (xml_preamble1));
1734 0 : gt_write_data (gt, NULL, 0);
1735 0 : gt_write_data (gt, xml_preamble2, strlen (xml_preamble2));
1736 0 : gt_write_data (gt, NULL, 0);
1737 0 : if (flags & GT_RESULT_ENCRYPT)
1738 0 : result_encrypt_to_xml (gt->ctx, indent,
1739 : (result_xml_write_cb_t) gt_write_data, gt);
1740 0 : if (flags & GT_RESULT_DECRYPT)
1741 0 : result_decrypt_to_xml (gt->ctx, indent,
1742 : (result_xml_write_cb_t) gt_write_data, gt);
1743 0 : if (flags & GT_RESULT_SIGN)
1744 0 : result_sign_to_xml (gt->ctx, indent,
1745 : (result_xml_write_cb_t) gt_write_data, gt);
1746 0 : if (flags & GT_RESULT_VERIFY)
1747 0 : result_verify_to_xml (gt->ctx, indent,
1748 : (result_xml_write_cb_t) gt_write_data, gt);
1749 0 : if (flags & GT_RESULT_IMPORT)
1750 0 : result_import_to_xml (gt->ctx, indent,
1751 : (result_xml_write_cb_t) gt_write_data, gt);
1752 0 : if (flags & GT_RESULT_GENKEY)
1753 0 : result_genkey_to_xml (gt->ctx, indent,
1754 : (result_xml_write_cb_t) gt_write_data, gt);
1755 0 : if (flags & GT_RESULT_KEYLIST)
1756 0 : result_keylist_to_xml (gt->ctx, indent,
1757 : (result_xml_write_cb_t) gt_write_data, gt);
1758 0 : if (flags & GT_RESULT_VFS_MOUNT)
1759 0 : result_vfs_mount_to_xml (gt->ctx, indent,
1760 : (result_xml_write_cb_t) gt_write_data, gt);
1761 0 : gt_write_data (gt, xml_end, strlen (xml_end));
1762 :
1763 0 : return 0;
1764 : }
1765 :
1766 :
1767 : /* GPGME SERVER. */
1768 :
1769 : #include <assuan.h>
1770 :
1771 : struct server
1772 : {
1773 : gpgme_tool_t gt;
1774 : assuan_context_t assuan_ctx;
1775 :
1776 : gpgme_data_encoding_t input_enc;
1777 : gpgme_data_encoding_t output_enc;
1778 : assuan_fd_t input_fd;
1779 : char *input_filename;
1780 : FILE *input_stream;
1781 : assuan_fd_t output_fd;
1782 : char *output_filename;
1783 : FILE *output_stream;
1784 : assuan_fd_t message_fd;
1785 : char *message_filename;
1786 : FILE *message_stream;
1787 : gpgme_data_encoding_t message_enc;
1788 : };
1789 :
1790 :
1791 : gpg_error_t
1792 0 : server_write_status (void *hook, const char *status, const char *msg)
1793 : {
1794 0 : struct server *server = hook;
1795 0 : return assuan_write_status (server->assuan_ctx, status, msg);
1796 : }
1797 :
1798 :
1799 : gpg_error_t
1800 0 : server_write_data (void *hook, const void *buf, size_t len)
1801 : {
1802 0 : struct server *server = hook;
1803 0 : return assuan_send_data (server->assuan_ctx, buf, len);
1804 : }
1805 :
1806 :
1807 : static gpg_error_t
1808 0 : server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
1809 : int was_bad, int fd)
1810 : {
1811 0 : struct server *server = opaque;
1812 : gpg_error_t err;
1813 0 : unsigned char *buf = NULL;
1814 0 : size_t buflen = 0;
1815 :
1816 : (void)was_bad;
1817 :
1818 0 : if (server && server->assuan_ctx)
1819 : {
1820 0 : if (uid_hint)
1821 0 : assuan_write_status (server->assuan_ctx, "USERID_HINT", uid_hint);
1822 0 : if (info)
1823 0 : assuan_write_status (server->assuan_ctx, "NEED_PASSPHRASE", info);
1824 :
1825 0 : err = assuan_inquire (server->assuan_ctx, "PASSPHRASE",
1826 : &buf, &buflen, 100);
1827 : }
1828 : else
1829 0 : err = gpg_error (GPG_ERR_NO_PASSPHRASE);
1830 :
1831 0 : if (!err)
1832 : {
1833 : /* We take care to always send a LF. */
1834 0 : if (gpgme_io_writen (fd, buf, buflen))
1835 0 : err = gpg_error_from_syserror ();
1836 0 : else if (!memchr (buf, '\n', buflen) && gpgme_io_writen (fd, "\n", 1))
1837 0 : err = gpg_error_from_syserror ();
1838 : }
1839 0 : free (buf);
1840 0 : return err;
1841 : }
1842 :
1843 :
1844 : /* Wrapper around assuan_command_parse_fd to also handle a
1845 : "file=FILENAME" argument. On success either a filename is returned
1846 : at FILENAME or a file descriptor at RFD; the other one is set to
1847 : NULL respective ASSUAN_INVALID_FD. */
1848 : static gpg_error_t
1849 0 : server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd,
1850 : char **filename)
1851 : {
1852 0 : *rfd = ASSUAN_INVALID_FD;
1853 0 : *filename = NULL;
1854 :
1855 0 : if (! strncasecmp (line, "file=", 5))
1856 : {
1857 : char *term;
1858 0 : *filename = strdup (line + 5);
1859 0 : if (!*filename)
1860 0 : return gpg_error_from_syserror();
1861 0 : term = strchr (*filename, ' ');
1862 0 : if (term)
1863 0 : *term = '\0';
1864 0 : return 0;
1865 : }
1866 : else
1867 0 : return assuan_command_parse_fd (ctx, line, rfd);
1868 : }
1869 :
1870 :
1871 : static gpgme_data_encoding_t
1872 0 : server_data_encoding (const char *line)
1873 : {
1874 0 : if (strstr (line, "--binary"))
1875 0 : return GPGME_DATA_ENCODING_BINARY;
1876 0 : if (strstr (line, "--base64"))
1877 0 : return GPGME_DATA_ENCODING_BASE64;
1878 0 : if (strstr (line, "--armor"))
1879 0 : return GPGME_DATA_ENCODING_ARMOR;
1880 0 : if (strstr (line, "--url"))
1881 0 : return GPGME_DATA_ENCODING_URL;
1882 0 : if (strstr (line, "--urlesc"))
1883 0 : return GPGME_DATA_ENCODING_URLESC;
1884 0 : if (strstr (line, "--url0"))
1885 0 : return GPGME_DATA_ENCODING_URL0;
1886 0 : if (strstr (line, "--mime"))
1887 0 : return GPGME_DATA_ENCODING_MIME;
1888 0 : return GPGME_DATA_ENCODING_NONE;
1889 : }
1890 :
1891 :
1892 : static gpgme_error_t
1893 0 : server_data_obj (assuan_fd_t fd, char *fn, int out,
1894 : gpgme_data_encoding_t encoding,
1895 : gpgme_data_t *data, FILE **fs)
1896 : {
1897 : gpgme_error_t err;
1898 :
1899 0 : *fs = NULL;
1900 0 : if (fn)
1901 : {
1902 0 : *fs = fopen (fn, out ? "wb" : "rb");
1903 0 : if (!*fs)
1904 0 : return gpg_error_from_syserror ();
1905 :
1906 0 : err = gpgme_data_new_from_stream (data, *fs);
1907 : }
1908 : else
1909 0 : err = gpgme_data_new_from_fd (data, (int) fd);
1910 :
1911 0 : if (err)
1912 0 : return err;
1913 0 : return gpgme_data_set_encoding (*data, encoding);
1914 : }
1915 :
1916 :
1917 : void
1918 0 : server_reset_fds (struct server *server)
1919 : {
1920 : /* assuan closes the input and output FDs for us when doing a RESET,
1921 : but we use this same function after commands, so repeat it
1922 : here. */
1923 0 : if (server->input_fd != ASSUAN_INVALID_FD)
1924 : {
1925 : #if HAVE_W32_SYSTEM
1926 : CloseHandle (server->input_fd);
1927 : #else
1928 0 : close (server->input_fd);
1929 : #endif
1930 0 : server->input_fd = ASSUAN_INVALID_FD;
1931 : }
1932 0 : if (server->output_fd != ASSUAN_INVALID_FD)
1933 : {
1934 : #if HAVE_W32_SYSTEM
1935 : CloseHandle (server->output_fd);
1936 : #else
1937 0 : close (server->output_fd);
1938 : #endif
1939 0 : server->output_fd = ASSUAN_INVALID_FD;
1940 : }
1941 0 : if (server->message_fd != ASSUAN_INVALID_FD)
1942 : {
1943 : /* FIXME: Assuan should provide a close function. */
1944 : #if HAVE_W32_SYSTEM
1945 : CloseHandle (server->message_fd);
1946 : #else
1947 0 : close (server->message_fd);
1948 : #endif
1949 0 : server->message_fd = ASSUAN_INVALID_FD;
1950 : }
1951 0 : if (server->input_filename)
1952 : {
1953 0 : free (server->input_filename);
1954 0 : server->input_filename = NULL;
1955 : }
1956 0 : if (server->output_filename)
1957 : {
1958 0 : free (server->output_filename);
1959 0 : server->output_filename = NULL;
1960 : }
1961 0 : if (server->message_filename)
1962 : {
1963 0 : free (server->message_filename);
1964 0 : server->message_filename = NULL;
1965 : }
1966 0 : if (server->input_stream)
1967 : {
1968 0 : fclose (server->input_stream);
1969 0 : server->input_stream = NULL;
1970 : }
1971 0 : if (server->output_stream)
1972 : {
1973 0 : fclose (server->output_stream);
1974 0 : server->output_stream = NULL;
1975 : }
1976 0 : if (server->message_stream)
1977 : {
1978 0 : fclose (server->message_stream);
1979 0 : server->message_stream = NULL;
1980 : }
1981 :
1982 0 : server->input_enc = GPGME_DATA_ENCODING_NONE;
1983 0 : server->output_enc = GPGME_DATA_ENCODING_NONE;
1984 0 : server->message_enc = GPGME_DATA_ENCODING_NONE;
1985 0 : }
1986 :
1987 :
1988 : static gpg_error_t
1989 0 : reset_notify (assuan_context_t ctx, char *line)
1990 : {
1991 0 : struct server *server = assuan_get_pointer (ctx);
1992 :
1993 : (void)line;
1994 :
1995 0 : server_reset_fds (server);
1996 0 : gt_reset (server->gt);
1997 0 : return 0;
1998 : }
1999 :
2000 :
2001 : static const char hlp_version[] =
2002 : "VERSION [<string>]\n"
2003 : "\n"
2004 : "Call the function gpgme_check_version.";
2005 : static gpg_error_t
2006 0 : cmd_version (assuan_context_t ctx, char *line)
2007 : {
2008 0 : if (line && *line)
2009 : {
2010 0 : const char *version = gpgme_check_version (line);
2011 0 : return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
2012 : }
2013 : else
2014 : {
2015 0 : const char *version = gpgme_check_version (NULL);
2016 0 : return assuan_send_data (ctx, version, strlen (version));
2017 : }
2018 : }
2019 :
2020 :
2021 : static const char hlp_engine[] =
2022 : "ENGINE [<string>]\n"
2023 : "\n"
2024 : "Get information about a GPGME engine (a.k.a. protocol).";
2025 : static gpg_error_t
2026 0 : cmd_engine (assuan_context_t ctx, char *line)
2027 : {
2028 0 : struct server *server = assuan_get_pointer (ctx);
2029 0 : return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
2030 : }
2031 :
2032 :
2033 : static const char hlp_protocol[] =
2034 : "PROTOCOL [<name>]\n"
2035 : "\n"
2036 : "With NAME, set the protocol. Without, return the current\n"
2037 : "protocol.";
2038 : static gpg_error_t
2039 0 : cmd_protocol (assuan_context_t ctx, char *line)
2040 : {
2041 0 : struct server *server = assuan_get_pointer (ctx);
2042 0 : if (line && *line)
2043 0 : return gt_set_protocol (server->gt, gt_protocol_from_name (line));
2044 : else
2045 0 : return gt_get_protocol (server->gt);
2046 : }
2047 :
2048 :
2049 : static const char hlp_sub_protocol[] =
2050 : "SUB_PROTOCOL [<name>]\n"
2051 : "\n"
2052 : "With NAME, set the sub-protocol. Without, return the\n"
2053 : "current sub-protocol.";
2054 : static gpg_error_t
2055 0 : cmd_sub_protocol (assuan_context_t ctx, char *line)
2056 : {
2057 0 : struct server *server = assuan_get_pointer (ctx);
2058 0 : if (line && *line)
2059 0 : return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
2060 : else
2061 0 : return gt_get_sub_protocol (server->gt);
2062 : }
2063 :
2064 :
2065 : static const char hlp_pinentry_mode[] =
2066 : "PINENTRY_MODE <name>\n"
2067 : "\n"
2068 : "Set the pinentry mode to NAME. Allowedvalues for NAME are:\n"
2069 : " default - reset to the default of the engine,\n"
2070 : " ask - force the use of the pinentry,\n"
2071 : " cancel - emulate use of pinentry's cancel button,\n"
2072 : " error - return a pinentry error,\n"
2073 : " loopback - redirect pinentry queries to the caller.\n"
2074 : "Note that only recent versions of GPG support changing the pinentry mode.";
2075 : static gpg_error_t
2076 0 : cmd_pinentry_mode (assuan_context_t ctx, char *line)
2077 : {
2078 0 : struct server *server = assuan_get_pointer (ctx);
2079 : gpgme_pinentry_mode_t mode;
2080 :
2081 0 : if (!line || !*line || !strcmp (line, "default"))
2082 0 : mode = GPGME_PINENTRY_MODE_DEFAULT;
2083 0 : else if (!strcmp (line, "ask"))
2084 0 : mode = GPGME_PINENTRY_MODE_ASK;
2085 0 : else if (!strcmp (line, "cancel"))
2086 0 : mode = GPGME_PINENTRY_MODE_CANCEL;
2087 0 : else if (!strcmp (line, "error"))
2088 0 : mode = GPGME_PINENTRY_MODE_ERROR;
2089 0 : else if (!strcmp (line, "loopback"))
2090 0 : mode = GPGME_PINENTRY_MODE_LOOPBACK;
2091 : else
2092 0 : return gpg_error (GPG_ERR_INV_VALUE);
2093 :
2094 0 : return gt_set_pinentry_mode (server->gt, mode, server);
2095 : }
2096 :
2097 :
2098 : static const char hlp_armor[] =
2099 : "ARMOR [true|false]\n"
2100 : "\n"
2101 : "With 'true' or 'false', turn output ASCII armoring on or\n"
2102 : "off. Without, return the current armoring status.";
2103 : static gpg_error_t
2104 0 : cmd_armor (assuan_context_t ctx, char *line)
2105 : {
2106 0 : struct server *server = assuan_get_pointer (ctx);
2107 0 : if (line && *line)
2108 : {
2109 0 : int flag = 0;
2110 :
2111 0 : if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2112 0 : || line[0] == '1')
2113 0 : flag = 1;
2114 :
2115 0 : return gt_set_armor (server->gt, flag);
2116 : }
2117 : else
2118 0 : return gt_get_armor (server->gt);
2119 : }
2120 :
2121 :
2122 : static const char hlp_textmode[] =
2123 : "TEXTMODE [true|false]\n"
2124 : "\n"
2125 : "With 'true' or 'false', turn text mode on or off.\n"
2126 : "Without, return the current text mode status.";
2127 : static gpg_error_t
2128 0 : cmd_textmode (assuan_context_t ctx, char *line)
2129 : {
2130 0 : struct server *server = assuan_get_pointer (ctx);
2131 0 : if (line && *line)
2132 : {
2133 0 : int flag = 0;
2134 :
2135 0 : if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2136 0 : || line[0] == '1')
2137 0 : flag = 1;
2138 :
2139 0 : return gt_set_textmode (server->gt, flag);
2140 : }
2141 : else
2142 0 : return gt_get_textmode (server->gt);
2143 : }
2144 :
2145 :
2146 : static const char hlp_include_certs[] =
2147 : "INCLUDE_CERTS [default|<n>]\n"
2148 : "\n"
2149 : "With DEFAULT or N, set how many certificates should be\n"
2150 : "included in the next S/MIME signed message. See the\n"
2151 : "GPGME documentation for details on the meaning of"
2152 : "various N. Without either, return the current setting.";
2153 : static gpg_error_t
2154 0 : cmd_include_certs (assuan_context_t ctx, char *line)
2155 : {
2156 0 : struct server *server = assuan_get_pointer (ctx);
2157 :
2158 0 : if (line && *line)
2159 : {
2160 0 : int include_certs = 0;
2161 :
2162 0 : if (! strcasecmp (line, "default"))
2163 0 : include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
2164 : else
2165 0 : include_certs = atoi (line);
2166 :
2167 0 : return gt_set_include_certs (server->gt, include_certs);
2168 : }
2169 : else
2170 0 : return gt_get_include_certs (server->gt);
2171 : }
2172 :
2173 :
2174 : static const char hlp_keylist_mode[] =
2175 : "KEYLIST_MODE [local] [extern] [sigs] [sig_notations]\n"
2176 : " [ephemeral] [validate]\n"
2177 : "\n"
2178 : "Set the mode for the next KEYLIST command.";
2179 : static gpg_error_t
2180 0 : cmd_keylist_mode (assuan_context_t ctx, char *line)
2181 : {
2182 0 : struct server *server = assuan_get_pointer (ctx);
2183 :
2184 0 : if (line && *line)
2185 : {
2186 0 : gpgme_keylist_mode_t mode = 0;
2187 :
2188 0 : if (strstr (line, "local"))
2189 0 : mode |= GPGME_KEYLIST_MODE_LOCAL;
2190 0 : if (strstr (line, "extern"))
2191 0 : mode |= GPGME_KEYLIST_MODE_EXTERN;
2192 0 : if (strstr (line, "sigs"))
2193 0 : mode |= GPGME_KEYLIST_MODE_SIGS;
2194 0 : if (strstr (line, "sig_notations"))
2195 0 : mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2196 0 : if (strstr (line, "with_secret"))
2197 0 : mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2198 0 : if (strstr (line, "ephemeral"))
2199 0 : mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2200 0 : if (strstr (line, "validate"))
2201 0 : mode |= GPGME_KEYLIST_MODE_VALIDATE;
2202 :
2203 0 : return gt_set_keylist_mode (server->gt, mode);
2204 : }
2205 : else
2206 0 : return gt_get_keylist_mode (server->gt);
2207 : }
2208 :
2209 :
2210 : static const char hlp_input[] =
2211 : "INPUT [<fd>|FILE=<path>]\n"
2212 : "\n"
2213 : "Set the input for the next command. Use either the\n"
2214 : "Assuan file descriptor FD or a filesystem PATH.";
2215 : static gpg_error_t
2216 0 : cmd_input (assuan_context_t ctx, char *line)
2217 : {
2218 0 : struct server *server = assuan_get_pointer (ctx);
2219 : gpg_error_t err;
2220 : assuan_fd_t sysfd;
2221 : char *filename;
2222 :
2223 0 : err = server_parse_fd (ctx, line, &sysfd, &filename);
2224 0 : if (err)
2225 0 : return err;
2226 0 : server->input_fd = sysfd;
2227 0 : server->input_filename = filename;
2228 0 : server->input_enc = server_data_encoding (line);
2229 0 : return 0;
2230 : }
2231 :
2232 :
2233 : static const char hlp_output[] =
2234 : "OUTPUT [<fd>|FILE=<path>]\n"
2235 : "\n"
2236 : "Set the output for the next command. Use either the\n"
2237 : "Assuan file descriptor FD or a filesystem PATH.";
2238 : static gpg_error_t
2239 0 : cmd_output (assuan_context_t ctx, char *line)
2240 : {
2241 0 : struct server *server = assuan_get_pointer (ctx);
2242 : gpg_error_t err;
2243 : assuan_fd_t sysfd;
2244 : char *filename;
2245 :
2246 0 : err = server_parse_fd (ctx, line, &sysfd, &filename);
2247 0 : if (err)
2248 0 : return err;
2249 0 : server->output_fd = sysfd;
2250 0 : server->output_filename = filename;
2251 0 : server->output_enc = server_data_encoding (line);
2252 0 : return 0;
2253 : }
2254 :
2255 :
2256 : static const char hlp_message[] =
2257 : "MESSAGE [<fd>|FILE=<path>]\n"
2258 : "\n"
2259 : "Set the plaintext message for the next VERIFY command\n"
2260 : "with a detached signature. Use either the Assuan file\n"
2261 : "descriptor FD or a filesystem PATH.";
2262 : static gpg_error_t
2263 0 : cmd_message (assuan_context_t ctx, char *line)
2264 : {
2265 0 : struct server *server = assuan_get_pointer (ctx);
2266 : gpg_error_t err;
2267 : assuan_fd_t sysfd;
2268 : char *filename;
2269 :
2270 0 : err = server_parse_fd (ctx, line, &sysfd, &filename);
2271 0 : if (err)
2272 0 : return err;
2273 0 : server->message_fd = sysfd;
2274 0 : server->message_filename = filename;
2275 0 : server->message_enc = server_data_encoding (line);
2276 0 : return 0;
2277 : }
2278 :
2279 :
2280 : static const char hlp_recipient[] =
2281 : "RECIPIENT <pattern>\n"
2282 : "\n"
2283 : "Add the key matching PATTERN to the list of recipients\n"
2284 : "for the next encryption command.";
2285 : static gpg_error_t
2286 0 : cmd_recipient (assuan_context_t ctx, char *line)
2287 : {
2288 0 : struct server *server = assuan_get_pointer (ctx);
2289 :
2290 0 : return gt_recipients_add (server->gt, line);
2291 : }
2292 :
2293 :
2294 : static const char hlp_signer[] =
2295 : "SIGNER <fingerprint>\n"
2296 : "\n"
2297 : "Add the key with FINGERPRINT to the list of signers to\n"
2298 : "be used for the next signing command.";
2299 : static gpg_error_t
2300 0 : cmd_signer (assuan_context_t ctx, char *line)
2301 : {
2302 0 : struct server *server = assuan_get_pointer (ctx);
2303 :
2304 0 : return gt_signers_add (server->gt, line);
2305 : }
2306 :
2307 :
2308 : static const char hlp_signers_clear[] =
2309 : "SIGNERS_CLEAR\n"
2310 : "\n"
2311 : "Clear the list of signers specified by previous SIGNER\n"
2312 : "commands.";
2313 : static gpg_error_t
2314 0 : cmd_signers_clear (assuan_context_t ctx, char *line)
2315 : {
2316 0 : struct server *server = assuan_get_pointer (ctx);
2317 :
2318 : (void)line;
2319 :
2320 0 : return gt_signers_clear (server->gt);
2321 : }
2322 :
2323 :
2324 : static gpg_error_t
2325 0 : _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
2326 : {
2327 0 : struct server *server = assuan_get_pointer (ctx);
2328 : gpg_error_t err;
2329 : assuan_fd_t inp_fd;
2330 : char *inp_fn;
2331 : assuan_fd_t out_fd;
2332 : char *out_fn;
2333 : gpgme_data_t inp_data;
2334 : gpgme_data_t out_data;
2335 :
2336 : (void)line;
2337 :
2338 0 : inp_fd = server->input_fd;
2339 0 : inp_fn = server->input_filename;
2340 0 : if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2341 0 : return GPG_ERR_ASS_NO_INPUT;
2342 0 : out_fd = server->output_fd;
2343 0 : out_fn = server->output_filename;
2344 0 : if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2345 0 : return GPG_ERR_ASS_NO_OUTPUT;
2346 :
2347 0 : err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2348 : &server->input_stream);
2349 0 : if (err)
2350 0 : return err;
2351 0 : err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2352 : &server->output_stream);
2353 0 : if (err)
2354 : {
2355 0 : gpgme_data_release (inp_data);
2356 0 : return err;
2357 : }
2358 :
2359 0 : err = gt_decrypt_verify (server->gt, inp_data, out_data, verify);
2360 :
2361 0 : gpgme_data_release (inp_data);
2362 0 : gpgme_data_release (out_data);
2363 :
2364 0 : server_reset_fds (server);
2365 :
2366 0 : return err;
2367 : }
2368 :
2369 :
2370 : static const char hlp_decrypt[] =
2371 : "DECRYPT\n"
2372 : "\n"
2373 : "Decrypt the object set by the last INPUT command and\n"
2374 : "write the decrypted message to the object set by the\n"
2375 : "last OUTPUT command.";
2376 : static gpg_error_t
2377 0 : cmd_decrypt (assuan_context_t ctx, char *line)
2378 : {
2379 0 : return _cmd_decrypt_verify (ctx, line, 0);
2380 : }
2381 :
2382 :
2383 : static const char hlp_decrypt_verify[] =
2384 : "DECRYPT_VERIFY\n"
2385 : "\n"
2386 : "Decrypt the object set by the last INPUT command and\n"
2387 : "verify any embedded signatures. Write the decrypted\n"
2388 : "message to the object set by the last OUTPUT command.";
2389 : static gpg_error_t
2390 0 : cmd_decrypt_verify (assuan_context_t ctx, char *line)
2391 : {
2392 0 : return _cmd_decrypt_verify (ctx, line, 1);
2393 : }
2394 :
2395 :
2396 : static gpg_error_t
2397 0 : _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
2398 : {
2399 0 : struct server *server = assuan_get_pointer (ctx);
2400 : gpg_error_t err;
2401 : assuan_fd_t inp_fd;
2402 : char *inp_fn;
2403 : assuan_fd_t out_fd;
2404 : char *out_fn;
2405 0 : gpgme_data_t inp_data = NULL;
2406 0 : gpgme_data_t out_data = NULL;
2407 0 : gpgme_encrypt_flags_t flags = 0;
2408 :
2409 0 : if (strstr (line, "--always-trust"))
2410 0 : flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
2411 0 : if (strstr (line, "--no-encrypt-to"))
2412 0 : flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
2413 0 : if (strstr (line, "--prepare"))
2414 0 : flags |= GPGME_ENCRYPT_PREPARE;
2415 0 : if (strstr (line, "--expect-sign"))
2416 0 : flags |= GPGME_ENCRYPT_EXPECT_SIGN;
2417 0 : if (strstr (line, "--no-compress"))
2418 0 : flags |= GPGME_ENCRYPT_NO_COMPRESS;
2419 :
2420 0 : inp_fd = server->input_fd;
2421 0 : inp_fn = server->input_filename;
2422 0 : out_fd = server->output_fd;
2423 0 : out_fn = server->output_filename;
2424 0 : if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
2425 : {
2426 0 : err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2427 : &server->input_stream);
2428 0 : if (err)
2429 0 : return err;
2430 : }
2431 0 : if (out_fd != ASSUAN_INVALID_FD || out_fn)
2432 : {
2433 0 : err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2434 : &server->output_stream);
2435 0 : if (err)
2436 : {
2437 0 : gpgme_data_release (inp_data);
2438 0 : return err;
2439 : }
2440 : }
2441 :
2442 0 : err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign);
2443 :
2444 0 : gpgme_data_release (inp_data);
2445 0 : gpgme_data_release (out_data);
2446 :
2447 0 : server_reset_fds (server);
2448 :
2449 0 : return err;
2450 : }
2451 :
2452 :
2453 : static const char hlp_encrypt[] =
2454 : "ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2455 : " [--no-compress] [--prepare] [--expect-sign]\n"
2456 : "\n"
2457 : "Encrypt the object set by the last INPUT command to\n"
2458 : "the keys specified by previous RECIPIENT commands. \n"
2459 : "Write the signed and encrypted message to the object\n"
2460 : "set by the last OUTPUT command.";
2461 : static gpg_error_t
2462 0 : cmd_encrypt (assuan_context_t ctx, char *line)
2463 : {
2464 0 : return _cmd_sign_encrypt (ctx, line, 0);
2465 : }
2466 :
2467 :
2468 : static const char hlp_sign_encrypt[] =
2469 : "SIGN_ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2470 : " [--no-compress] [--prepare] [--expect-sign]\n"
2471 : "\n"
2472 : "Sign the object set by the last INPUT command with the\n"
2473 : "keys specified by previous SIGNER commands and encrypt\n"
2474 : "it to the keys specified by previous RECIPIENT\n"
2475 : "commands. Write the signed and encrypted message to\n"
2476 : "the object set by the last OUTPUT command.";
2477 : static gpg_error_t
2478 0 : cmd_sign_encrypt (assuan_context_t ctx, char *line)
2479 : {
2480 0 : return _cmd_sign_encrypt (ctx, line, 1);
2481 : }
2482 :
2483 :
2484 : static const char hlp_sign[] =
2485 : "SIGN [--clear|--detach]\n"
2486 : "\n"
2487 : "Sign the object set by the last INPUT command with the\n"
2488 : "keys specified by previous SIGNER commands. Write the\n"
2489 : "signed message to the object set by the last OUTPUT\n"
2490 : "command. With `--clear`, generate a clear text\n"
2491 : "signature. With `--detach`, generate a detached\n"
2492 : "signature.";
2493 : static gpg_error_t
2494 0 : cmd_sign (assuan_context_t ctx, char *line)
2495 : {
2496 0 : struct server *server = assuan_get_pointer (ctx);
2497 : gpg_error_t err;
2498 : assuan_fd_t inp_fd;
2499 : char *inp_fn;
2500 : assuan_fd_t out_fd;
2501 : char *out_fn;
2502 : gpgme_data_t inp_data;
2503 : gpgme_data_t out_data;
2504 0 : gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
2505 :
2506 0 : if (strstr (line, "--clear"))
2507 0 : mode = GPGME_SIG_MODE_CLEAR;
2508 0 : if (strstr (line, "--detach"))
2509 0 : mode = GPGME_SIG_MODE_DETACH;
2510 :
2511 0 : inp_fd = server->input_fd;
2512 0 : inp_fn = server->input_filename;
2513 0 : if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2514 0 : return GPG_ERR_ASS_NO_INPUT;
2515 0 : out_fd = server->output_fd;
2516 0 : out_fn = server->output_filename;
2517 0 : if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2518 0 : return GPG_ERR_ASS_NO_OUTPUT;
2519 :
2520 0 : err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2521 : &server->input_stream);
2522 0 : if (err)
2523 0 : return err;
2524 0 : err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2525 : &server->output_stream);
2526 0 : if (err)
2527 : {
2528 0 : gpgme_data_release (inp_data);
2529 0 : return err;
2530 : }
2531 :
2532 0 : err = gt_sign (server->gt, inp_data, out_data, mode);
2533 :
2534 0 : gpgme_data_release (inp_data);
2535 0 : gpgme_data_release (out_data);
2536 0 : server_reset_fds (server);
2537 :
2538 0 : return err;
2539 : }
2540 :
2541 :
2542 : static const char hlp_verify[] =
2543 : "VERIFY\n"
2544 : "\n"
2545 : "Verify signatures on the object set by the last INPUT\n"
2546 : "and MESSAGE commands. If the message was encrypted,\n"
2547 : "write the plaintext to the object set by the last\n"
2548 : "OUTPUT command.";
2549 : static gpg_error_t
2550 0 : cmd_verify (assuan_context_t ctx, char *line)
2551 : {
2552 0 : struct server *server = assuan_get_pointer (ctx);
2553 : gpg_error_t err;
2554 : assuan_fd_t inp_fd;
2555 : assuan_fd_t msg_fd;
2556 : assuan_fd_t out_fd;
2557 : char *inp_fn;
2558 : char *msg_fn;
2559 : char *out_fn;
2560 : gpgme_data_t inp_data;
2561 0 : gpgme_data_t msg_data = NULL;
2562 0 : gpgme_data_t out_data = NULL;
2563 :
2564 : (void)line;
2565 :
2566 0 : inp_fd = server->input_fd;
2567 0 : inp_fn = server->input_filename;
2568 0 : if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2569 0 : return GPG_ERR_ASS_NO_INPUT;
2570 0 : msg_fd = server->message_fd;
2571 0 : msg_fn = server->message_filename;
2572 0 : out_fd = server->output_fd;
2573 0 : out_fn = server->output_filename;
2574 :
2575 0 : err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2576 : &server->input_stream);
2577 0 : if (err)
2578 0 : return err;
2579 0 : if (msg_fd != ASSUAN_INVALID_FD || msg_fn)
2580 : {
2581 0 : err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data,
2582 : &server->message_stream);
2583 0 : if (err)
2584 : {
2585 0 : gpgme_data_release (inp_data);
2586 0 : return err;
2587 : }
2588 : }
2589 0 : if (out_fd != ASSUAN_INVALID_FD || out_fn)
2590 : {
2591 0 : err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2592 : &server->output_stream);
2593 0 : if (err)
2594 : {
2595 0 : gpgme_data_release (inp_data);
2596 0 : gpgme_data_release (msg_data);
2597 0 : return err;
2598 : }
2599 : }
2600 :
2601 0 : err = gt_verify (server->gt, inp_data, msg_data, out_data);
2602 :
2603 0 : gpgme_data_release (inp_data);
2604 0 : if (msg_data)
2605 0 : gpgme_data_release (msg_data);
2606 0 : if (out_data)
2607 0 : gpgme_data_release (out_data);
2608 :
2609 0 : server_reset_fds (server);
2610 :
2611 0 : return err;
2612 : }
2613 :
2614 :
2615 : static const char hlp_import[] =
2616 : "IMPORT [<pattern>]\n"
2617 : "\n"
2618 : "With PATTERN, import the keys described by PATTERN.\n"
2619 : "Without, read a key (or keys) from the object set by the\n"
2620 : "last INPUT command.";
2621 : static gpg_error_t
2622 0 : cmd_import (assuan_context_t ctx, char *line)
2623 : {
2624 0 : struct server *server = assuan_get_pointer (ctx);
2625 :
2626 0 : if (line && *line)
2627 : {
2628 0 : char *fprs[2] = { line, NULL };
2629 :
2630 0 : return gt_import_keys (server->gt, fprs);
2631 : }
2632 : else
2633 : {
2634 : gpg_error_t err;
2635 : assuan_fd_t inp_fd;
2636 : char *inp_fn;
2637 : gpgme_data_t inp_data;
2638 :
2639 0 : inp_fd = server->input_fd;
2640 0 : inp_fn = server->input_filename;
2641 0 : if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2642 0 : return GPG_ERR_ASS_NO_INPUT;
2643 :
2644 0 : err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2645 : &server->input_stream);
2646 0 : if (err)
2647 0 : return err;
2648 :
2649 0 : err = gt_import (server->gt, inp_data);
2650 :
2651 0 : gpgme_data_release (inp_data);
2652 0 : server_reset_fds (server);
2653 :
2654 0 : return err;
2655 : }
2656 : }
2657 :
2658 :
2659 : static const char hlp_export[] =
2660 : "EXPORT [--extern] [--minimal] [--secret [--pkcs12] [--raw]] [<pattern>]\n"
2661 : "\n"
2662 : "Export the keys described by PATTERN. Write the\n"
2663 : "the output to the object set by the last OUTPUT command.";
2664 : static gpg_error_t
2665 0 : cmd_export (assuan_context_t ctx, char *line)
2666 : {
2667 0 : struct server *server = assuan_get_pointer (ctx);
2668 : gpg_error_t err;
2669 : assuan_fd_t out_fd;
2670 : char *out_fn;
2671 : gpgme_data_t out_data;
2672 0 : gpgme_export_mode_t mode = 0;
2673 : const char *pattern[2];
2674 :
2675 0 : out_fd = server->output_fd;
2676 0 : out_fn = server->output_filename;
2677 0 : if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2678 0 : return GPG_ERR_ASS_NO_OUTPUT;
2679 0 : err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2680 : &server->output_stream);
2681 0 : if (err)
2682 0 : return err;
2683 :
2684 0 : if (has_option (line, "--extern"))
2685 0 : mode |= GPGME_EXPORT_MODE_EXTERN;
2686 0 : if (has_option (line, "--minimal"))
2687 0 : mode |= GPGME_EXPORT_MODE_MINIMAL;
2688 0 : if (has_option (line, "--secret"))
2689 0 : mode |= GPGME_EXPORT_MODE_SECRET;
2690 0 : if (has_option (line, "--raw"))
2691 0 : mode |= GPGME_EXPORT_MODE_RAW;
2692 0 : if (has_option (line, "--pkcs12"))
2693 0 : mode |= GPGME_EXPORT_MODE_PKCS12;
2694 :
2695 0 : line = skip_options (line);
2696 :
2697 0 : pattern[0] = line;
2698 0 : pattern[1] = NULL;
2699 :
2700 0 : err = gt_export (server->gt, pattern, mode, out_data);
2701 :
2702 0 : gpgme_data_release (out_data);
2703 0 : server_reset_fds (server);
2704 :
2705 0 : return err;
2706 : }
2707 :
2708 :
2709 : static gpg_error_t
2710 0 : _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
2711 : {
2712 0 : while (size > 0)
2713 : {
2714 0 : gpgme_ssize_t writen = gpgme_data_write (data, buf, size);
2715 0 : if (writen < 0 && errno != EAGAIN)
2716 0 : return gpg_error_from_syserror ();
2717 0 : else if (writen > 0)
2718 : {
2719 0 : buf = (void *) (((char *) buf) + writen);
2720 0 : size -= writen;
2721 : }
2722 : }
2723 0 : return 0;
2724 : }
2725 :
2726 :
2727 : static gpg_error_t
2728 0 : cmd_genkey (assuan_context_t ctx, char *line)
2729 : {
2730 0 : struct server *server = assuan_get_pointer (ctx);
2731 : gpg_error_t err;
2732 : assuan_fd_t inp_fd;
2733 : char *inp_fn;
2734 : assuan_fd_t out_fd;
2735 : char *out_fn;
2736 : gpgme_data_t inp_data;
2737 0 : gpgme_data_t out_data = NULL;
2738 0 : gpgme_data_t parms_data = NULL;
2739 : const char *parms;
2740 :
2741 : (void)line;
2742 :
2743 0 : inp_fd = server->input_fd;
2744 0 : inp_fn = server->input_filename;
2745 0 : if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2746 0 : return GPG_ERR_ASS_NO_INPUT;
2747 0 : out_fd = server->output_fd;
2748 0 : out_fn = server->output_filename;
2749 :
2750 0 : err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2751 : &server->input_stream);
2752 0 : if (err)
2753 0 : return err;
2754 0 : if (out_fd != ASSUAN_INVALID_FD || out_fn)
2755 : {
2756 0 : err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2757 : &server->output_stream);
2758 0 : if (err)
2759 : {
2760 0 : gpgme_data_release (inp_data);
2761 0 : return err;
2762 : }
2763 : }
2764 :
2765 : /* Convert input data. */
2766 0 : err = gpgme_data_new (&parms_data);
2767 0 : if (err)
2768 0 : goto out;
2769 : do
2770 : {
2771 : char buf[512];
2772 0 : gpgme_ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
2773 0 : if (readn < 0)
2774 : {
2775 0 : err = gpg_error_from_syserror ();
2776 0 : goto out;
2777 : }
2778 0 : else if (readn == 0)
2779 0 : break;
2780 :
2781 0 : err = _cmd_genkey_write (parms_data, buf, readn);
2782 0 : if (err)
2783 0 : goto out;
2784 : }
2785 0 : while (1);
2786 0 : err = _cmd_genkey_write (parms_data, "", 1);
2787 0 : if (err)
2788 0 : goto out;
2789 0 : parms = gpgme_data_release_and_get_mem (parms_data, NULL);
2790 0 : parms_data = NULL;
2791 0 : if (! parms)
2792 : {
2793 0 : err = gpg_error (GPG_ERR_GENERAL);
2794 0 : goto out;
2795 : }
2796 :
2797 0 : err = gt_genkey (server->gt, parms, out_data, NULL);
2798 :
2799 0 : server_reset_fds (server);
2800 :
2801 : out:
2802 0 : gpgme_data_release (inp_data);
2803 0 : if (out_data)
2804 0 : gpgme_data_release (out_data);
2805 0 : if (parms_data)
2806 0 : gpgme_data_release (parms_data);
2807 :
2808 0 : return err;
2809 : }
2810 :
2811 :
2812 : static gpg_error_t
2813 0 : cmd_delete (assuan_context_t ctx, char *line)
2814 : {
2815 0 : struct server *server = assuan_get_pointer (ctx);
2816 0 : int allow_secret = 0;
2817 0 : const char optstr[] = "--allow-secret";
2818 :
2819 0 : if (!strncasecmp (line, optstr, strlen (optstr)))
2820 : {
2821 0 : allow_secret = 1;
2822 0 : line += strlen (optstr);
2823 0 : while (*line && !spacep (line))
2824 0 : line++;
2825 : }
2826 0 : return gt_delete (server->gt, line, allow_secret);
2827 : }
2828 :
2829 :
2830 : static const char hlp_keylist[] =
2831 : "KEYLIST [--secret-only] [<patterns>]\n"
2832 : "\n"
2833 : "List all certificates or only those specified by PATTERNS. Each\n"
2834 : "pattern shall be a percent-plus escaped certificate specification.";
2835 : static gpg_error_t
2836 0 : cmd_keylist (assuan_context_t ctx, char *line)
2837 : {
2838 : #define MAX_CMD_KEYLIST_PATTERN 20
2839 0 : struct server *server = assuan_get_pointer (ctx);
2840 0 : gpgme_tool_t gt = server->gt;
2841 : struct result_xml_state state;
2842 : gpg_error_t err;
2843 0 : int secret_only = 0;
2844 0 : int idx, indent=2;
2845 : const char *pattern[MAX_CMD_KEYLIST_PATTERN+1];
2846 0 : const char optstr[] = "--secret-only";
2847 : char *p;
2848 :
2849 0 : if (!strncasecmp (line, optstr, strlen (optstr)))
2850 : {
2851 0 : secret_only = 1;
2852 0 : line += strlen (optstr);
2853 0 : while (*line && !spacep (line))
2854 0 : line++;
2855 : }
2856 :
2857 0 : idx = 0;
2858 0 : for (p=line; *p; line = p)
2859 : {
2860 0 : while (*p && *p != ' ')
2861 0 : p++;
2862 0 : if (*p)
2863 0 : *p++ = 0;
2864 0 : if (*line)
2865 : {
2866 0 : if (idx+1 == DIM (pattern))
2867 0 : return gpg_error (GPG_ERR_TOO_MANY);
2868 0 : strcpy_escaped_plus (line, line);
2869 0 : pattern[idx++] = line;
2870 : }
2871 : }
2872 0 : pattern[idx] = NULL;
2873 :
2874 0 : gt_write_data (gt, xml_preamble1, strlen (xml_preamble1));
2875 0 : gt_write_data (gt, NULL, 0);
2876 0 : gt_write_data (gt, xml_preamble2, strlen (xml_preamble2));
2877 0 : gt_write_data (gt, NULL, 0);
2878 0 : result_init (&state, indent, (result_xml_write_cb_t) gt_write_data, gt);
2879 0 : result_xml_tag_start (&state, "keylist", NULL);
2880 :
2881 0 : err = gt_keylist_start (server->gt, pattern, secret_only);
2882 0 : while (! err)
2883 : {
2884 : gpgme_key_t key;
2885 : gpgme_subkey_t subkey;
2886 : gpgme_user_id_t uid;
2887 :
2888 0 : err = gt_keylist_next (server->gt, &key);
2889 0 : if (gpg_err_code (err) == GPG_ERR_EOF)
2890 : {
2891 0 : err = 0;
2892 0 : break;
2893 : }
2894 0 : else if (! err)
2895 : {
2896 0 : result_xml_tag_start (&state, "key", NULL);
2897 0 : result_add_value (&state, "revoked", key->revoked);
2898 0 : result_add_value (&state, "expired", key->expired);
2899 0 : result_add_value (&state, "disabled", key->disabled);
2900 0 : result_add_value (&state, "invalid", key->invalid);
2901 0 : result_add_value (&state, "can-encrypt", key->can_encrypt);
2902 0 : result_add_value (&state, "can-sign", key->can_sign);
2903 0 : result_add_value (&state, "can-certify", key->can_certify);
2904 0 : result_add_value (&state, "can-authenticate", key->can_authenticate);
2905 0 : result_add_value (&state, "is-qualified", key->is_qualified);
2906 0 : result_add_value (&state, "secret", key->secret);
2907 0 : result_add_protocol (&state, "protocol", key->protocol);
2908 0 : result_xml_tag_start (&state, "issuer", NULL);
2909 0 : result_add_string (&state, "serial", key->issuer_serial);
2910 0 : result_add_string (&state, "name", key->issuer_name);
2911 0 : result_xml_tag_end (&state); /* issuer */
2912 0 : result_add_string (&state, "chain-id", key->chain_id);
2913 0 : result_add_validity (&state, "owner-trust", key->owner_trust);
2914 0 : result_xml_tag_start (&state, "subkeys", NULL);
2915 0 : subkey = key->subkeys;
2916 0 : while (subkey) {
2917 0 : result_xml_tag_start (&state, "subkey", NULL);
2918 : /* FIXME: more data */
2919 0 : result_add_keyid (&state, "keyid", subkey->keyid);
2920 0 : if (subkey->fpr)
2921 0 : result_add_fpr (&state, "fpr", subkey->fpr);
2922 0 : result_add_value (&state, "secret", subkey->secret);
2923 0 : result_add_value (&state, "is_cardkey", subkey->is_cardkey);
2924 0 : if (subkey->card_number)
2925 0 : result_add_string (&state, "card_number", subkey->card_number);
2926 0 : if (subkey->curve)
2927 0 : result_add_string (&state, "curve", subkey->curve);
2928 0 : result_xml_tag_end (&state); /* subkey */
2929 0 : subkey = subkey->next;
2930 : }
2931 0 : result_xml_tag_end (&state); /* subkeys */
2932 0 : result_xml_tag_start (&state, "uids", NULL);
2933 0 : uid = key->uids;
2934 0 : while (uid) {
2935 0 : result_xml_tag_start (&state, "uid", NULL);
2936 : /* FIXME: more data */
2937 0 : result_add_string (&state, "uid", uid->uid);
2938 0 : result_add_string (&state, "name", uid->name);
2939 0 : result_add_string (&state, "email", uid->email);
2940 0 : result_add_string (&state, "comment", uid->comment);
2941 0 : result_xml_tag_end (&state); /* uid */
2942 0 : uid = uid->next;
2943 : }
2944 0 : result_xml_tag_end (&state); /* uids */
2945 0 : result_xml_tag_end (&state); /* key */
2946 0 : gpgme_key_unref (key);
2947 : }
2948 : }
2949 :
2950 0 : result_xml_tag_end (&state); /* keylist */
2951 0 : gt_write_data (gt, xml_end, strlen (xml_end));
2952 :
2953 0 : server_reset_fds (server);
2954 :
2955 0 : return err;
2956 : }
2957 :
2958 :
2959 : static const char hlp_getauditlog[] =
2960 : "GETAUDITLOG [--html] [--with-help]\n"
2961 : "\n"
2962 : "Call the function gpgme_op_getauditlog with the given flags. Write\n"
2963 : "the output to the object set by the last OUTPUT command.";
2964 : static gpg_error_t
2965 0 : cmd_getauditlog (assuan_context_t ctx, char *line)
2966 : {
2967 0 : struct server *server = assuan_get_pointer (ctx);
2968 : gpg_error_t err;
2969 : assuan_fd_t out_fd;
2970 : char *out_fn;
2971 : gpgme_data_t out_data;
2972 0 : unsigned int flags = 0;
2973 :
2974 0 : out_fd = server->output_fd;
2975 0 : out_fn = server->output_filename;
2976 0 : if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2977 0 : return GPG_ERR_ASS_NO_OUTPUT;
2978 0 : err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2979 : &server->output_stream);
2980 0 : if (err)
2981 0 : return err;
2982 :
2983 0 : if (strstr (line, "--html"))
2984 0 : flags |= GPGME_AUDITLOG_HTML;
2985 0 : if (strstr (line, "--with-help"))
2986 0 : flags |= GPGME_AUDITLOG_WITH_HELP;
2987 :
2988 0 : err = gt_getauditlog (server->gt, out_data, flags);
2989 :
2990 0 : gpgme_data_release (out_data);
2991 0 : server_reset_fds (server);
2992 :
2993 0 : return err;
2994 : }
2995 :
2996 :
2997 : static gpg_error_t
2998 0 : cmd_vfs_mount (assuan_context_t ctx, char *line)
2999 : {
3000 0 : struct server *server = assuan_get_pointer (ctx);
3001 : char *mount_dir;
3002 : gpg_error_t err;
3003 :
3004 0 : mount_dir = strchr (line, ' ');
3005 0 : if (mount_dir)
3006 : {
3007 0 : *(mount_dir++) = '\0';
3008 0 : while (*mount_dir == ' ')
3009 0 : mount_dir++;
3010 : }
3011 :
3012 0 : err = gt_vfs_mount (server->gt, line, mount_dir, 0);
3013 :
3014 0 : return err;
3015 : }
3016 :
3017 :
3018 : static gpg_error_t
3019 0 : cmd_vfs_create (assuan_context_t ctx, char *line)
3020 : {
3021 0 : struct server *server = assuan_get_pointer (ctx);
3022 : gpg_error_t err;
3023 : char *end;
3024 :
3025 0 : end = strchr (line, ' ');
3026 0 : if (end)
3027 : {
3028 0 : *(end++) = '\0';
3029 0 : while (*end == ' ')
3030 0 : end++;
3031 : }
3032 :
3033 0 : err = gt_vfs_create (server->gt, line, 0);
3034 :
3035 0 : return err;
3036 : }
3037 :
3038 :
3039 : static const char hlp_passwd[] =
3040 : "PASSWD <user-id>\n"
3041 : "\n"
3042 : "Ask the backend to change the passphrase for the key\n"
3043 : "specified by USER-ID.";
3044 : static gpg_error_t
3045 0 : cmd_passwd (assuan_context_t ctx, char *line)
3046 : {
3047 0 : struct server *server = assuan_get_pointer (ctx);
3048 :
3049 0 : return gt_passwd (server->gt, line);
3050 : }
3051 :
3052 :
3053 :
3054 : static gpg_error_t
3055 0 : cmd_result (assuan_context_t ctx, char *line)
3056 : {
3057 0 : struct server *server = assuan_get_pointer (ctx);
3058 :
3059 : (void)line;
3060 :
3061 0 : return gt_result (server->gt, GT_RESULT_ALL);
3062 : }
3063 :
3064 :
3065 : /* STRERROR <err> */
3066 : static gpg_error_t
3067 0 : cmd_strerror (assuan_context_t ctx, char *line)
3068 : {
3069 : gpg_error_t err;
3070 : char buf[100];
3071 :
3072 0 : err = atoi (line);
3073 0 : snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
3074 : gpgme_strsource (err));
3075 0 : return assuan_send_data (ctx, buf, strlen (buf));
3076 : }
3077 :
3078 :
3079 : static gpg_error_t
3080 0 : cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
3081 : {
3082 : gpgme_pubkey_algo_t algo;
3083 : char buf[100];
3084 :
3085 0 : algo = atoi (line);
3086 0 : snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
3087 0 : return assuan_send_data (ctx, buf, strlen (buf));
3088 : }
3089 :
3090 :
3091 : static gpg_error_t
3092 0 : cmd_hash_algo_name (assuan_context_t ctx, char *line)
3093 : {
3094 : gpgme_hash_algo_t algo;
3095 : char buf[100];
3096 :
3097 0 : algo = atoi (line);
3098 0 : snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
3099 0 : return assuan_send_data (ctx, buf, strlen (buf));
3100 : }
3101 :
3102 :
3103 : static const char hlp_identify[] =
3104 : "IDENTIY\n"
3105 : "\n"
3106 : "Identify the type of data set with the INPUT command.";
3107 : static gpg_error_t
3108 0 : cmd_identify (assuan_context_t ctx, char *line)
3109 : {
3110 0 : struct server *server = assuan_get_pointer (ctx);
3111 : gpg_error_t err;
3112 : assuan_fd_t inp_fd;
3113 : char *inp_fn;
3114 : gpgme_data_t inp_data;
3115 :
3116 : (void)line;
3117 :
3118 0 : inp_fd = server->input_fd;
3119 0 : inp_fn = server->input_filename;
3120 0 : if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3121 0 : return GPG_ERR_ASS_NO_INPUT;
3122 :
3123 0 : err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3124 : &server->input_stream);
3125 0 : if (err)
3126 0 : return err;
3127 :
3128 0 : err = gt_identify (server->gt, inp_data);
3129 :
3130 0 : gpgme_data_release (inp_data);
3131 0 : server_reset_fds (server);
3132 :
3133 0 : return err;
3134 : }
3135 :
3136 :
3137 : static const char hlp_spawn[] =
3138 : "SPAWN PGM [args]\n"
3139 : "\n"
3140 : "Run program PGM with stdin connected to the INPUT source;\n"
3141 : "stdout and stderr to the OUTPUT source.";
3142 : static gpg_error_t
3143 0 : cmd_spawn (assuan_context_t ctx, char *line)
3144 : {
3145 0 : struct server *server = assuan_get_pointer (ctx);
3146 : gpg_error_t err;
3147 : assuan_fd_t inp_fd;
3148 : char *inp_fn;
3149 : assuan_fd_t out_fd;
3150 : char *out_fn;
3151 0 : gpgme_data_t inp_data = NULL;
3152 0 : gpgme_data_t out_data = NULL;
3153 :
3154 0 : inp_fd = server->input_fd;
3155 0 : inp_fn = server->input_filename;
3156 0 : out_fd = server->output_fd;
3157 0 : out_fn = server->output_filename;
3158 0 : if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
3159 : {
3160 0 : err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3161 : &server->input_stream);
3162 0 : if (err)
3163 0 : return err;
3164 : }
3165 0 : if (out_fd != ASSUAN_INVALID_FD || out_fn)
3166 : {
3167 0 : err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3168 : &server->output_stream);
3169 0 : if (err)
3170 : {
3171 0 : gpgme_data_release (inp_data);
3172 0 : return err;
3173 : }
3174 : }
3175 :
3176 0 : err = gt_spawn (server->gt, line, inp_data, out_data);
3177 :
3178 0 : gpgme_data_release (inp_data);
3179 0 : gpgme_data_release (out_data);
3180 :
3181 0 : server_reset_fds (server);
3182 :
3183 0 : return err;
3184 : }
3185 :
3186 :
3187 : /* Tell the assuan library about our commands. */
3188 : static gpg_error_t
3189 0 : register_commands (assuan_context_t ctx)
3190 : {
3191 : gpg_error_t err;
3192 : static struct {
3193 : const char *name;
3194 : assuan_handler_t handler;
3195 : const char * const help;
3196 : } table[] = {
3197 : /* RESET, BYE are implicit. */
3198 : { "VERSION", cmd_version, hlp_version },
3199 : /* TODO: Set engine info. */
3200 : { "ENGINE", cmd_engine, hlp_engine },
3201 : { "PROTOCOL", cmd_protocol, hlp_protocol },
3202 : { "SUB_PROTOCOL", cmd_sub_protocol, hlp_sub_protocol },
3203 : { "PINENTRY_MODE", cmd_pinentry_mode, hlp_pinentry_mode },
3204 : { "ARMOR", cmd_armor, hlp_armor },
3205 : { "TEXTMODE", cmd_textmode, hlp_textmode },
3206 : { "INCLUDE_CERTS", cmd_include_certs, hlp_include_certs },
3207 : { "KEYLIST_MODE", cmd_keylist_mode, hlp_keylist_mode },
3208 : { "INPUT", cmd_input, hlp_input },
3209 : { "OUTPUT", cmd_output, hlp_output },
3210 : { "MESSAGE", cmd_message, hlp_message },
3211 : { "RECIPIENT", cmd_recipient, hlp_recipient },
3212 : { "SIGNER", cmd_signer, hlp_signer },
3213 : { "SIGNERS_CLEAR", cmd_signers_clear, hlp_signers_clear },
3214 : /* TODO: SIGNOTATION missing. */
3215 : /* TODO: Could add wait interface if we allow more than one context */
3216 : /* and add _START variants. */
3217 : /* TODO: Could add data interfaces if we allow multiple data objects. */
3218 : { "DECRYPT", cmd_decrypt, hlp_decrypt },
3219 : { "DECRYPT_VERIFY", cmd_decrypt_verify, hlp_decrypt_verify },
3220 : { "ENCRYPT", cmd_encrypt, hlp_encrypt },
3221 : { "ENCRYPT_SIGN", cmd_sign_encrypt, hlp_sign_encrypt },
3222 : { "SIGN_ENCRYPT", cmd_sign_encrypt, hlp_sign_encrypt },
3223 : { "SIGN", cmd_sign, hlp_sign },
3224 : { "VERIFY", cmd_verify, hlp_verify },
3225 : { "IMPORT", cmd_import, hlp_import },
3226 : { "EXPORT", cmd_export, hlp_export },
3227 : { "GENKEY", cmd_genkey },
3228 : { "DELETE", cmd_delete },
3229 : /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
3230 : { "KEYLIST", cmd_keylist, hlp_keylist },
3231 : { "LISTKEYS", cmd_keylist, hlp_keylist },
3232 : /* TODO: TRUSTLIST, TRUSTLIST_EXT */
3233 : { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
3234 : /* TODO: ASSUAN */
3235 : { "VFS_MOUNT", cmd_vfs_mount },
3236 : { "MOUNT", cmd_vfs_mount },
3237 : { "VFS_CREATE", cmd_vfs_create },
3238 : { "CREATE", cmd_vfs_create },
3239 : /* TODO: GPGCONF */
3240 : { "RESULT", cmd_result },
3241 : { "STRERROR", cmd_strerror },
3242 : { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
3243 : { "HASH_ALGO_NAME", cmd_hash_algo_name },
3244 : { "PASSWD", cmd_passwd, hlp_passwd },
3245 : { "IDENTIFY", cmd_identify, hlp_identify },
3246 : { "SPAWN", cmd_spawn, hlp_spawn },
3247 : { NULL }
3248 : };
3249 : int idx;
3250 :
3251 0 : for (idx = 0; table[idx].name; idx++)
3252 : {
3253 0 : err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
3254 : table[idx].help);
3255 0 : if (err)
3256 0 : return err;
3257 : }
3258 0 : return 0;
3259 : }
3260 :
3261 :
3262 : void
3263 0 : gpgme_server (gpgme_tool_t gt)
3264 : {
3265 : gpg_error_t err;
3266 : assuan_fd_t filedes[2];
3267 : struct server server;
3268 : static const char hello[] = ("GPGME-Tool " VERSION " ready");
3269 :
3270 0 : memset (&server, 0, sizeof (server));
3271 0 : server.input_fd = ASSUAN_INVALID_FD;
3272 0 : server.output_fd = ASSUAN_INVALID_FD;
3273 0 : server.message_fd = ASSUAN_INVALID_FD;
3274 0 : server.input_enc = GPGME_DATA_ENCODING_NONE;
3275 0 : server.output_enc = GPGME_DATA_ENCODING_NONE;
3276 0 : server.message_enc = GPGME_DATA_ENCODING_NONE;
3277 :
3278 0 : server.gt = gt;
3279 0 : gt->write_status = server_write_status;
3280 0 : gt->write_status_hook = &server;
3281 0 : gt->write_data = server_write_data;
3282 0 : gt->write_data_hook = &server;
3283 :
3284 : /* We use a pipe based server so that we can work from scripts.
3285 : assuan_init_pipe_server will automagically detect when we are
3286 : called with a socketpair and ignore FIELDES in this case. */
3287 : #ifdef HAVE_W32CE_SYSTEM
3288 : filedes[0] = ASSUAN_STDIN;
3289 : filedes[1] = ASSUAN_STDOUT;
3290 : #else
3291 0 : filedes[0] = assuan_fdopen (0);
3292 0 : filedes[1] = assuan_fdopen (1);
3293 : #endif
3294 0 : err = assuan_new (&server.assuan_ctx);
3295 0 : if (err)
3296 0 : log_error (1, err, "can't create assuan context");
3297 :
3298 0 : assuan_set_pointer (server.assuan_ctx, &server);
3299 :
3300 0 : err = assuan_init_pipe_server (server.assuan_ctx, filedes);
3301 0 : if (err)
3302 0 : log_error (1, err, "can't initialize assuan server");
3303 0 : err = register_commands (server.assuan_ctx);
3304 0 : if (err)
3305 0 : log_error (1, err, "can't register assuan commands");
3306 0 : assuan_set_hello_line (server.assuan_ctx, hello);
3307 :
3308 0 : assuan_register_reset_notify (server.assuan_ctx, reset_notify);
3309 :
3310 : #define DBG_ASSUAN 0
3311 : if (DBG_ASSUAN)
3312 : assuan_set_log_stream (server.assuan_ctx, log_stream);
3313 :
3314 : for (;;)
3315 : {
3316 0 : err = assuan_accept (server.assuan_ctx);
3317 0 : if (err == -1)
3318 0 : break;
3319 0 : else if (err)
3320 : {
3321 0 : log_error (0, err, "assuan accept problem");
3322 0 : break;
3323 : }
3324 :
3325 0 : err = assuan_process (server.assuan_ctx);
3326 0 : if (err)
3327 0 : log_error (0, err, "assuan processing failed");
3328 0 : }
3329 :
3330 0 : assuan_release (server.assuan_ctx);
3331 0 : }
3332 :
3333 :
3334 :
3335 : static const char *
3336 0 : my_strusage( int level )
3337 : {
3338 : const char *p;
3339 :
3340 0 : switch (level)
3341 : {
3342 0 : case 11: p = "gpgme-tool"; break;
3343 0 : case 13: p = PACKAGE_VERSION; break;
3344 0 : case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break;
3345 0 : case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
3346 : case 1:
3347 : case 40:
3348 0 : p = "Usage: gpgme-tool [OPTIONS] [COMMANDS]";
3349 0 : break;
3350 : case 41:
3351 0 : p = "GPGME Tool -- Assuan server exposing GPGME operations\n";
3352 0 : break;
3353 : case 42:
3354 0 : p = "1"; /* Flag print 40 as part of 41. */
3355 0 : break;
3356 0 : default: p = NULL; break;
3357 : }
3358 0 : return p;
3359 : }
3360 :
3361 :
3362 : int
3363 0 : main (int argc, char *argv[])
3364 : {
3365 : static ARGPARSE_OPTS opts[] = {
3366 : ARGPARSE_c ('s', "server", "Server mode"),
3367 : ARGPARSE_s_s(501, "gpg-binary", "|FILE|Use FILE for the GPG backend"),
3368 : ARGPARSE_c (502, "lib-version", "Show library version"),
3369 : ARGPARSE_end()
3370 : };
3371 0 : ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
3372 0 : enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd = CMD_DEFAULT;
3373 0 : const char *gpg_binary = NULL;
3374 : struct gpgme_tool gt;
3375 : gpg_error_t err;
3376 0 : int needgt = 1;
3377 :
3378 0 : set_strusage (my_strusage);
3379 :
3380 : #ifdef HAVE_SETLOCALE
3381 0 : setlocale (LC_ALL, "");
3382 : #endif
3383 0 : gpgme_check_version (NULL);
3384 : #ifdef LC_CTYPE
3385 0 : gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3386 : #endif
3387 : #ifdef LC_MESSAGES
3388 0 : gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3389 : #endif
3390 :
3391 0 : log_init ();
3392 :
3393 0 : while (arg_parse (&pargs, opts))
3394 : {
3395 0 : switch (pargs.r_opt)
3396 : {
3397 0 : case 's': cmd = CMD_SERVER; break;
3398 0 : case 501: gpg_binary = pargs.r.ret_str; break;
3399 0 : case 502: cmd = CMD_LIBVERSION; break;
3400 : default:
3401 0 : pargs.err = ARGPARSE_PRINT_WARNING;
3402 0 : break;
3403 : }
3404 : }
3405 :
3406 0 : if (cmd == CMD_LIBVERSION)
3407 0 : needgt = 0;
3408 :
3409 0 : if (needgt && gpg_binary)
3410 : {
3411 0 : if (access (gpg_binary, X_OK))
3412 0 : err = gpg_error_from_syserror ();
3413 : else
3414 0 : err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP,
3415 : gpg_binary, NULL);
3416 0 : if (err)
3417 0 : log_error (1, err, "error witching OpenPGP engine to '%s'",
3418 : gpg_binary);
3419 : }
3420 :
3421 0 : if (needgt)
3422 0 : gt_init (>);
3423 :
3424 0 : switch (cmd)
3425 : {
3426 : case CMD_DEFAULT:
3427 : case CMD_SERVER:
3428 0 : gpgme_server (>);
3429 0 : break;
3430 :
3431 : case CMD_LIBVERSION:
3432 0 : printf ("Version from header: %s (0x%06x)\n",
3433 : GPGME_VERSION, GPGME_VERSION_NUMBER);
3434 0 : printf ("Version from binary: %s\n", gpgme_check_version (NULL));
3435 0 : printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01"));
3436 0 : break;
3437 : }
3438 :
3439 0 : if (needgt)
3440 0 : gpgme_release (gt.ctx);
3441 :
3442 : #ifdef HAVE_W32CE_SYSTEM
3443 : /* Give the buggy ssh server time to flush the output buffers. */
3444 : Sleep (300);
3445 : #endif
3446 :
3447 0 : return 0;
3448 : }
|