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 "&lt;";
399     case '>':
400       return "&gt;";
401     case '&':
402       return "&amp;";
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, &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 (&gt);
3420 
3421   switch (cmd)
3422     {
3423     case CMD_DEFAULT:
3424     case CMD_SERVER:
3425       gpgme_server (&gt);
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