json: Refactor signature and ei code
[gpgme.git] / src / gpgme-json.c
1 /* gpgme-json.c - JSON based interface to gpgme (server)
2  * Copyright (C) 2018 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1+
19  */
20
21 /* This is tool implements the Native Messaging protocol of web
22  * browsers and provides the server part of it.  A Javascript based
23  * client can be found in lang/javascript.
24  */
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #ifdef HAVE_LOCALE_H
32 #include <locale.h>
33 #endif
34 #include <stdint.h>
35 #include <sys/stat.h>
36
37 #define GPGRT_ENABLE_ES_MACROS 1
38 #define GPGRT_ENABLE_LOG_MACROS 1
39 #define GPGRT_ENABLE_ARGPARSE_MACROS 1
40 #include "gpgme.h"
41 #include "cJSON.h"
42
43
44 #if GPGRT_VERSION_NUMBER < 0x011c00 /* 1.28 */
45 int main (void){fputs ("Build with Libgpg-error >= 1.28!\n", stderr);return 1;}
46 #else /* libgpg-error >= 1.28 */
47
48 /* We don't allow a request with more than 64 MiB.  */
49 #define MAX_REQUEST_SIZE (64 * 1024 * 1024)
50
51 /* Minimal, default and maximum chunk size for returned data. The
52  * first chunk is returned directly.  If the "more" flag is also
53  * returned, a "getmore" command needs to be used to get the next
54  * chunk.  Right now this value covers just the value of the "data"
55  * element; so to cover for the other returned objects this values
56  * needs to be lower than the maximum allowed size of the browser. */
57 #define MIN_REPLY_CHUNK_SIZE  512
58 #define DEF_REPLY_CHUNK_SIZE (512 * 1024)
59 #define MAX_REPLY_CHUNK_SIZE (10 * 1024 * 1024)
60
61
62 static void xoutofcore (const char *type) GPGRT_ATTR_NORETURN;
63 static cjson_t error_object_v (cjson_t json, const char *message,
64                                va_list arg_ptr, gpg_error_t err)
65                                GPGRT_ATTR_PRINTF(2,0);
66 static cjson_t error_object (cjson_t json, const char *message,
67                             ...) GPGRT_ATTR_PRINTF(2,3);
68 static char *error_object_string (const char *message,
69                                   ...) GPGRT_ATTR_PRINTF(1,2);
70
71
72 /* True if interactive mode is active.  */
73 static int opt_interactive;
74 /* True is debug mode is active.  */
75 static int opt_debug;
76
77 /* Pending data to be returned by a getmore command.  */
78 static struct
79 {
80   char  *buffer;   /* Malloced data or NULL if not used.  */
81   size_t length;   /* Length of that data.  */
82   size_t written;  /* # of already written bytes from BUFFER.  */
83   const char *type;/* The "type" of the data.  */
84   int base64;      /* The "base64" flag of the data.  */
85 } pending_data;
86
87
88 /*
89  * Helper functions and macros
90  */
91
92 #define xtrymalloc(a)  gpgrt_malloc ((a))
93 #define xtrystrdup(a)  gpgrt_strdup ((a))
94 #define xmalloc(a) ({                           \
95       void *_r = gpgrt_malloc ((a));            \
96       if (!_r)                                  \
97         xoutofcore ("malloc");                  \
98       _r; })
99 #define xcalloc(a,b) ({                         \
100       void *_r = gpgrt_calloc ((a), (b));       \
101       if (!_r)                                  \
102         xoutofcore ("calloc");                  \
103       _r; })
104 #define xstrdup(a) ({                           \
105       char *_r = gpgrt_strdup ((a));            \
106       if (!_r)                                  \
107         xoutofcore ("strdup");                  \
108       _r; })
109 #define xstrconcat(a, ...) ({                           \
110       char *_r = gpgrt_strconcat ((a), __VA_ARGS__);    \
111       if (!_r)                                          \
112         xoutofcore ("strconcat");                       \
113       _r; })
114 #define xfree(a) gpgrt_free ((a))
115
116 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
117
118 #ifndef HAVE_STPCPY
119 static GPGRT_INLINE char *
120 _my_stpcpy (char *a, const char *b)
121 {
122   while (*b)
123     *a++ = *b++;
124   *a = 0;
125   return a;
126 }
127 #define stpcpy(a,b) _my_stpcpy ((a), (b))
128 #endif /*!HAVE_STPCPY*/
129
130
131
132 static void
133 xoutofcore (const char *type)
134 {
135   gpg_error_t err = gpg_error_from_syserror ();
136   log_error ("%s failed: %s\n", type, gpg_strerror (err));
137   exit (2);
138 }
139
140
141 /* Call cJSON_CreateObject but terminate in case of an error.  */
142 static cjson_t
143 xjson_CreateObject (void)
144 {
145   cjson_t json = cJSON_CreateObject ();
146   if (!json)
147     xoutofcore ("cJSON_CreateObject");
148   return json;
149 }
150
151 /* Call cJSON_CreateArray but terminate in case of an error.  */
152 static cjson_t
153 xjson_CreateArray (void)
154 {
155   cjson_t json = cJSON_CreateArray ();
156   if (!json)
157     xoutofcore ("cJSON_CreateArray");
158   return json;
159 }
160
161
162 /* Wrapper around cJSON_AddStringToObject which returns an gpg-error
163  * code instead of the NULL or the new object.  */
164 static gpg_error_t
165 cjson_AddStringToObject (cjson_t object, const char *name, const char *string)
166 {
167   if (!cJSON_AddStringToObject (object, name, string))
168     return gpg_error_from_syserror ();
169   return 0;
170 }
171
172
173 /* Same as cjson_AddStringToObject but prints an error message and
174  * terminates the process.  */
175 static void
176 xjson_AddStringToObject (cjson_t object, const char *name, const char *string)
177 {
178   if (!cJSON_AddStringToObject (object, name, string))
179     xoutofcore ("cJSON_AddStringToObject");
180 }
181
182
183 /* Same as xjson_AddStringToObject but ignores NULL strings */
184 static void
185 xjson_AddStringToObject0 (cjson_t object, const char *name, const char *string)
186 {
187   if (!string)
188     return;
189   xjson_AddStringToObject (object, name, string);
190 }
191
192 /* Wrapper around cJSON_AddBoolToObject which terminates the process
193  * in case of an error.  */
194 static void
195 xjson_AddBoolToObject (cjson_t object, const char *name, int abool)
196 {
197   if (!cJSON_AddBoolToObject (object, name, abool))
198     xoutofcore ("cJSON_AddStringToObject");
199   return ;
200 }
201
202 /* Wrapper around cJSON_AddNumberToObject which terminates the process
203  * in case of an error.  */
204 static void
205 xjson_AddNumberToObject (cjson_t object, const char *name, double dbl)
206 {
207   if (!cJSON_AddNumberToObject (object, name, dbl))
208     xoutofcore ("cJSON_AddNumberToObject");
209   return ;
210 }
211
212 /* Wrapper around cJSON_AddItemToObject which terminates the process
213  * in case of an error.  */
214 static void
215 xjson_AddItemToObject (cjson_t object, const char *name, cjson_t item)
216 {
217   if (!cJSON_AddItemToObject (object, name, item))
218     xoutofcore ("cJSON_AddItemToObject");
219   return ;
220 }
221
222 /* This is similar to cJSON_AddStringToObject but takes (DATA,
223  * DATALEN) and adds it under NAME as a base 64 encoded string to
224  * OBJECT.  */
225 static gpg_error_t
226 add_base64_to_object (cjson_t object, const char *name,
227                       const void *data, size_t datalen)
228 {
229 #if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
230   return gpg_error (GPG_ERR_NOT_SUPPORTED);
231 #else
232   gpg_err_code_t err;
233   estream_t fp = NULL;
234   gpgrt_b64state_t state = NULL;
235   cjson_t j_str = NULL;
236   void *buffer = NULL;
237
238   fp = es_fopenmem (0, "rwb");
239   if (!fp)
240     {
241       err = gpg_err_code_from_syserror ();
242       goto leave;
243     }
244   state = gpgrt_b64enc_start (fp, "");
245   if (!state)
246     {
247       err = gpg_err_code_from_syserror ();
248       goto leave;
249     }
250
251   err = gpgrt_b64enc_write (state, data, datalen);
252   if (err)
253     goto leave;
254
255   err = gpgrt_b64enc_finish (state);
256   state = NULL;
257   if (err)
258     return err;
259
260   es_fputc (0, fp);
261   if (es_fclose_snatch (fp, &buffer, NULL))
262     {
263       fp = NULL;
264       err = gpg_error_from_syserror ();
265       goto leave;
266     }
267   fp = NULL;
268
269   j_str = cJSON_CreateStringConvey (buffer);
270   if (!j_str)
271     {
272       err = gpg_error_from_syserror ();
273       goto leave;
274     }
275   buffer = NULL;
276
277   if (!cJSON_AddItemToObject (object, name, j_str))
278     {
279       err = gpg_error_from_syserror ();
280       cJSON_Delete (j_str);
281       j_str = NULL;
282       goto leave;
283     }
284   j_str = NULL;
285
286  leave:
287   xfree (buffer);
288   cJSON_Delete (j_str);
289   gpgrt_b64enc_finish (state);
290   es_fclose (fp);
291   return err;
292 #endif
293 }
294
295
296 /* Create a JSON error object.  If JSON is not NULL the error message
297  * is appended to that object.  An existing "type" item will be replaced. */
298 static cjson_t
299 error_object_v (cjson_t json, const char *message, va_list arg_ptr,
300                 gpg_error_t err)
301 {
302   cjson_t response, j_tmp;
303   char *msg;
304
305   msg = gpgrt_vbsprintf (message, arg_ptr);
306   if (!msg)
307     xoutofcore ("error_object");
308
309   response = json? json : xjson_CreateObject ();
310
311   if (!(j_tmp = cJSON_GetObjectItem (response, "type")))
312     xjson_AddStringToObject (response, "type", "error");
313   else /* Replace existing "type".  */
314     {
315       j_tmp = cJSON_CreateString ("error");
316       if (!j_tmp)
317         xoutofcore ("cJSON_CreateString");
318       cJSON_ReplaceItemInObject (response, "type", j_tmp);
319      }
320   xjson_AddStringToObject (response, "msg", msg);
321   xfree (msg);
322
323   xjson_AddNumberToObject (response, "code", err);
324
325   return response;
326 }
327
328
329 /* Call cJSON_Print but terminate in case of an error.  */
330 static char *
331 xjson_Print (cjson_t object)
332 {
333   char *buf;
334   buf = cJSON_Print (object);
335   if (!buf)
336     xoutofcore ("cJSON_Print");
337   return buf;
338 }
339
340
341 static cjson_t
342 error_object (cjson_t json, const char *message, ...)
343 {
344   cjson_t response;
345   va_list arg_ptr;
346
347   va_start (arg_ptr, message);
348   response = error_object_v (json, message, arg_ptr, 0);
349   va_end (arg_ptr);
350   return response;
351 }
352
353
354 static cjson_t
355 gpg_error_object (cjson_t json, gpg_error_t err, const char *message, ...)
356 {
357   cjson_t response;
358   va_list arg_ptr;
359
360   va_start (arg_ptr, message);
361   response = error_object_v (json, message, arg_ptr, err);
362   va_end (arg_ptr);
363   return response;
364 }
365
366
367 static char *
368 error_object_string (const char *message, ...)
369 {
370   cjson_t response;
371   va_list arg_ptr;
372   char *msg;
373
374   va_start (arg_ptr, message);
375   response = error_object_v (NULL, message, arg_ptr, 0);
376   va_end (arg_ptr);
377
378   msg = xjson_Print (response);
379   cJSON_Delete (response);
380   return msg;
381 }
382
383
384 /* Get the boolean property NAME from the JSON object and store true
385  * or valse at R_VALUE.  If the name is unknown the value of DEF_VALUE
386  * is returned.  If the type of the value is not boolean,
387  * GPG_ERR_INV_VALUE is returned and R_VALUE set to DEF_VALUE.  */
388 static gpg_error_t
389 get_boolean_flag (cjson_t json, const char *name, int def_value, int *r_value)
390 {
391   cjson_t j_item;
392
393   j_item = cJSON_GetObjectItem (json, name);
394   if (!j_item)
395     *r_value = def_value;
396   else if (cjson_is_true (j_item))
397     *r_value = 1;
398   else if (cjson_is_false (j_item))
399     *r_value = 0;
400   else
401     {
402       *r_value = def_value;
403       return gpg_error (GPG_ERR_INV_VALUE);
404     }
405
406   return 0;
407 }
408
409
410 /* Get the boolean property PROTOCOL from the JSON object and store
411  * its value at R_PROTOCOL.  The default is OpenPGP.  */
412 static gpg_error_t
413 get_protocol (cjson_t json, gpgme_protocol_t *r_protocol)
414 {
415   cjson_t j_item;
416
417   *r_protocol = GPGME_PROTOCOL_OpenPGP;
418   j_item = cJSON_GetObjectItem (json, "protocol");
419   if (!j_item)
420     ;
421   else if (!cjson_is_string (j_item))
422     return gpg_error (GPG_ERR_INV_VALUE);
423   else if (!strcmp(j_item->valuestring, "openpgp"))
424     ;
425   else if (!strcmp(j_item->valuestring, "cms"))
426     *r_protocol = GPGME_PROTOCOL_CMS;
427   else
428     return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
429
430   return 0;
431 }
432
433
434 /* Get the chunksize from JSON and store it at R_CHUNKSIZE.  */
435 static gpg_error_t
436 get_chunksize (cjson_t json, size_t *r_chunksize)
437 {
438   cjson_t j_item;
439
440   *r_chunksize = DEF_REPLY_CHUNK_SIZE;
441   j_item = cJSON_GetObjectItem (json, "chunksize");
442   if (!j_item)
443     ;
444   else if (!cjson_is_number (j_item))
445     return gpg_error (GPG_ERR_INV_VALUE);
446   else if ((size_t)j_item->valueint < MIN_REPLY_CHUNK_SIZE)
447     *r_chunksize = MIN_REPLY_CHUNK_SIZE;
448   else if ((size_t)j_item->valueint > MAX_REPLY_CHUNK_SIZE)
449     *r_chunksize = MAX_REPLY_CHUNK_SIZE;
450   else
451     *r_chunksize = (size_t)j_item->valueint;
452
453   return 0;
454 }
455
456
457 /* Extract the keys from the "keys" array in the JSON object.  On
458  * success a string with the keys identifiers is stored at R_KEYS.
459  * The keys in that string are LF delimited.  On failure an error code
460  * is returned.  */
461 static gpg_error_t
462 get_keys (cjson_t json, char **r_keystring)
463 {
464   cjson_t j_keys, j_item;
465   int i, nkeys;
466   char *p;
467   size_t length;
468
469   *r_keystring = NULL;
470
471   j_keys = cJSON_GetObjectItem (json, "keys");
472   if (!j_keys)
473     return gpg_error (GPG_ERR_NO_KEY);
474   if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys))
475     return gpg_error (GPG_ERR_INV_VALUE);
476
477   /* Fixme: We should better use a membuf like thing.  */
478   length = 1; /* For the EOS.  */
479   if (cjson_is_string (j_keys))
480     {
481       nkeys = 1;
482       length += strlen (j_keys->valuestring);
483       if (strchr (j_keys->valuestring, '\n'))
484         return gpg_error (GPG_ERR_INV_USER_ID);
485     }
486   else
487     {
488       nkeys = cJSON_GetArraySize (j_keys);
489       if (!nkeys)
490         return gpg_error (GPG_ERR_NO_KEY);
491       for (i=0; i < nkeys; i++)
492         {
493           j_item = cJSON_GetArrayItem (j_keys, i);
494           if (!j_item || !cjson_is_string (j_item))
495             return gpg_error (GPG_ERR_INV_VALUE);
496           if (i)
497             length++; /* Space for delimiter. */
498           length += strlen (j_item->valuestring);
499           if (strchr (j_item->valuestring, '\n'))
500             return gpg_error (GPG_ERR_INV_USER_ID);
501         }
502     }
503
504   p = *r_keystring = xtrymalloc (length);
505   if (!p)
506     return gpg_error_from_syserror ();
507
508   if (cjson_is_string (j_keys))
509     {
510       strcpy (p, j_keys->valuestring);
511     }
512   else
513     {
514       for (i=0; i < nkeys; i++)
515         {
516           j_item = cJSON_GetArrayItem (j_keys, i);
517           if (i)
518             *p++ = '\n'; /* Add delimiter.  */
519           p = stpcpy (p, j_item->valuestring);
520         }
521     }
522   return 0;
523 }
524
525
526
527 \f
528 /*
529  *  GPGME support functions.
530  */
531
532 /* Helper for get_context.  */
533 static gpgme_ctx_t
534 _create_new_context (gpgme_protocol_t proto)
535 {
536   gpg_error_t err;
537   gpgme_ctx_t ctx;
538
539   err = gpgme_new (&ctx);
540   if (err)
541     log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
542   gpgme_set_protocol (ctx, proto);
543   gpgme_set_ctx_flag (ctx, "request-origin", "browser");
544   return ctx;
545 }
546
547
548 /* Return a context object for protocol PROTO.  This is currently a
549  * statically allocated context initialized for PROTO.  Terminates
550  * process on failure.  */
551 static gpgme_ctx_t
552 get_context (gpgme_protocol_t proto)
553 {
554   static gpgme_ctx_t ctx_openpgp, ctx_cms;
555
556   if (proto == GPGME_PROTOCOL_OpenPGP)
557     {
558       if (!ctx_openpgp)
559         ctx_openpgp = _create_new_context (proto);
560       return ctx_openpgp;
561     }
562   else if (proto == GPGME_PROTOCOL_CMS)
563     {
564       if (!ctx_cms)
565         ctx_cms = _create_new_context (proto);
566       return ctx_cms;
567     }
568   else
569     log_bug ("invalid protocol %d requested\n", proto);
570 }
571
572
573
574 /* Free context object retrieved by get_context.  */
575 static void
576 release_context (gpgme_ctx_t ctx)
577 {
578   /* Nothing to do right now.  */
579   (void)ctx;
580 }
581
582
583
584 /* Given a Base-64 encoded string object in JSON return a gpgme data
585  * object at R_DATA.  */
586 static gpg_error_t
587 data_from_base64_string (gpgme_data_t *r_data, cjson_t json)
588 {
589 #if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
590   *r_data = NULL;
591   return gpg_error (GPG_ERR_NOT_SUPPORTED);
592 #else
593   gpg_error_t err;
594   size_t len;
595   char *buf = NULL;
596   gpgrt_b64state_t state = NULL;
597   gpgme_data_t data = NULL;
598
599   *r_data = NULL;
600
601   /* A quick check on the JSON.  */
602   if (!cjson_is_string (json))
603     {
604       err = gpg_error (GPG_ERR_INV_VALUE);
605       goto leave;
606     }
607
608   state = gpgrt_b64dec_start (NULL);
609   if (!state)
610     {
611       err = gpg_err_code_from_syserror ();
612       goto leave;
613     }
614
615   /* Fixme: Data duplication - we should see how to snatch the memory
616    * from the json object.  */
617   len = strlen (json->valuestring);
618   buf = xtrystrdup (json->valuestring);
619   if (!buf)
620     {
621       err = gpg_error_from_syserror ();
622       goto leave;
623     }
624
625   err = gpgrt_b64dec_proc (state, buf, len, &len);
626   if (err)
627     goto leave;
628
629   err = gpgrt_b64dec_finish (state);
630   state = NULL;
631   if (err)
632     goto leave;
633
634   err = gpgme_data_new_from_mem (&data, buf, len, 1);
635   if (err)
636     goto leave;
637   *r_data = data;
638   data = NULL;
639
640  leave:
641   xfree (data);
642   xfree (buf);
643   gpgrt_b64dec_finish (state);
644   return err;
645 #endif
646 }
647
648
649 /* Create sigsum json array */
650 static cjson_t
651 sigsum_to_json (gpgme_sigsum_t summary)
652 {
653   cjson_t result = xjson_CreateArray ();
654
655   if ( (summary & GPGME_SIGSUM_VALID      ))
656     cJSON_AddItemToArray (result,
657         cJSON_CreateString ("valid"));
658   if ( (summary & GPGME_SIGSUM_GREEN      ))
659     cJSON_AddItemToArray (result,
660         cJSON_CreateString ("green"));
661   if ( (summary & GPGME_SIGSUM_RED        ))
662     cJSON_AddItemToArray (result,
663         cJSON_CreateString ("red"));
664   if ( (summary & GPGME_SIGSUM_KEY_REVOKED))
665     cJSON_AddItemToArray (result,
666         cJSON_CreateString ("revoked"));
667   if ( (summary & GPGME_SIGSUM_KEY_EXPIRED))
668     cJSON_AddItemToArray (result,
669         cJSON_CreateString ("key-expired"));
670   if ( (summary & GPGME_SIGSUM_SIG_EXPIRED))
671     cJSON_AddItemToArray (result,
672         cJSON_CreateString ("sig-expired"));
673   if ( (summary & GPGME_SIGSUM_KEY_MISSING))
674     cJSON_AddItemToArray (result,
675         cJSON_CreateString ("key-missing"));
676   if ( (summary & GPGME_SIGSUM_CRL_MISSING))
677     cJSON_AddItemToArray (result,
678         cJSON_CreateString ("crl-missing"));
679   if ( (summary & GPGME_SIGSUM_CRL_TOO_OLD))
680     cJSON_AddItemToArray (result,
681         cJSON_CreateString ("crl-too-old"));
682   if ( (summary & GPGME_SIGSUM_BAD_POLICY ))
683     cJSON_AddItemToArray (result,
684         cJSON_CreateString ("bad-policy"));
685   if ( (summary & GPGME_SIGSUM_SYS_ERROR  ))
686     cJSON_AddItemToArray (result,
687         cJSON_CreateString ("sys-error"));
688
689   return result;
690 }
691
692
693 /* Helper for summary formatting */
694 static const char *
695 validity_to_string (gpgme_validity_t val)
696 {
697   switch (val)
698     {
699     case GPGME_VALIDITY_UNDEFINED:return "undefined";
700     case GPGME_VALIDITY_NEVER:    return "never";
701     case GPGME_VALIDITY_MARGINAL: return "marginal";
702     case GPGME_VALIDITY_FULL:     return "full";
703     case GPGME_VALIDITY_ULTIMATE: return "ultimate";
704     case GPGME_VALIDITY_UNKNOWN:
705     default:                      return "unknown";
706     }
707 }
708
709 static const char *
710 protocol_to_string (gpgme_protocol_t proto)
711 {
712   switch (proto)
713     {
714     case GPGME_PROTOCOL_OpenPGP: return "OpenPGP";
715     case GPGME_PROTOCOL_CMS:     return "CMS";
716     case GPGME_PROTOCOL_GPGCONF: return "gpgconf";
717     case GPGME_PROTOCOL_ASSUAN:  return "assuan";
718     case GPGME_PROTOCOL_G13:     return "g13";
719     case GPGME_PROTOCOL_UISERVER:return "uiserver";
720     case GPGME_PROTOCOL_SPAWN:   return "spawn";
721     default:
722                                  return "unknown";
723     }
724 }
725
726 /* Create a sig_notation json object */
727 static cjson_t
728 sig_notation_to_json (gpgme_sig_notation_t not)
729 {
730   cjson_t result = xjson_CreateObject ();
731   xjson_AddBoolToObject (result, "human_readable", not->human_readable);
732   xjson_AddBoolToObject (result, "critical", not->critical);
733
734   xjson_AddStringToObject0 (result, "name", not->name);
735   xjson_AddStringToObject0 (result, "value", not->value);
736
737   xjson_AddNumberToObject (result, "flags", not->flags);
738
739   return result;
740 }
741
742 /* Create a key_sig json object */
743 static cjson_t
744 key_sig_to_json (gpgme_key_sig_t sig)
745 {
746   cjson_t result = xjson_CreateObject ();
747
748   xjson_AddBoolToObject (result, "revoked", sig->revoked);
749   xjson_AddBoolToObject (result, "expired", sig->expired);
750   xjson_AddBoolToObject (result, "invalid", sig->invalid);
751   xjson_AddBoolToObject (result, "exportable", sig->exportable);
752
753   xjson_AddStringToObject0 (result, "pubkey_algo_name",
754                             gpgme_pubkey_algo_name (sig->pubkey_algo));
755   xjson_AddStringToObject0 (result, "keyid", sig->keyid);
756   xjson_AddStringToObject0 (result, "status", gpgme_strerror (sig->status));
757   xjson_AddStringToObject0 (result, "name", sig->name);
758   xjson_AddStringToObject0 (result, "email", sig->email);
759   xjson_AddStringToObject0 (result, "comment", sig->comment);
760
761   xjson_AddNumberToObject (result, "pubkey_algo", sig->pubkey_algo);
762   xjson_AddNumberToObject (result, "timestamp", sig->timestamp);
763   xjson_AddNumberToObject (result, "expires", sig->expires);
764   xjson_AddNumberToObject (result, "status_code", sig->status);
765   xjson_AddNumberToObject (result, "sig_class", sig->sig_class);
766
767   if (sig->notations)
768     {
769       gpgme_sig_notation_t not;
770       cjson_t array = xjson_CreateArray ();
771       for (not = sig->notations; not; not = not->next)
772         cJSON_AddItemToArray (array, sig_notation_to_json (not));
773       xjson_AddItemToObject (result, "notations", array);
774     }
775
776   return result;
777 }
778
779 /* Create a tofu info object */
780 static cjson_t
781 tofu_to_json (gpgme_tofu_info_t tofu)
782 {
783   cjson_t result = xjson_CreateObject ();
784
785   xjson_AddStringToObject0 (result, "description", tofu->description);
786
787   xjson_AddNumberToObject (result, "validity", tofu->validity);
788   xjson_AddNumberToObject (result, "policy", tofu->policy);
789   xjson_AddNumberToObject (result, "signcount", tofu->signcount);
790   xjson_AddNumberToObject (result, "encrcount", tofu->encrcount);
791   xjson_AddNumberToObject (result, "signfirst", tofu->signfirst);
792   xjson_AddNumberToObject (result, "signlast", tofu->signlast);
793   xjson_AddNumberToObject (result, "encrfirst", tofu->encrfirst);
794   xjson_AddNumberToObject (result, "encrlast", tofu->encrlast);
795
796   return result;
797 }
798
799 /* Create a userid json object */
800 static cjson_t
801 uid_to_json (gpgme_user_id_t uid)
802 {
803   cjson_t result = xjson_CreateObject ();
804
805   xjson_AddBoolToObject (result, "revoked", uid->revoked);
806   xjson_AddBoolToObject (result, "invalid", uid->invalid);
807
808   xjson_AddStringToObject0 (result, "validity",
809                             validity_to_string (uid->validity));
810   xjson_AddStringToObject0 (result, "uid", uid->uid);
811   xjson_AddStringToObject0 (result, "name", uid->name);
812   xjson_AddStringToObject0 (result, "email", uid->email);
813   xjson_AddStringToObject0 (result, "comment", uid->comment);
814   xjson_AddStringToObject0 (result, "address", uid->address);
815
816   xjson_AddNumberToObject (result, "origin", uid->origin);
817   xjson_AddNumberToObject (result, "last_update", uid->last_update);
818
819   /* Key sigs */
820   if (uid->signatures)
821     {
822       cjson_t sig_array = xjson_CreateArray ();
823       gpgme_key_sig_t sig;
824
825       for (sig = uid->signatures; sig; sig = sig->next)
826         cJSON_AddItemToArray (sig_array, key_sig_to_json (sig));
827
828       xjson_AddItemToObject (result, "signatures", sig_array);
829     }
830
831   /* TOFU info */
832   if (uid->tofu)
833     {
834       gpgme_tofu_info_t tofu;
835       cjson_t array = xjson_CreateArray ();
836       for (tofu = uid->tofu; tofu; tofu = tofu->next)
837         cJSON_AddItemToArray (array, tofu_to_json (tofu));
838       xjson_AddItemToObject (result, "tofu", array);
839     }
840
841   return result;
842 }
843
844 /* Create a subkey json object */
845 static cjson_t
846 subkey_to_json (gpgme_subkey_t sub)
847 {
848   cjson_t result = xjson_CreateObject ();
849
850   xjson_AddBoolToObject (result, "revoked", sub->revoked);
851   xjson_AddBoolToObject (result, "expired", sub->expired);
852   xjson_AddBoolToObject (result, "disabled", sub->disabled);
853   xjson_AddBoolToObject (result, "invalid", sub->invalid);
854   xjson_AddBoolToObject (result, "can_encrypt", sub->can_encrypt);
855   xjson_AddBoolToObject (result, "can_sign", sub->can_sign);
856   xjson_AddBoolToObject (result, "can_certify", sub->can_certify);
857   xjson_AddBoolToObject (result, "can_authenticate", sub->can_authenticate);
858   xjson_AddBoolToObject (result, "secret", sub->secret);
859   xjson_AddBoolToObject (result, "is_qualified", sub->is_qualified);
860   xjson_AddBoolToObject (result, "is_cardkey", sub->is_cardkey);
861   xjson_AddBoolToObject (result, "is_de_vs", sub->is_de_vs);
862
863   xjson_AddStringToObject0 (result, "pubkey_algo_name",
864                             gpgme_pubkey_algo_name (sub->pubkey_algo));
865   xjson_AddStringToObject0 (result, "pubkey_algo_string",
866                             gpgme_pubkey_algo_string (sub));
867   xjson_AddStringToObject0 (result, "keyid", sub->keyid);
868   xjson_AddStringToObject0 (result, "card_number", sub->card_number);
869   xjson_AddStringToObject0 (result, "curve", sub->curve);
870   xjson_AddStringToObject0 (result, "keygrip", sub->keygrip);
871
872   xjson_AddNumberToObject (result, "pubkey_algo", sub->pubkey_algo);
873   xjson_AddNumberToObject (result, "length", sub->length);
874   xjson_AddNumberToObject (result, "timestamp", sub->timestamp);
875   xjson_AddNumberToObject (result, "expires", sub->expires);
876
877   return result;
878 }
879
880 /* Create a key json object */
881 static cjson_t
882 key_to_json (gpgme_key_t key)
883 {
884   cjson_t result = xjson_CreateObject ();
885
886   xjson_AddBoolToObject (result, "revoked", key->revoked);
887   xjson_AddBoolToObject (result, "expired", key->expired);
888   xjson_AddBoolToObject (result, "disabled", key->disabled);
889   xjson_AddBoolToObject (result, "invalid", key->invalid);
890   xjson_AddBoolToObject (result, "can_encrypt", key->can_encrypt);
891   xjson_AddBoolToObject (result, "can_sign", key->can_sign);
892   xjson_AddBoolToObject (result, "can_certify", key->can_certify);
893   xjson_AddBoolToObject (result, "can_authenticate", key->can_authenticate);
894   xjson_AddBoolToObject (result, "secret", key->secret);
895   xjson_AddBoolToObject (result, "is_qualified", key->is_qualified);
896
897   xjson_AddStringToObject0 (result, "protocol",
898                             protocol_to_string (key->protocol));
899   xjson_AddStringToObject0 (result, "issuer_serial", key->issuer_serial);
900   xjson_AddStringToObject0 (result, "issuer_name", key->issuer_name);
901   xjson_AddStringToObject0 (result, "fingerprint", key->fpr);
902   xjson_AddStringToObject0 (result, "chain_id", key->chain_id);
903   xjson_AddStringToObject0 (result, "owner_trust",
904                             validity_to_string (key->owner_trust));
905
906   xjson_AddNumberToObject (result, "origin", key->origin);
907   xjson_AddNumberToObject (result, "last_update", key->last_update);
908
909   /* Add subkeys */
910   if (key->subkeys)
911     {
912       cjson_t subkey_array = xjson_CreateArray ();
913       gpgme_subkey_t sub;
914       for (sub = key->subkeys; sub; sub = sub->next)
915         cJSON_AddItemToArray (subkey_array, subkey_to_json (sub));
916
917       xjson_AddItemToObject (result, "subkeys", subkey_array);
918     }
919
920   /* User Ids */
921   if (key->uids)
922     {
923       cjson_t uid_array = xjson_CreateArray ();
924       gpgme_user_id_t uid;
925       for (uid = key->uids; uid; uid = uid->next)
926         cJSON_AddItemToArray (uid_array, uid_to_json (uid));
927
928       xjson_AddItemToObject (result, "userids", uid_array);
929     }
930
931   return result;
932 }
933
934 /* Create a signature json object */
935 static cjson_t
936 signature_to_json (gpgme_signature_t sig)
937 {
938   cjson_t result = xjson_CreateObject ();
939
940   xjson_AddStringToObject0 (result, "status",
941                             gpgme_strerror (sig->status));
942
943   xjson_AddStringToObject0 (result, "validity",
944                             validity_to_string (sig->validity));
945   xjson_AddStringToObject0 (result, "fingerprint", sig->fpr);
946
947   xjson_AddItemToObject (result, "summary", sigsum_to_json (sig->summary));
948
949   xjson_AddNumberToObject (result, "created", sig->timestamp);
950   xjson_AddNumberToObject (result, "expired", sig->exp_timestamp);
951   xjson_AddNumberToObject (result, "code", sig->status);
952
953   return result;
954 }
955
956 /* Create a JSON object from a gpgme_verify result */
957 static cjson_t
958 verify_result_to_json (gpgme_verify_result_t verify_result)
959 {
960   cjson_t response = xjson_CreateObject ();
961
962   if (verify_result->signatures)
963     {
964       cjson_t array = xjson_CreateArray ();
965       gpgme_signature_t sig;
966
967       for (sig = verify_result->signatures; sig; sig = sig->next)
968         cJSON_AddItemToArray (array, signature_to_json (sig));
969       xjson_AddItemToObject (response, "signatures", array);
970     }
971
972   return response;
973 }
974
975 /* Create a JSON object from an engine_info */
976 static cjson_t
977 engine_info_to_json (gpgme_engine_info_t info)
978 {
979   cjson_t result = xjson_CreateObject ();
980
981   xjson_AddStringToObject0 (result, "protocol",
982                             protocol_to_string (info->protocol));
983   xjson_AddStringToObject0 (result, "fname", info->file_name);
984   xjson_AddStringToObject0 (result, "version", info->version);
985   xjson_AddStringToObject0 (result, "req_version", info->req_version);
986   xjson_AddStringToObject0 (result, "homedir", info->home_dir ?
987                                                 info->home_dir :
988                                                 "default");
989   return result;
990 }
991
992 /* Create a gpgme_data from json string data named "name"
993  * in the request. Takes the base64 option into account.
994  *
995  * Adds an error to the "result" on error. */
996 static gpg_error_t
997 get_string_data (cjson_t request, cjson_t result, const char *name,
998                  gpgme_data_t *r_data)
999 {
1000   gpgme_error_t err;
1001   int opt_base64;
1002   cjson_t j_data;
1003
1004   if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
1005     return err;
1006
1007   /* Get the data.  Note that INPUT is a shallow data object with the
1008    * storage hold in REQUEST.  */
1009   j_data = cJSON_GetObjectItem (request, name);
1010   if (!j_data)
1011     {
1012       return gpg_error (GPG_ERR_NO_DATA);
1013     }
1014   if (!cjson_is_string (j_data))
1015     {
1016       return gpg_error (GPG_ERR_INV_VALUE);
1017     }
1018   if (opt_base64)
1019     {
1020       err = data_from_base64_string (r_data, j_data);
1021       if (err)
1022         {
1023           gpg_error_object (result, err,
1024                             "Error decoding Base-64 encoded '%s': %s",
1025                             name, gpg_strerror (err));
1026           return err;
1027         }
1028     }
1029   else
1030     {
1031       err = gpgme_data_new_from_mem (r_data, j_data->valuestring,
1032                                      strlen (j_data->valuestring), 0);
1033       if (err)
1034         {
1035           gpg_error_object (result, err, "Error getting '%s': %s",
1036                             name, gpg_strerror (err));
1037           return err;
1038         }
1039     }
1040   return 0;
1041 }
1042
1043 \f
1044 /*
1045  * Implementation of the commands.
1046  */
1047
1048
1049 /* Create a "data" object and the "type", "base64" and "more" flags
1050  * from DATA and append them to RESULT.  Ownership of DATA is
1051  * transferred to this function.  TYPE must be a fixed string.
1052  * CHUNKSIZE is the chunksize requested from the caller.  If BASE64 is
1053  * -1 the need for base64 encoding is determined by the content of
1054  * DATA, all other values are taken as true or false.  Note that
1055  * op_getmore has similar code but works on PENDING_DATA which is set
1056  * here.  */
1057 static gpg_error_t
1058 make_data_object (cjson_t result, gpgme_data_t data, size_t chunksize,
1059                   const char *type, int base64)
1060 {
1061   gpg_error_t err;
1062   char *buffer;
1063   const char *s;
1064   size_t buflen, n;
1065   int c;
1066
1067   if (!base64 || base64 == -1) /* Make sure that we really have a string.  */
1068     gpgme_data_write (data, "", 1);
1069
1070   buffer = gpgme_data_release_and_get_mem (data, &buflen);
1071   data = NULL;
1072   if (!buffer)
1073     {
1074       err = gpg_error_from_syserror ();
1075       goto leave;
1076     }
1077
1078   if (base64 == -1)
1079     {
1080       base64 = 0;
1081       if (!buflen)
1082         log_fatal ("Appended Nul byte got lost\n");
1083       /* Figure out if there is any Nul octet in the buffer.  In that
1084        * case we need to Base-64 the buffer.  Due to problems with the
1085        * browser's Javascript we use Base-64 also in case an UTF-8
1086        * character is in the buffer.  This is because the chunking may
1087        * split an UTF-8 characters and JS can't handle this.  */
1088       for (s=buffer, n=0; n < buflen -1; s++, n++)
1089         if (!*s || (*s & 0x80))
1090           {
1091             buflen--; /* Adjust for the extra nul byte.  */
1092             base64 = 1;
1093             break;
1094           }
1095     }
1096
1097   /* Adjust the chunksize if we need to do base64 conversion.  */
1098   if (base64)
1099     chunksize = (chunksize / 4) * 3;
1100
1101   xjson_AddStringToObject (result, "type", type);
1102   xjson_AddBoolToObject (result, "base64", base64);
1103
1104   if (buflen > chunksize)
1105     {
1106       xjson_AddBoolToObject (result, "more", 1);
1107
1108       c = buffer[chunksize];
1109       buffer[chunksize] = 0;
1110       if (base64)
1111         err = add_base64_to_object (result, "data", buffer, chunksize);
1112       else
1113         err = cjson_AddStringToObject (result, "data", buffer);
1114       buffer[chunksize] = c;
1115       if (err)
1116         goto leave;
1117
1118       pending_data.buffer = buffer;
1119       buffer = NULL;
1120       pending_data.length = buflen;
1121       pending_data.written = chunksize;
1122       pending_data.type = type;
1123       pending_data.base64 = base64;
1124     }
1125   else
1126     {
1127       if (base64)
1128         err = add_base64_to_object (result, "data", buffer, buflen);
1129       else
1130         err = cjson_AddStringToObject (result, "data", buffer);
1131     }
1132
1133  leave:
1134   gpgme_free (buffer);
1135   return err;
1136 }
1137
1138
1139 \f
1140 static const char hlp_encrypt[] =
1141   "op:     \"encrypt\"\n"
1142   "keys:   Array of strings with the fingerprints or user-ids\n"
1143   "        of the keys to encrypt the data.  For a single key\n"
1144   "        a String may be used instead of an array.\n"
1145   "data:   Input data. \n"
1146   "\n"
1147   "Optional parameters:\n"
1148   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1149   "chunksize:     Max number of bytes in the resulting \"data\".\n"
1150   "\n"
1151   "Optional boolean flags (default is false):\n"
1152   "base64:        Input data is base64 encoded.\n"
1153   "mime:          Indicate that data is a MIME object.\n"
1154   "armor:         Request output in armored format.\n"
1155   "always-trust:  Request --always-trust option.\n"
1156   "no-encrypt-to: Do not use a default recipient.\n"
1157   "no-compress:   Do not compress the plaintext first.\n"
1158   "throw-keyids:  Request the --throw-keyids option.\n"
1159   "want-address:  Require that the keys include a mail address.\n"
1160   "wrap:          Assume the input is an OpenPGP message.\n"
1161   "\n"
1162   "Response on success:\n"
1163   "type:   \"ciphertext\"\n"
1164   "data:   Unless armor mode is used a Base64 encoded binary\n"
1165   "        ciphertext.  In armor mode a string with an armored\n"
1166   "        OpenPGP or a PEM message.\n"
1167   "base64: Boolean indicating whether data is base64 encoded.\n"
1168   "more:   Optional boolean indicating that \"getmore\" is required.";
1169 static gpg_error_t
1170 op_encrypt (cjson_t request, cjson_t result)
1171 {
1172   gpg_error_t err;
1173   gpgme_ctx_t ctx = NULL;
1174   gpgme_protocol_t protocol;
1175   size_t chunksize;
1176   int opt_mime;
1177   char *keystring = NULL;
1178   gpgme_data_t input = NULL;
1179   gpgme_data_t output = NULL;
1180   int abool;
1181   gpgme_encrypt_flags_t encrypt_flags = 0;
1182
1183   if ((err = get_protocol (request, &protocol)))
1184     goto leave;
1185   ctx = get_context (protocol);
1186   if ((err = get_chunksize (request, &chunksize)))
1187     goto leave;
1188
1189   if ((err = get_boolean_flag (request, "mime", 0, &opt_mime)))
1190     goto leave;
1191
1192   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1193     goto leave;
1194   gpgme_set_armor (ctx, abool);
1195   if ((err = get_boolean_flag (request, "always-trust", 0, &abool)))
1196     goto leave;
1197   if (abool)
1198     encrypt_flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
1199   if ((err = get_boolean_flag (request, "no-encrypt-to", 0,&abool)))
1200     goto leave;
1201   if (abool)
1202     encrypt_flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1203   if ((err = get_boolean_flag (request, "no-compress", 0, &abool)))
1204     goto leave;
1205   if (abool)
1206     encrypt_flags |= GPGME_ENCRYPT_NO_COMPRESS;
1207   if ((err = get_boolean_flag (request, "throw-keyids", 0, &abool)))
1208     goto leave;
1209   if (abool)
1210     encrypt_flags |= GPGME_ENCRYPT_THROW_KEYIDS;
1211   if ((err = get_boolean_flag (request, "wrap", 0, &abool)))
1212     goto leave;
1213   if (abool)
1214     encrypt_flags |= GPGME_ENCRYPT_WRAP;
1215   if ((err = get_boolean_flag (request, "want-address", 0, &abool)))
1216     goto leave;
1217   if (abool)
1218     encrypt_flags |= GPGME_ENCRYPT_WANT_ADDRESS;
1219
1220
1221   /* Get the keys.  */
1222   err = get_keys (request, &keystring);
1223   if (err)
1224     {
1225       /* Provide a custom error response.  */
1226       gpg_error_object (result, err, "Error getting keys: %s",
1227                         gpg_strerror (err));
1228       goto leave;
1229     }
1230
1231   if ((err = get_string_data (request, result, "data", &input)))
1232       goto leave;
1233
1234   if (opt_mime)
1235     gpgme_data_set_encoding (input, GPGME_DATA_ENCODING_MIME);
1236
1237
1238   /* Create an output data object.  */
1239   err = gpgme_data_new (&output);
1240   if (err)
1241     {
1242       gpg_error_object (result, err, "Error creating output data object: %s",
1243                         gpg_strerror (err));
1244       goto leave;
1245     }
1246
1247   /* Encrypt.  */
1248   err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
1249                               input, output);
1250   /* encrypt_result = gpgme_op_encrypt_result (ctx); */
1251   if (err)
1252     {
1253       gpg_error_object (result, err, "Encryption failed: %s",
1254                         gpg_strerror (err));
1255       goto leave;
1256     }
1257   gpgme_data_release (input);
1258   input = NULL;
1259
1260   /* We need to base64 if armoring has not been requested.  */
1261   err = make_data_object (result, output, chunksize,
1262                           "ciphertext", !gpgme_get_armor (ctx));
1263   output = NULL;
1264
1265  leave:
1266   xfree (keystring);
1267   release_context (ctx);
1268   gpgme_data_release (input);
1269   gpgme_data_release (output);
1270   return err;
1271 }
1272
1273
1274 \f
1275 static const char hlp_decrypt[] =
1276   "op:     \"decrypt\"\n"
1277   "data:   The encrypted data.\n"
1278   "\n"
1279   "Optional parameters:\n"
1280   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1281   "chunksize:     Max number of bytes in the resulting \"data\".\n"
1282   "\n"
1283   "Optional boolean flags (default is false):\n"
1284   "base64:        Input data is base64 encoded.\n"
1285   "\n"
1286   "Response on success:\n"
1287   "type:   \"plaintext\"\n"
1288   "data:   The decrypted data.  This may be base64 encoded.\n"
1289   "base64: Boolean indicating whether data is base64 encoded.\n"
1290   "mime:   A Boolean indicating whether the data is a MIME object.\n"
1291   "info:   An optional object with extra information.\n"
1292   "info:   An object with optional signature information.\n"
1293   "  Array values:\n"
1294   "   signatures\n"
1295   "    String values:\n"
1296   "     status: The status of the signature.\n"
1297   "     fingerprint: The fingerprint of the signing key.\n"
1298   "     validity: The validity as string.\n"
1299   "    Number values:\n"
1300   "     code: The status as a number.\n"
1301   "    Array values:\n"
1302   "     summary: A string array of the sig summary.\n"
1303   "more:   Optional boolean indicating that \"getmore\" is required.";
1304 static gpg_error_t
1305 op_decrypt (cjson_t request, cjson_t result)
1306 {
1307   gpg_error_t err;
1308   gpgme_ctx_t ctx = NULL;
1309   gpgme_protocol_t protocol;
1310   size_t chunksize;
1311   gpgme_data_t input = NULL;
1312   gpgme_data_t output = NULL;
1313   gpgme_decrypt_result_t decrypt_result;
1314   gpgme_verify_result_t verify_result;
1315
1316   if ((err = get_protocol (request, &protocol)))
1317     goto leave;
1318   ctx = get_context (protocol);
1319   if ((err = get_chunksize (request, &chunksize)))
1320     goto leave;
1321
1322   if ((err = get_string_data (request, result, "data", &input)))
1323       goto leave;
1324
1325   /* Create an output data object.  */
1326   err = gpgme_data_new (&output);
1327   if (err)
1328     {
1329       gpg_error_object (result, err,
1330                         "Error creating output data object: %s",
1331                         gpg_strerror (err));
1332       goto leave;
1333     }
1334
1335   /* Decrypt.  */
1336   err = gpgme_op_decrypt_ext (ctx, GPGME_DECRYPT_VERIFY,
1337                               input, output);
1338   decrypt_result = gpgme_op_decrypt_result (ctx);
1339   if (err)
1340     {
1341       gpg_error_object (result, err, "Decryption failed: %s",
1342                         gpg_strerror (err));
1343       goto leave;
1344     }
1345   gpgme_data_release (input);
1346   input = NULL;
1347
1348   if (decrypt_result->is_mime)
1349     xjson_AddBoolToObject (result, "mime", 1);
1350
1351   verify_result = gpgme_op_verify_result (ctx);
1352   if (verify_result && verify_result->signatures)
1353     {
1354       xjson_AddItemToObject (result, "info",
1355                              verify_result_to_json (verify_result));
1356     }
1357
1358   err = make_data_object (result, output, chunksize, "plaintext", -1);
1359   output = NULL;
1360
1361   if (err)
1362     {
1363       gpg_error_object (result, err, "Plaintext output failed: %s",
1364                         gpg_strerror (err));
1365       goto leave;
1366     }
1367
1368  leave:
1369   release_context (ctx);
1370   gpgme_data_release (input);
1371   gpgme_data_release (output);
1372   return err;
1373 }
1374
1375
1376 \f
1377 static const char hlp_sign[] =
1378   "op:     \"sign\"\n"
1379   "keys:   Array of strings with the fingerprints of the signing key.\n"
1380   "        For a single key a String may be used instead of an array.\n"
1381   "data:   Input data. \n"
1382   "\n"
1383   "Optional parameters:\n"
1384   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1385   "chunksize:     Max number of bytes in the resulting \"data\".\n"
1386   "sender:        The mail address of the sender.\n"
1387   "mode:          A string with the signing mode can be:\n"
1388   "               detached (default)\n"
1389   "               opaque\n"
1390   "               clearsign\n"
1391   "\n"
1392   "Optional boolean flags (default is false):\n"
1393   "base64:        Input data is base64 encoded.\n"
1394   "armor:         Request output in armored format.\n"
1395   "\n"
1396   "Response on success:\n"
1397   "type:   \"signature\"\n"
1398   "data:   Unless armor mode is used a Base64 encoded binary\n"
1399   "        signature.  In armor mode a string with an armored\n"
1400   "        OpenPGP or a PEM message.\n"
1401   "base64: Boolean indicating whether data is base64 encoded.\n"
1402   "more:   Optional boolean indicating that \"getmore\" is required.";
1403 static gpg_error_t
1404 op_sign (cjson_t request, cjson_t result)
1405 {
1406   gpg_error_t err;
1407   gpgme_ctx_t ctx = NULL;
1408   gpgme_protocol_t protocol;
1409   size_t chunksize;
1410   char *keystring = NULL;
1411   gpgme_data_t input = NULL;
1412   gpgme_data_t output = NULL;
1413   int abool;
1414   cjson_t j_tmp;
1415   gpgme_sig_mode_t mode = GPGME_SIG_MODE_DETACH;
1416   gpgme_ctx_t keylist_ctx = NULL;
1417   gpgme_key_t key = NULL;
1418
1419   if ((err = get_protocol (request, &protocol)))
1420     goto leave;
1421   ctx = get_context (protocol);
1422   if ((err = get_chunksize (request, &chunksize)))
1423     goto leave;
1424
1425   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1426     goto leave;
1427   gpgme_set_armor (ctx, abool);
1428
1429   j_tmp = cJSON_GetObjectItem (request, "mode");
1430   if (j_tmp && cjson_is_string (j_tmp))
1431     {
1432       if (!strcmp (j_tmp->valuestring, "opaque"))
1433         {
1434           mode = GPGME_SIG_MODE_NORMAL;
1435         }
1436       else if (!strcmp (j_tmp->valuestring, "clearsign"))
1437         {
1438           mode = GPGME_SIG_MODE_CLEAR;
1439         }
1440     }
1441
1442   j_tmp = cJSON_GetObjectItem (request, "sender");
1443   if (j_tmp && cjson_is_string (j_tmp))
1444     {
1445       gpgme_set_sender (ctx, j_tmp->valuestring);
1446     }
1447
1448   /* Get the keys.  */
1449   err = get_keys (request, &keystring);
1450   if (err)
1451     {
1452       /* Provide a custom error response.  */
1453       gpg_error_object (result, err, "Error getting keys: %s",
1454                         gpg_strerror (err));
1455       goto leave;
1456     }
1457
1458   /* Do a keylisting and add the keys */
1459   if ((err = gpgme_new (&keylist_ctx)))
1460     goto leave;
1461   gpgme_set_protocol (keylist_ctx, protocol);
1462   gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
1463
1464   err = gpgme_op_keylist_start (ctx, keystring, 1);
1465   if (err)
1466     {
1467       gpg_error_object (result, err, "Error listing keys: %s",
1468                         gpg_strerror (err));
1469       goto leave;
1470     }
1471   while (!(err = gpgme_op_keylist_next (ctx, &key)))
1472     {
1473       if ((err = gpgme_signers_add (ctx, key)))
1474         {
1475           gpg_error_object (result, err, "Error adding signer: %s",
1476                             gpg_strerror (err));
1477           goto leave;
1478         }
1479       gpgme_key_unref (key);
1480     }
1481
1482   if ((err = get_string_data (request, result, "data", &input)))
1483       goto leave;
1484
1485   /* Create an output data object.  */
1486   err = gpgme_data_new (&output);
1487   if (err)
1488     {
1489       gpg_error_object (result, err, "Error creating output data object: %s",
1490                         gpg_strerror (err));
1491       goto leave;
1492     }
1493
1494   /* Sign. */
1495   err = gpgme_op_sign (ctx, input, output, mode);
1496   if (err)
1497     {
1498       gpg_error_object (result, err, "Signing failed: %s",
1499                         gpg_strerror (err));
1500       goto leave;
1501     }
1502
1503   gpgme_data_release (input);
1504   input = NULL;
1505
1506   /* We need to base64 if armoring has not been requested.  */
1507   err = make_data_object (result, output, chunksize,
1508                           "signature", !gpgme_get_armor (ctx));
1509   output = NULL;
1510
1511  leave:
1512   xfree (keystring);
1513   release_context (ctx);
1514   release_context (keylist_ctx);
1515   gpgme_data_release (input);
1516   gpgme_data_release (output);
1517   return err;
1518 }
1519 \f
1520 static const char hlp_verify[] =
1521   "op:     \"verify\"\n"
1522   "data:   The data to verify.\n"
1523   "\n"
1524   "Optional parameters:\n"
1525   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1526   "chunksize:     Max number of bytes in the resulting \"data\".\n"
1527   "signature:     A detached signature. If missing opaque is assumed.\n"
1528   "\n"
1529   "Optional boolean flags (default is false):\n"
1530   "base64:        Input data is base64 encoded.\n"
1531   "\n"
1532   "Response on success:\n"
1533   "type:   \"plaintext\"\n"
1534   "data:   The verified data.  This may be base64 encoded.\n"
1535   "base64: Boolean indicating whether data is base64 encoded.\n"
1536   "info:   An object with signature information.\n"
1537   "  Array values:\n"
1538   "   signatures\n"
1539   "    String values:\n"
1540   "     status: The status of the signature.\n"
1541   "     fingerprint: The fingerprint of the signing key.\n"
1542   "     validity: The validity as string.\n"
1543   "    Number values:\n"
1544   "     code: The status as a number.\n"
1545   "    Array values:\n"
1546   "     summary: A string array of the sig summary.\n"
1547   "more:   Optional boolean indicating that \"getmore\" is required.";
1548 static gpg_error_t
1549 op_verify (cjson_t request, cjson_t result)
1550 {
1551   gpg_error_t err;
1552   gpgme_ctx_t ctx = NULL;
1553   gpgme_protocol_t protocol;
1554   size_t chunksize;
1555   gpgme_data_t input = NULL;
1556   gpgme_data_t signature = NULL;
1557   gpgme_data_t output = NULL;
1558   gpgme_verify_result_t verify_result;
1559
1560   if ((err = get_protocol (request, &protocol)))
1561     goto leave;
1562   ctx = get_context (protocol);
1563   if ((err = get_chunksize (request, &chunksize)))
1564     goto leave;
1565
1566   if ((err = get_string_data (request, result, "data", &input)))
1567     goto leave;
1568
1569   err = get_string_data (request, result, "signature", &signature);
1570   /* Signature data is optional otherwise we expect opaque or clearsigned. */
1571   if (err && err != gpg_error (GPG_ERR_NO_DATA))
1572     goto leave;
1573
1574   /* Create an output data object.  */
1575   err = gpgme_data_new (&output);
1576   if (err)
1577     {
1578       gpg_error_object (result, err, "Error creating output data object: %s",
1579                         gpg_strerror (err));
1580       goto leave;
1581     }
1582
1583   /* Verify.  */
1584   if (signature)
1585     {
1586       err = gpgme_op_verify (ctx, signature, input, output);
1587     }
1588   else
1589     {
1590       err = gpgme_op_verify (ctx, input, 0, output);
1591     }
1592   if (err)
1593     {
1594       gpg_error_object (result, err, "Verify failed: %s", gpg_strerror (err));
1595       goto leave;
1596     }
1597   gpgme_data_release (input);
1598   input = NULL;
1599   gpgme_data_release (signature);
1600   signature = NULL;
1601
1602   verify_result = gpgme_op_verify_result (ctx);
1603   if (verify_result && verify_result->signatures)
1604     {
1605       xjson_AddItemToObject (result, "info",
1606                              verify_result_to_json (verify_result));
1607     }
1608
1609   err = make_data_object (result, output, chunksize, "plaintext", -1);
1610   output = NULL;
1611
1612   if (err)
1613     {
1614       gpg_error_object (result, err, "Plaintext output failed: %s",
1615                         gpg_strerror (err));
1616       goto leave;
1617     }
1618
1619  leave:
1620   release_context (ctx);
1621   gpgme_data_release (input);
1622   gpgme_data_release (output);
1623   gpgme_data_release (signature);
1624   return err;
1625 }
1626 \f
1627 static const char hlp_version[] =
1628   "op:     \"version\"\n"
1629   "\n"
1630   "Response on success:\n"
1631   "gpgme:  The GPGME Version.\n"
1632   "info:   dump of engine info. containing:\n"
1633   "        protocol: The protocol.\n"
1634   "        fname:    The file name.\n"
1635   "        version:  The version.\n"
1636   "        req_ver:  The required version.\n"
1637   "        homedir:  The homedir of the engine or \"default\".\n";
1638 static gpg_error_t
1639 op_version (cjson_t request, cjson_t result)
1640 {
1641   gpg_error_t err = 0;
1642   gpgme_engine_info_t ei = NULL;
1643   cjson_t infos = xjson_CreateArray ();
1644
1645   if (!cJSON_AddStringToObject (result, "gpgme", gpgme_check_version (NULL)))
1646     {
1647       cJSON_Delete (infos);
1648       return gpg_error_from_syserror ();
1649     }
1650
1651   if ((err = gpgme_get_engine_info (&ei)))
1652     {
1653       cJSON_Delete (infos);
1654       return err;
1655     }
1656
1657   for (; ei; ei = ei->next)
1658     cJSON_AddItemToArray (infos, engine_info_to_json (ei));
1659
1660   if (!cJSON_AddItemToObject (result, "info", infos))
1661     {
1662       err = gpg_error_from_syserror ();
1663       cJSON_Delete (infos);
1664       return err;
1665     }
1666
1667   return 0;
1668 }
1669 \f
1670 static const char hlp_keylist[] =
1671   "op:     \"keylist\"\n"
1672   "keys:   Array of strings or fingerprints to lookup\n"
1673   "        For a single key a String may be used instead of an array.\n"
1674   "\n"
1675   "Optional parameters:\n"
1676   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1677   "chunksize:     Max number of bytes in the resulting \"data\".\n"
1678   "\n"
1679   "Optional boolean flags (default is false):\n"
1680   "secret:        List secret keys.\n"
1681   "extern:        Add KEYLIST_MODE_EXTERN.\n"
1682   "local:         Add KEYLIST_MODE_LOCAL. (default mode).\n"
1683   "sigs:          Add KEYLIST_MODE_SIGS.\n"
1684   "notations:     Add KEYLIST_MODE_SIG_NOTATIONS.\n"
1685   "tofu:          Add KEYLIST_MODE_WITH_TOFU.\n"
1686   "ephemeral:     Add KEYLIST_MODE_EPHEMERAL.\n"
1687   "validate:      Add KEYLIST_MODE_VALIDATE.\n"
1688   "\n"
1689   "Response on success:\n"
1690   "keys:   Array of keys.\n"
1691   "  Boolean values:\n"
1692   "   revoked\n"
1693   "   expired\n"
1694   "   disabled\n"
1695   "   invalid\n"
1696   "   can_encrypt\n"
1697   "   can_sign\n"
1698   "   can_certify\n"
1699   "   can_authenticate\n"
1700   "   secret\n"
1701   "   is_qualified\n"
1702   "  String values:\n"
1703   "   protocol\n"
1704   "   issuer_serial (CMS Only)\n"
1705   "   issuer_name (CMS Only)\n"
1706   "   chain_id (CMS Only)\n"
1707   "   owner_trust (OpenPGP only)\n"
1708   "   fingerprint\n"
1709   "  Number values:\n"
1710   "   last_update\n"
1711   "   origin\n"
1712   "  Array values:\n"
1713   "   subkeys\n"
1714   "    Boolean values:\n"
1715   "     revoked\n"
1716   "     expired\n"
1717   "     disabled\n"
1718   "     invalid\n"
1719   "     can_encrypt\n"
1720   "     can_sign\n"
1721   "     can_certify\n"
1722   "     can_authenticate\n"
1723   "     secret\n"
1724   "     is_qualified\n"
1725   "     is_cardkey\n"
1726   "     is_de_vs\n"
1727   "    String values:\n"
1728   "     pubkey_algo_name\n"
1729   "     pubkey_algo_string\n"
1730   "     keyid\n"
1731   "     card_number\n"
1732   "     curve\n"
1733   "     keygrip\n"
1734   "    Number values:\n"
1735   "     pubkey_algo\n"
1736   "     length\n"
1737   "     timestamp\n"
1738   "     expires\n"
1739   "   userids\n"
1740   "    Boolean values:\n"
1741   "     revoked\n"
1742   "     invalid\n"
1743   "    String values:\n"
1744   "     validity\n"
1745   "     uid\n"
1746   "     name\n"
1747   "     email\n"
1748   "     comment\n"
1749   "     address\n"
1750   "    Number values:\n"
1751   "     origin\n"
1752   "     last_update\n"
1753   "    Array values:\n"
1754   "     signatures\n"
1755   "      Boolean values:\n"
1756   "       revoked\n"
1757   "       expired\n"
1758   "       invalid\n"
1759   "       exportable\n"
1760   "      String values:\n"
1761   "       pubkey_algo_name\n"
1762   "       keyid\n"
1763   "       status\n"
1764   "       uid\n"
1765   "       name\n"
1766   "       email\n"
1767   "       comment\n"
1768   "      Number values:\n"
1769   "       pubkey_algo\n"
1770   "       timestamp\n"
1771   "       expires\n"
1772   "       status_code\n"
1773   "       sig_class\n"
1774   "      Array values:\n"
1775   "       notations\n"
1776   "        Boolean values:\n"
1777   "         human_readable\n"
1778   "         critical\n"
1779   "        String values:\n"
1780   "         name\n"
1781   "         value\n"
1782   "        Number values:\n"
1783   "         flags\n"
1784   "     tofu\n"
1785   "      String values:\n"
1786   "       description\n"
1787   "      Number values:\n"
1788   "       validity\n"
1789   "       policy\n"
1790   "       signcount\n"
1791   "       encrcount\n"
1792   "       signfirst\n"
1793   "       signlast\n"
1794   "       encrfirst\n"
1795   "       encrlast\n"
1796   "more:   Optional boolean indicating that \"getmore\" is required.\n"
1797   "        (not implemented)";
1798 static gpg_error_t
1799 op_keylist (cjson_t request, cjson_t result)
1800 {
1801   gpg_error_t err;
1802   gpgme_ctx_t ctx = NULL;
1803   gpgme_protocol_t protocol;
1804   size_t chunksize;
1805   char *keystring = NULL;
1806   int abool;
1807   gpgme_keylist_mode_t mode = 0;
1808   gpgme_key_t key = NULL;
1809   cjson_t keyarray = xjson_CreateArray ();
1810
1811   if ((err = get_protocol (request, &protocol)))
1812     goto leave;
1813   ctx = get_context (protocol);
1814   if ((err = get_chunksize (request, &chunksize)))
1815     goto leave;
1816
1817   /* Handle the various keylist mode bools. */
1818   if ((err = get_boolean_flag (request, "secret", 0, &abool)))
1819     goto leave;
1820   if (abool)
1821     mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
1822
1823   if ((err = get_boolean_flag (request, "extern", 0, &abool)))
1824     goto leave;
1825   if (abool)
1826     mode |= GPGME_KEYLIST_MODE_EXTERN;
1827
1828   if ((err = get_boolean_flag (request, "local", 0, &abool)))
1829     goto leave;
1830   if (abool)
1831     mode |= GPGME_KEYLIST_MODE_LOCAL;
1832
1833   if ((err = get_boolean_flag (request, "sigs", 0, &abool)))
1834     goto leave;
1835   if (abool)
1836     mode |= GPGME_KEYLIST_MODE_SIGS;
1837
1838   if ((err = get_boolean_flag (request, "notations", 0, &abool)))
1839     goto leave;
1840   if (abool)
1841     mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
1842
1843   if ((err = get_boolean_flag (request, "tofu", 0, &abool)))
1844     goto leave;
1845   if (abool)
1846     mode |= GPGME_KEYLIST_MODE_WITH_TOFU;
1847
1848   if ((err = get_boolean_flag (request, "ephemeral", 0, &abool)))
1849     goto leave;
1850   if (abool)
1851     mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
1852
1853   if ((err = get_boolean_flag (request, "validate", 0, &abool)))
1854     goto leave;
1855   if (abool)
1856     mode |= GPGME_KEYLIST_MODE_VALIDATE;
1857
1858   if (!mode)
1859     {
1860       /* default to local */
1861       mode = GPGME_KEYLIST_MODE_LOCAL;
1862     }
1863
1864   /* Get the keys.  */
1865   err = get_keys (request, &keystring);
1866   if (err)
1867     {
1868       /* Provide a custom error response.  */
1869       gpg_error_object (result, err, "Error getting keys: %s",
1870                         gpg_strerror (err));
1871       goto leave;
1872     }
1873
1874   /* Do a keylisting and add the keys */
1875   if ((err = gpgme_new (&ctx)))
1876     goto leave;
1877   gpgme_set_protocol (ctx, protocol);
1878   gpgme_set_keylist_mode (ctx, mode);
1879
1880   err = gpgme_op_keylist_start (ctx, keystring,
1881                                 (mode & GPGME_KEYLIST_MODE_WITH_SECRET));
1882   if (err)
1883     {
1884       gpg_error_object (result, err, "Error listing keys: %s",
1885                         gpg_strerror (err));
1886       goto leave;
1887     }
1888
1889   while (!(err = gpgme_op_keylist_next (ctx, &key)))
1890     {
1891       cJSON_AddItemToArray (keyarray, key_to_json (key));
1892       gpgme_key_unref (key);
1893     }
1894   err = 0;
1895
1896   if (!cJSON_AddItemToObject (result, "keys", keyarray))
1897     {
1898       err = gpg_error_from_syserror ();
1899       goto leave;
1900     }
1901
1902  leave:
1903   xfree (keystring);
1904   if (err)
1905     {
1906       cJSON_Delete (keyarray);
1907     }
1908   return err;
1909 }
1910 \f
1911 static const char hlp_getmore[] =
1912   "op:     \"getmore\"\n"
1913   "\n"
1914   "Optional parameters:\n"
1915   "chunksize:  Max number of bytes in the \"data\" object.\n"
1916   "\n"
1917   "Response on success:\n"
1918   "type:       Type of the pending data\n"
1919   "data:       The next chunk of data\n"
1920   "base64:     Boolean indicating whether data is base64 encoded\n"
1921   "more:       Optional boolean requesting another \"getmore\".";
1922 static gpg_error_t
1923 op_getmore (cjson_t request, cjson_t result)
1924 {
1925   gpg_error_t err;
1926   int c;
1927   size_t n;
1928   size_t chunksize;
1929
1930   if ((err = get_chunksize (request, &chunksize)))
1931     goto leave;
1932
1933   /* Adjust the chunksize if we need to do base64 conversion.  */
1934   if (pending_data.base64)
1935     chunksize = (chunksize / 4) * 3;
1936
1937   /* Do we have anything pending?  */
1938   if (!pending_data.buffer)
1939     {
1940       err = gpg_error (GPG_ERR_NO_DATA);
1941       gpg_error_object (result, err, "Operation not possible: %s",
1942                         gpg_strerror (err));
1943       goto leave;
1944     }
1945
1946   xjson_AddStringToObject (result, "type", pending_data.type);
1947   xjson_AddBoolToObject (result, "base64", pending_data.base64);
1948
1949   if (pending_data.written >= pending_data.length)
1950     {
1951       /* EOF reached.  This should not happen but we return an empty
1952        * string once in case of client errors.  */
1953       gpgme_free (pending_data.buffer);
1954       pending_data.buffer = NULL;
1955       xjson_AddBoolToObject (result, "more", 0);
1956       err = cjson_AddStringToObject (result, "data", "");
1957     }
1958   else
1959     {
1960       n = pending_data.length - pending_data.written;
1961       if (n > chunksize)
1962         {
1963           n = chunksize;
1964           xjson_AddBoolToObject (result, "more", 1);
1965         }
1966       else
1967         xjson_AddBoolToObject (result, "more", 0);
1968
1969       c = pending_data.buffer[pending_data.written + n];
1970       pending_data.buffer[pending_data.written + n] = 0;
1971       if (pending_data.base64)
1972         err = add_base64_to_object (result, "data",
1973                                     (pending_data.buffer
1974                                      + pending_data.written), n);
1975       else
1976         err = cjson_AddStringToObject (result, "data",
1977                                        (pending_data.buffer
1978                                         + pending_data.written));
1979       pending_data.buffer[pending_data.written + n] = c;
1980       if (!err)
1981         {
1982           pending_data.written += n;
1983           if (pending_data.written >= pending_data.length)
1984             {
1985               gpgme_free (pending_data.buffer);
1986               pending_data.buffer = NULL;
1987             }
1988         }
1989     }
1990
1991  leave:
1992   return err;
1993 }
1994
1995
1996 \f
1997 static const char hlp_help[] =
1998   "The tool expects a JSON object with the request and responds with\n"
1999   "another JSON object.  Even on error a JSON object is returned.  The\n"
2000   "property \"op\" is mandatory and its string value selects the\n"
2001   "operation; if the property \"help\" with the value \"true\" exists, the\n"
2002   "operation is not performned but a string with the documentation\n"
2003   "returned.  To list all operations it is allowed to leave out \"op\" in\n"
2004   "help mode.  Supported values for \"op\" are:\n\n"
2005   "  encrypt     Encrypt data.\n"
2006   "  decrypt     Decrypt data.\n"
2007   "  sign        Sign data.\n"
2008   "  getmore     Retrieve remaining data.\n"
2009   "  help        Help overview.";
2010 static gpg_error_t
2011 op_help (cjson_t request, cjson_t result)
2012 {
2013   cjson_t j_tmp;
2014   char *buffer = NULL;
2015   const char *msg;
2016
2017   j_tmp = cJSON_GetObjectItem (request, "interactive_help");
2018   if (opt_interactive && j_tmp && cjson_is_string (j_tmp))
2019     msg = buffer = xstrconcat (hlp_help, "\n", j_tmp->valuestring, NULL);
2020   else
2021     msg = hlp_help;
2022
2023   xjson_AddStringToObject (result, "type", "help");
2024   xjson_AddStringToObject (result, "msg", msg);
2025
2026   xfree (buffer);
2027   return 0;
2028 }
2029
2030
2031 \f
2032 /*
2033  * Dispatcher
2034  */
2035
2036 /* Process a request and return the response.  The response is a newly
2037  * allocated string or NULL in case of an error.  */
2038 static char *
2039 process_request (const char *request)
2040 {
2041   static struct {
2042     const char *op;
2043     gpg_error_t (*handler)(cjson_t request, cjson_t result);
2044     const char * const helpstr;
2045   } optbl[] = {
2046     { "encrypt", op_encrypt, hlp_encrypt },
2047     { "decrypt", op_decrypt, hlp_decrypt },
2048     { "keylist", op_keylist, hlp_keylist },
2049     { "sign",    op_sign,    hlp_sign },
2050     { "verify",  op_verify,  hlp_verify },
2051     { "version", op_version, hlp_version },
2052     { "getmore", op_getmore, hlp_getmore },
2053     { "help",    op_help,    hlp_help },
2054     { NULL }
2055   };
2056   size_t erroff;
2057   cjson_t json;
2058   cjson_t j_tmp, j_op;
2059   cjson_t response;
2060   int helpmode;
2061   const char *op;
2062   char *res;
2063   int idx;
2064
2065   response = xjson_CreateObject ();
2066
2067   json = cJSON_Parse (request, &erroff);
2068   if (!json)
2069     {
2070       log_string (GPGRT_LOGLVL_INFO, request);
2071       log_info ("invalid JSON object at offset %zu\n", erroff);
2072       error_object (response, "invalid JSON object at offset %zu\n", erroff);
2073       goto leave;
2074     }
2075
2076   j_tmp = cJSON_GetObjectItem (json, "help");
2077   helpmode = (j_tmp && cjson_is_true (j_tmp));
2078
2079   j_op = cJSON_GetObjectItem (json, "op");
2080   if (!j_op || !cjson_is_string (j_op))
2081     {
2082       if (!helpmode)
2083         {
2084           error_object (response, "Property \"op\" missing");
2085           goto leave;
2086         }
2087       op = "help";  /* Help summary.  */
2088     }
2089   else
2090     op = j_op->valuestring;
2091
2092   for (idx=0; optbl[idx].op; idx++)
2093     if (!strcmp (op, optbl[idx].op))
2094       break;
2095   if (optbl[idx].op)
2096     {
2097       if (helpmode && strcmp (op, "help"))
2098         {
2099           xjson_AddStringToObject (response, "type", "help");
2100           xjson_AddStringToObject (response, "op", op);
2101           xjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
2102         }
2103       else
2104         {
2105           gpg_error_t err;
2106
2107           /* If this is not the "getmore" command and we have any
2108            * pending data release that data.  */
2109           if (pending_data.buffer && optbl[idx].handler != op_getmore)
2110             {
2111               gpgme_free (pending_data.buffer);
2112               pending_data.buffer = NULL;
2113             }
2114
2115           err = optbl[idx].handler (json, response);
2116           if (err)
2117             {
2118               if (!(j_tmp = cJSON_GetObjectItem (response, "type"))
2119                   || !cjson_is_string (j_tmp)
2120                   || strcmp (j_tmp->valuestring, "error"))
2121                 {
2122                   /* No error type response - provide a generic one.  */
2123                   gpg_error_object (response, err, "Operation failed: %s",
2124                                     gpg_strerror (err));
2125                 }
2126
2127               xjson_AddStringToObject (response, "op", op);
2128             }
2129         }
2130     }
2131   else  /* Operation not supported.  */
2132     {
2133       error_object (response, "Unknown operation '%s'", op);
2134       xjson_AddStringToObject (response, "op", op);
2135     }
2136
2137  leave:
2138   cJSON_Delete (json);
2139   if (opt_interactive)
2140     res = cJSON_Print (response);
2141   else
2142     res = cJSON_PrintUnformatted (response);
2143   if (!res)
2144     log_error ("Printing JSON data failed\n");
2145   cJSON_Delete (response);
2146   return res;
2147 }
2148
2149
2150 \f
2151 /*
2152  *  Driver code
2153  */
2154
2155 static char *
2156 get_file (const char *fname)
2157 {
2158   gpg_error_t err;
2159   estream_t fp;
2160   struct stat st;
2161   char *buf;
2162   size_t buflen;
2163
2164   fp = es_fopen (fname, "r");
2165   if (!fp)
2166     {
2167       err = gpg_error_from_syserror ();
2168       log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
2169       return NULL;
2170     }
2171
2172   if (fstat (es_fileno(fp), &st))
2173     {
2174       err = gpg_error_from_syserror ();
2175       log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
2176       es_fclose (fp);
2177       return NULL;
2178     }
2179
2180   buflen = st.st_size;
2181   buf = xmalloc (buflen+1);
2182   if (es_fread (buf, buflen, 1, fp) != 1)
2183     {
2184       err = gpg_error_from_syserror ();
2185       log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
2186       es_fclose (fp);
2187       xfree (buf);
2188       return NULL;
2189     }
2190   buf[buflen] = 0;
2191   es_fclose (fp);
2192
2193   return buf;
2194 }
2195
2196
2197 /* Return a malloced line or NULL on EOF.  Terminate on read
2198  * error.  */
2199 static char *
2200 get_line (void)
2201 {
2202   char *line = NULL;
2203   size_t linesize = 0;
2204   gpg_error_t err;
2205   size_t maxlength = 2048;
2206   int n;
2207   const char *s;
2208   char *p;
2209
2210  again:
2211   n = es_read_line (es_stdin, &line, &linesize, &maxlength);
2212   if (n < 0)
2213     {
2214       err = gpg_error_from_syserror ();
2215       log_error ("error reading line: %s\n", gpg_strerror (err));
2216       exit (1);
2217     }
2218   if (!n)
2219     {
2220       xfree (line);
2221       line = NULL;
2222       return NULL;  /* EOF */
2223     }
2224   if (!maxlength)
2225     {
2226       log_info ("line too long - skipped\n");
2227       goto again;
2228     }
2229   if (memchr (line, 0, n))
2230     log_info ("warning: line shortened due to embedded Nul character\n");
2231
2232   if (line[n-1] == '\n')
2233     line[n-1] = 0;
2234
2235   /* Trim leading spaces.  */
2236   for (s=line; spacep (s); s++)
2237     ;
2238   if (s != line)
2239     {
2240       for (p=line; *s;)
2241         *p++ = *s++;
2242       *p = 0;
2243       n = p - line;
2244     }
2245
2246   return line;
2247 }
2248
2249
2250 /* Process meta commands used with the standard REPL.  */
2251 static char *
2252 process_meta_commands (const char *request)
2253 {
2254   char *result = NULL;
2255
2256   while (spacep (request))
2257     request++;
2258
2259   if (!strncmp (request, "help", 4) && (spacep (request+4) || !request[4]))
2260     {
2261       if (request[4])
2262         {
2263           char *buf = xstrconcat ("{ \"help\":true, \"op\":\"", request+5,
2264                                   "\" }", NULL);
2265           result = process_request (buf);
2266           xfree (buf);
2267         }
2268       else
2269         result = process_request ("{ \"op\": \"help\","
2270                                   " \"interactive_help\": "
2271                                   "\"\\nMeta commands:\\n"
2272                                   "  ,read FNAME Process data from FILE\\n"
2273                                   "  ,help CMD   Print help for a command\\n"
2274                                   "  ,quit       Terminate process\""
2275                                   "}");
2276     }
2277   else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
2278     exit (0);
2279   else if (!strncmp (request, "read", 4) && (spacep (request+4) || !request[4]))
2280     {
2281       if (!request[4])
2282         log_info ("usage: ,read FILENAME\n");
2283       else
2284         {
2285           char *buffer = get_file (request + 5);
2286           if (buffer)
2287             {
2288               result = process_request (buffer);
2289               xfree (buffer);
2290             }
2291         }
2292     }
2293   else
2294     log_info ("invalid meta command\n");
2295
2296   return result;
2297 }
2298
2299
2300 /* If STRING has a help response, return the MSG property in a human
2301  * readable format.  */
2302 static char *
2303 get_help_msg (const char *string)
2304 {
2305   cjson_t json, j_type, j_msg;
2306   const char *msg;
2307   char *buffer = NULL;
2308   char *p;
2309
2310   json = cJSON_Parse (string, NULL);
2311   if (json)
2312     {
2313       j_type = cJSON_GetObjectItem (json, "type");
2314       if (j_type && cjson_is_string (j_type)
2315           && !strcmp (j_type->valuestring, "help"))
2316         {
2317           j_msg = cJSON_GetObjectItem (json, "msg");
2318           if (j_msg || cjson_is_string (j_msg))
2319             {
2320               msg = j_msg->valuestring;
2321               buffer = malloc (strlen (msg)+1);
2322               if (buffer)
2323                 {
2324                   for (p=buffer; *msg; msg++)
2325                     {
2326                       if (*msg == '\\' && msg[1] == '\n')
2327                         *p++ = '\n';
2328                       else
2329                         *p++ = *msg;
2330                     }
2331                   *p = 0;
2332                 }
2333             }
2334         }
2335       cJSON_Delete (json);
2336     }
2337   return buffer;
2338 }
2339
2340
2341 /* An interactive standard REPL.  */
2342 static void
2343 interactive_repl (void)
2344 {
2345   char *line = NULL;
2346   char *request = NULL;
2347   char *response = NULL;
2348   char *p;
2349   int first;
2350
2351   es_setvbuf (es_stdin, NULL, _IONBF, 0);
2352 #if GPGRT_VERSION_NUMBER >= 0x011d00 /* 1.29 */
2353   es_fprintf (es_stderr, "%s %s ready (enter \",help\" for help)\n",
2354               gpgrt_strusage (11), gpgrt_strusage (13));
2355 #endif
2356   do
2357     {
2358       es_fputs ("> ", es_stderr);
2359       es_fflush (es_stderr);
2360       es_fflush (es_stdout);
2361       xfree (line);
2362       line = get_line ();
2363       es_fflush (es_stderr);
2364       es_fflush (es_stdout);
2365
2366       first = !request;
2367       if (line && *line)
2368         {
2369           if (!request)
2370             request = xstrdup (line);
2371           else
2372             request = xstrconcat (request, "\n", line, NULL);
2373         }
2374
2375       if (!line)
2376         es_fputs ("\n", es_stderr);
2377
2378       if (!line || !*line || (first && *request == ','))
2379         {
2380           /* Process the input.  */
2381           xfree (response);
2382           response = NULL;
2383           if (request && *request == ',')
2384             {
2385               response = process_meta_commands (request+1);
2386             }
2387           else if (request)
2388             {
2389               response = process_request (request);
2390             }
2391           xfree (request);
2392           request = NULL;
2393
2394           if (response)
2395             {
2396               if (opt_interactive)
2397                 {
2398                   char *msg = get_help_msg (response);
2399                   if (msg)
2400                     {
2401                       xfree (response);
2402                       response = msg;
2403                     }
2404                 }
2405
2406               es_fputs ("===> ", es_stderr);
2407               es_fflush (es_stderr);
2408               for (p=response; *p; p++)
2409                 {
2410                   if (*p == '\n')
2411                     {
2412                       es_fflush (es_stdout);
2413                       es_fputs ("\n===> ", es_stderr);
2414                       es_fflush (es_stderr);
2415                     }
2416                   else
2417                     es_putc (*p, es_stdout);
2418                 }
2419               es_fflush (es_stdout);
2420               es_fputs ("\n", es_stderr);
2421             }
2422         }
2423     }
2424   while (line);
2425
2426   xfree (request);
2427   xfree (response);
2428   xfree (line);
2429 }
2430
2431
2432 /* Read and process a single request.  */
2433 static void
2434 read_and_process_single_request (void)
2435 {
2436   char *line = NULL;
2437   char *request = NULL;
2438   char *response = NULL;
2439   size_t n;
2440
2441   for (;;)
2442     {
2443       xfree (line);
2444       line = get_line ();
2445       if (line && *line)
2446         request = (request? xstrconcat (request, "\n", line, NULL)
2447                    /**/   : xstrdup (line));
2448       if (!line)
2449         {
2450           if (request)
2451             {
2452               xfree (response);
2453               response = process_request (request);
2454               if (response)
2455                 {
2456                   es_fputs (response, es_stdout);
2457                   if ((n = strlen (response)) && response[n-1] != '\n')
2458                     es_fputc ('\n', es_stdout);
2459                 }
2460               es_fflush (es_stdout);
2461             }
2462           break;
2463         }
2464     }
2465
2466   xfree (response);
2467   xfree (request);
2468   xfree (line);
2469 }
2470
2471
2472 /* The Native Messaging processing loop.  */
2473 static void
2474 native_messaging_repl (void)
2475 {
2476   gpg_error_t err;
2477   uint32_t nrequest, nresponse;
2478   char *request = NULL;
2479   char *response = NULL;
2480   size_t n;
2481
2482   /* Due to the length octets we need to switch the I/O stream into
2483    * binary mode.  */
2484   es_set_binary (es_stdin);
2485   es_set_binary (es_stdout);
2486   es_setbuf (es_stdin, NULL);  /* stdin needs to be unbuffered! */
2487
2488   for (;;)
2489     {
2490       /* Read length.  Note that the protocol uses native endianess.
2491        * Is it allowed to call such a thing a well thought out
2492        * protocol?  */
2493       if (es_read (es_stdin, &nrequest, sizeof nrequest, &n))
2494         {
2495           err = gpg_error_from_syserror ();
2496           log_error ("error reading request header: %s\n", gpg_strerror (err));
2497           break;
2498         }
2499       if (!n)
2500         break;  /* EOF */
2501       if (n != sizeof nrequest)
2502         {
2503           log_error ("error reading request header: short read\n");
2504           break;
2505         }
2506       if (nrequest > MAX_REQUEST_SIZE)
2507         {
2508           log_error ("error reading request: request too long (%zu MiB)\n",
2509                      (size_t)nrequest / (1024*1024));
2510           /* Fixme: Shall we read the request to the bit bucket and
2511            * return an error reponse or just return an error reponse
2512            * and terminate?  Needs some testing.  */
2513           break;
2514         }
2515
2516       /* Read request.  */
2517       request = xtrymalloc (nrequest);
2518       if (!request)
2519         {
2520           err = gpg_error_from_syserror ();
2521           log_error ("error reading request: Not enough memory for %zu MiB)\n",
2522                      (size_t)nrequest / (1024*1024));
2523           /* FIXME: See comment above.  */
2524           break;
2525         }
2526       if (es_read (es_stdin, request, nrequest, &n))
2527         {
2528           err = gpg_error_from_syserror ();
2529           log_error ("error reading request: %s\n", gpg_strerror (err));
2530           break;
2531         }
2532       if (n != nrequest)
2533         {
2534           /* That is a protocol violation.  */
2535           xfree (response);
2536           response = error_object_string ("Invalid request:"
2537                                           " short read (%zu of %zu bytes)\n",
2538                                           n, (size_t)nrequest);
2539         }
2540       else /* Process request  */
2541         {
2542           if (opt_debug)
2543             log_debug ("request='%s'\n", request);
2544           xfree (response);
2545           response = process_request (request);
2546           if (opt_debug)
2547             log_debug ("response='%s'\n", response);
2548         }
2549       nresponse = strlen (response);
2550
2551       /* Write response */
2552       if (es_write (es_stdout, &nresponse, sizeof nresponse, &n))
2553         {
2554           err = gpg_error_from_syserror ();
2555           log_error ("error writing request header: %s\n", gpg_strerror (err));
2556           break;
2557         }
2558       if (n != sizeof nrequest)
2559         {
2560           log_error ("error writing request header: short write\n");
2561           break;
2562         }
2563       if (es_write (es_stdout, response, nresponse, &n))
2564         {
2565           err = gpg_error_from_syserror ();
2566           log_error ("error writing request: %s\n", gpg_strerror (err));
2567           break;
2568         }
2569       if (n != nresponse)
2570         {
2571           log_error ("error writing request: short write\n");
2572           break;
2573         }
2574       if (es_fflush (es_stdout) || es_ferror (es_stdout))
2575         {
2576           err = gpg_error_from_syserror ();
2577           log_error ("error writing request: %s\n", gpg_strerror (err));
2578           break;
2579         }
2580     }
2581
2582   xfree (response);
2583   xfree (request);
2584 }
2585
2586
2587 \f
2588 static const char *
2589 my_strusage( int level )
2590 {
2591   const char *p;
2592
2593   switch (level)
2594     {
2595     case  9: p = "LGPL-2.1-or-later"; break;
2596     case 11: p = "gpgme-json"; break;
2597     case 13: p = PACKAGE_VERSION; break;
2598     case 14: p = "Copyright (C) 2018 g10 Code GmbH"; break;
2599     case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
2600     case 1:
2601     case 40:
2602       p = "Usage: gpgme-json [OPTIONS]";
2603       break;
2604     case 41:
2605       p = "Native messaging based GPGME operations.\n";
2606       break;
2607     case 42:
2608       p = "1"; /* Flag print 40 as part of 41. */
2609       break;
2610     default: p = NULL; break;
2611     }
2612   return p;
2613 }
2614
2615 int
2616 main (int argc, char *argv[])
2617 {
2618 #if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
2619
2620   fprintf (stderr, "WARNING: Old libgpg-error - using limited mode\n");
2621   native_messaging_repl ();
2622
2623 #else /* This is a modern libgp-error.  */
2624
2625   enum { CMD_DEFAULT     = 0,
2626          CMD_INTERACTIVE = 'i',
2627          CMD_SINGLE      = 's',
2628          CMD_LIBVERSION  = 501,
2629   } cmd = CMD_DEFAULT;
2630   enum {
2631     OPT_DEBUG = 600
2632   };
2633
2634   static gpgrt_opt_t opts[] = {
2635     ARGPARSE_c  (CMD_INTERACTIVE, "interactive", "Interactive REPL"),
2636     ARGPARSE_c  (CMD_SINGLE,      "single",      "Single request mode"),
2637     ARGPARSE_c  (CMD_LIBVERSION,  "lib-version", "Show library version"),
2638     ARGPARSE_s_n(OPT_DEBUG,       "debug",       "Flyswatter"),
2639
2640     ARGPARSE_end()
2641   };
2642   gpgrt_argparse_t pargs = { &argc, &argv};
2643
2644   gpgrt_set_strusage (my_strusage);
2645
2646 #ifdef HAVE_SETLOCALE
2647   setlocale (LC_ALL, "");
2648 #endif
2649   gpgme_check_version (NULL);
2650 #ifdef LC_CTYPE
2651   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
2652 #endif
2653 #ifdef LC_MESSAGES
2654   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
2655 #endif
2656
2657   while (gpgrt_argparse (NULL, &pargs, opts))
2658     {
2659       switch (pargs.r_opt)
2660         {
2661         case CMD_INTERACTIVE:
2662           opt_interactive = 1;
2663           /* Fall trough.  */
2664         case CMD_SINGLE:
2665         case CMD_LIBVERSION:
2666           cmd = pargs.r_opt;
2667           break;
2668
2669         case OPT_DEBUG: opt_debug = 1; break;
2670
2671         default:
2672           pargs.err = ARGPARSE_PRINT_WARNING;
2673           break;
2674         }
2675     }
2676   gpgrt_argparse (NULL, &pargs, NULL);
2677
2678   if (!opt_debug)
2679     {
2680       const char *s = getenv ("GPGME_JSON_DEBUG");
2681       if (s && atoi (s) > 0)
2682         opt_debug = 1;
2683     }
2684
2685   if (opt_debug)
2686     {
2687       const char *home = getenv ("HOME");
2688       char *file = xstrconcat ("socket://",
2689                                home? home:"/tmp",
2690                                "/.gnupg/S.gpgme-json.log", NULL);
2691       log_set_file (file);
2692       xfree (file);
2693     }
2694
2695   if (opt_debug)
2696     { int i;
2697       for (i=0; argv[i]; i++)
2698         log_debug ("argv[%d]='%s'\n", i, argv[i]);
2699     }
2700
2701   switch (cmd)
2702     {
2703     case CMD_DEFAULT:
2704       native_messaging_repl ();
2705       break;
2706
2707     case CMD_SINGLE:
2708       read_and_process_single_request ();
2709       break;
2710
2711     case CMD_INTERACTIVE:
2712       interactive_repl ();
2713       break;
2714
2715     case CMD_LIBVERSION:
2716       printf ("Version from header: %s (0x%06x)\n",
2717               GPGME_VERSION, GPGME_VERSION_NUMBER);
2718       printf ("Version from binary: %s\n", gpgme_check_version (NULL));
2719       printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01"));
2720       break;
2721     }
2722
2723   if (opt_debug)
2724     log_debug ("ready");
2725
2726 #endif /* This is a modern libgp-error.  */
2727   return 0;
2728 }
2729 #endif /* libgpg-error >= 1.28 */