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