Imported Upstream version 2.3.8
[platform/upstream/gpg2.git] / tools / gpg-wks-client.c
1 /* gpg-wks-client.c - A client for the Web Key Service protocols.
2  * Copyright (C) 2016, 2022 g10 Code GmbH
3  * Copyright (C) 2016 Bundesamt für Sicherheit in der Informationstechnik
4  *
5  * This file is part of GnuPG.
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
19  * SPDX-License-Identifier: LGPL-2.1-or-later
20  */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #define INCLUDED_BY_MAIN_MODULE 1
31 #include "../common/util.h"
32 #include "../common/status.h"
33 #include "../common/i18n.h"
34 #include "../common/sysutils.h"
35 #include "../common/init.h"
36 #include "../common/asshelp.h"
37 #include "../common/userids.h"
38 #include "../common/ccparray.h"
39 #include "../common/exectool.h"
40 #include "../common/mbox-util.h"
41 #include "../common/name-value.h"
42 #include "../common/comopt.h"
43 #include "call-dirmngr.h"
44 #include "mime-maker.h"
45 #include "send-mail.h"
46 #include "gpg-wks.h"
47
48
49 /* Constants to identify the commands and options. */
50 enum cmd_and_opt_values
51   {
52     aNull = 0,
53
54     oQuiet      = 'q',
55     oVerbose    = 'v',
56     oOutput     = 'o',
57     oDirectory  = 'C',
58
59     oDebug      = 500,
60
61     aSupported,
62     aCheck,
63     aCreate,
64     aReceive,
65     aRead,
66     aMirror,
67     aInstallKey,
68     aRemoveKey,
69     aPrintWKDHash,
70     aPrintWKDURL,
71
72     oGpgProgram,
73     oSend,
74     oFakeSubmissionAddr,
75     oStatusFD,
76     oWithColons,
77     oBlacklist,
78     oNoAutostart,
79
80     oDummy
81   };
82
83
84 /* The list of commands and options. */
85 static gpgrt_opt_t opts[] = {
86   ARGPARSE_group (300, ("@Commands:\n ")),
87
88   ARGPARSE_c (aSupported, "supported",
89               ("check whether provider supports WKS")),
90   ARGPARSE_c (aCheck, "check",
91               ("check whether a key is available")),
92   ARGPARSE_c (aCreate,   "create",
93               ("create a publication request")),
94   ARGPARSE_c (aReceive,   "receive",
95               ("receive a MIME confirmation request")),
96   ARGPARSE_c (aRead,      "read",
97               ("receive a plain text confirmation request")),
98   ARGPARSE_c (aMirror, "mirror",
99               "mirror an LDAP directory"),
100   ARGPARSE_c (aInstallKey, "install-key",
101               "install a key into a directory"),
102   ARGPARSE_c (aRemoveKey, "remove-key",
103               "remove a key from a directory"),
104   ARGPARSE_c (aPrintWKDHash, "print-wkd-hash",
105               "Print the WKD identifier for the given user ids"),
106   ARGPARSE_c (aPrintWKDURL, "print-wkd-url",
107               "Print the WKD URL for the given user id"),
108
109   ARGPARSE_group (301, ("@\nOptions:\n ")),
110
111   ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
112   ARGPARSE_s_n (oQuiet, "quiet",  ("be somewhat more quiet")),
113   ARGPARSE_s_s (oDebug, "debug", "@"),
114   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
115   ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
116   ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
117   ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")),
118   ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
119   ARGPARSE_s_n (oWithColons, "with-colons", "@"),
120   ARGPARSE_s_s (oBlacklist, "blacklist", "@"),
121   ARGPARSE_s_s (oDirectory, "directory", "@"),
122
123   ARGPARSE_s_s (oFakeSubmissionAddr, "fake-submission-addr", "@"),
124
125   ARGPARSE_end ()
126 };
127
128
129 /* The list of supported debug flags.  */
130 static struct debug_flags_s debug_flags [] =
131   {
132     { DBG_MIME_VALUE   , "mime"    },
133     { DBG_PARSER_VALUE , "parser"  },
134     { DBG_CRYPTO_VALUE , "crypto"  },
135     { DBG_MEMORY_VALUE , "memory"  },
136     { DBG_MEMSTAT_VALUE, "memstat" },
137     { DBG_IPC_VALUE    , "ipc"     },
138     { DBG_EXTPROG_VALUE, "extprog" },
139     { 0, NULL }
140   };
141
142
143
144 /* Value of the option --fake-submission-addr.  */
145 const char *fake_submission_addr;
146
147 /* An array with blacklisted addresses and its length.  Use
148  * is_in_blacklist to check.  */
149 static char **blacklist_array;
150 static size_t blacklist_array_len;
151
152
153 static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
154 static void add_blacklist (const char *fname);
155 static gpg_error_t proc_userid_from_stdin (gpg_error_t (*func)(const char *),
156                                            const char *text);
157 static gpg_error_t command_supported (char *userid);
158 static gpg_error_t command_check (char *userid);
159 static gpg_error_t command_send (const char *fingerprint, const char *userid);
160 static gpg_error_t encrypt_response (estream_t *r_output, estream_t input,
161                                      const char *addrspec,
162                                      const char *fingerprint);
163 static gpg_error_t read_confirmation_request (estream_t msg);
164 static gpg_error_t command_receive_cb (void *opaque,
165                                        const char *mediatype, estream_t fp,
166                                        unsigned int flags);
167 static gpg_error_t command_mirror (char *domain[]);
168
169
170 \f
171 /* Print usage information and provide strings for help. */
172 static const char *
173 my_strusage( int level )
174 {
175   const char *p;
176
177   switch (level)
178     {
179     case  9: p = "LGPL-2.1-or-later"; break;
180     case 11: p = "gpg-wks-client"; break;
181     case 12: p = "@GNUPG@"; break;
182     case 13: p = VERSION; break;
183     case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break;
184     case 17: p = PRINTABLE_OS_NAME; break;
185     case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
186
187     case 1:
188     case 40:
189       p = ("Usage: gpg-wks-client [command] [options] [args] (-h for help)");
190       break;
191     case 41:
192       p = ("Syntax: gpg-wks-client [command] [options] [args]\n"
193            "Client for the Web Key Service\n");
194       break;
195
196     default: p = NULL; break;
197     }
198   return p;
199 }
200
201
202 static void
203 wrong_args (const char *text)
204 {
205   es_fprintf (es_stderr, _("usage: %s [options] %s\n"),
206               gpgrt_strusage (11), text);
207   exit (2);
208 }
209
210
211 \f
212 /* Command line parsing.  */
213 static enum cmd_and_opt_values
214 parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts)
215 {
216   enum cmd_and_opt_values cmd = 0;
217   int no_more_options = 0;
218
219   while (!no_more_options && gpgrt_argparse (NULL, pargs, popts))
220     {
221       switch (pargs->r_opt)
222         {
223         case oQuiet:     opt.quiet = 1; break;
224         case oVerbose:   opt.verbose++; break;
225         case oDebug:
226           if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
227             {
228               pargs->r_opt = ARGPARSE_INVALID_ARG;
229               pargs->err = ARGPARSE_PRINT_ERROR;
230             }
231           break;
232
233         case oGpgProgram:
234           opt.gpg_program = pargs->r.ret_str;
235           break;
236         case oDirectory:
237           opt.directory = pargs->r.ret_str;
238           break;
239         case oSend:
240           opt.use_sendmail = 1;
241           break;
242         case oOutput:
243           opt.output = pargs->r.ret_str;
244           break;
245         case oFakeSubmissionAddr:
246           fake_submission_addr = pargs->r.ret_str;
247           break;
248         case oStatusFD:
249           wks_set_status_fd (translate_sys2libc_fd_int (pargs->r.ret_int, 1));
250           break;
251         case oWithColons:
252           opt.with_colons = 1;
253           break;
254         case oNoAutostart:
255           opt.no_autostart = 1;
256           break;
257         case oBlacklist:
258           add_blacklist (pargs->r.ret_str);
259           break;
260
261         case aSupported:
262         case aCreate:
263         case aReceive:
264         case aRead:
265         case aCheck:
266         case aMirror:
267         case aInstallKey:
268         case aRemoveKey:
269         case aPrintWKDHash:
270         case aPrintWKDURL:
271           cmd = pargs->r_opt;
272           break;
273
274         default: pargs->err = ARGPARSE_PRINT_ERROR; break;
275         }
276     }
277
278   return cmd;
279 }
280
281
282 \f
283 /* gpg-wks-client main. */
284 int
285 main (int argc, char **argv)
286 {
287   gpg_error_t err, delayed_err;
288   gpgrt_argparse_t pargs;
289   enum cmd_and_opt_values cmd;
290
291   gnupg_reopen_std ("gpg-wks-client");
292   gpgrt_set_strusage (my_strusage);
293   log_set_prefix ("gpg-wks-client", GPGRT_LOG_WITH_PREFIX);
294
295   /* Make sure that our subsystems are ready.  */
296   i18n_init();
297   init_common_subsystems (&argc, &argv);
298
299   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
300   setup_libassuan_logging (&opt.debug, NULL);
301
302   /* Parse the command line. */
303   pargs.argc  = &argc;
304   pargs.argv  = &argv;
305   pargs.flags = ARGPARSE_FLAG_KEEP;
306   cmd = parse_arguments (&pargs, opts);
307   gpgrt_argparse (NULL, &pargs, NULL);
308
309   /* Check if gpg is build with sendmail support */
310   if (opt.use_sendmail && !NAME_OF_SENDMAIL[0])
311     {
312       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
313       log_error ("sending mail is not supported in this build: %s\n",
314                 gpg_strerror (err));
315     }
316
317   if (log_get_errorcount (0))
318     exit (2);
319
320   /* Process common component options.  Note that we set the config
321    * dir only here so that --homedir will have an effect.  */
322   gpgrt_set_confdir (GPGRT_CONFDIR_SYS, gnupg_sysconfdir ());
323   gpgrt_set_confdir (GPGRT_CONFDIR_USER, gnupg_homedir ());
324   if (parse_comopt (GNUPG_MODULE_NAME_CONNECT_AGENT, opt.verbose > 1))
325     exit(2);
326   if (comopt.no_autostart)
327      opt.no_autostart = 1;
328
329   /* Print a warning if an argument looks like an option.  */
330   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
331     {
332       int i;
333
334       for (i=0; i < argc; i++)
335         if (argv[i][0] == '-' && argv[i][1] == '-')
336           log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
337     }
338
339   /* Set defaults for non given options.  */
340   if (!opt.gpg_program)
341     opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
342
343   if (!opt.directory)
344     opt.directory = "openpgpkey";
345
346   /* Tell call-dirmngr what options we want.  */
347   set_dirmngr_options (opt.verbose, (opt.debug & DBG_IPC_VALUE),
348                        !opt.no_autostart);
349
350
351   /* Check that the top directory exists.  */
352   if (cmd == aInstallKey || cmd == aRemoveKey || cmd == aMirror)
353     {
354       struct stat sb;
355
356       if (gnupg_stat (opt.directory, &sb))
357         {
358           err = gpg_error_from_syserror ();
359           log_error ("error accessing directory '%s': %s\n",
360                      opt.directory, gpg_strerror (err));
361           goto leave;
362         }
363       if (!S_ISDIR(sb.st_mode))
364         {
365           log_error ("error accessing directory '%s': %s\n",
366                      opt.directory, "not a directory");
367           err = gpg_error (GPG_ERR_ENOENT);
368           goto leave;
369         }
370     }
371
372   /* Run the selected command.  */
373   switch (cmd)
374     {
375     case aSupported:
376       if (opt.with_colons)
377         {
378           for (; argc; argc--, argv++)
379             command_supported (*argv);
380           err = 0;
381         }
382       else
383         {
384           if (argc != 1)
385             wrong_args ("--supported DOMAIN");
386           err = command_supported (argv[0]);
387           if (err && gpg_err_code (err) != GPG_ERR_FALSE)
388             log_error ("checking support failed: %s\n", gpg_strerror (err));
389         }
390       break;
391
392     case aCreate:
393       if (argc != 2)
394         wrong_args ("--create FINGERPRINT USER-ID");
395       err = command_send (argv[0], argv[1]);
396       if (err)
397         log_error ("creating request failed: %s\n", gpg_strerror (err));
398       break;
399
400     case aReceive:
401       if (argc)
402         wrong_args ("--receive < MIME-DATA");
403       err = wks_receive (es_stdin, command_receive_cb, NULL);
404       if (err)
405         log_error ("processing mail failed: %s\n", gpg_strerror (err));
406       break;
407
408     case aRead:
409       if (argc)
410         wrong_args ("--read < WKS-DATA");
411       err = read_confirmation_request (es_stdin);
412       if (err)
413         log_error ("processing mail failed: %s\n", gpg_strerror (err));
414       break;
415
416     case aCheck:
417       if (argc != 1)
418         wrong_args ("--check USER-ID");
419       err = command_check (argv[0]);
420       break;
421
422     case aMirror:
423       if (!argc)
424         err = command_mirror (NULL);
425       else
426         err = command_mirror (argv);
427       break;
428
429     case aInstallKey:
430       if (!argc)
431         err = wks_cmd_install_key (NULL, NULL);
432       else if (argc == 2)
433         err = wks_cmd_install_key (*argv, argv[1]);
434       else
435         wrong_args ("--install-key [FILE|FINGERPRINT USER-ID]");
436       break;
437
438     case aRemoveKey:
439       if (argc != 1)
440         wrong_args ("--remove-key USER-ID");
441       err = wks_cmd_remove_key (*argv);
442       break;
443
444     case aPrintWKDHash:
445     case aPrintWKDURL:
446       if (!argc)
447         {
448           if (cmd == aPrintWKDHash)
449             err = proc_userid_from_stdin (wks_cmd_print_wkd_hash,
450                                           "printing WKD hash");
451           else
452             err = proc_userid_from_stdin (wks_cmd_print_wkd_url,
453                                           "printing WKD URL");
454         }
455       else
456         {
457           for (err = delayed_err = 0; !err && argc; argc--, argv++)
458             {
459               if (cmd == aPrintWKDHash)
460                 err = wks_cmd_print_wkd_hash (*argv);
461               else
462                 err = wks_cmd_print_wkd_url (*argv);
463               if (gpg_err_code (err) == GPG_ERR_INV_USER_ID)
464                 {
465                   /* Diagnostic already printed.  */
466                   delayed_err = err;
467                   err = 0;
468                 }
469               else if (err)
470                 log_error ("printing hash failed: %s\n", gpg_strerror (err));
471             }
472           if (!err)
473             err = delayed_err;
474         }
475       break;
476
477     default:
478       gpgrt_usage (1);
479       err = 0;
480       break;
481     }
482
483  leave:
484   if (err)
485     wks_write_status (STATUS_FAILURE, "- %u", err);
486   else if (log_get_errorcount (0))
487     wks_write_status (STATUS_FAILURE, "- %u", GPG_ERR_GENERAL);
488   else
489     wks_write_status (STATUS_SUCCESS, NULL);
490   return (err || log_get_errorcount (0))? 1:0;
491 }
492
493
494
495 /* Read a file FNAME into a buffer and return that malloced buffer.
496  * Caller must free the buffer.  On error NULL is returned, on success
497  * the valid length of the buffer is stored at R_LENGTH.  The returned
498  * buffer is guaranteed to be Nul terminated.  */
499 static char *
500 read_file (const char *fname, size_t *r_length)
501 {
502   estream_t fp;
503   char *buf;
504   size_t buflen;
505
506   if (!strcmp (fname, "-"))
507     {
508       size_t nread, bufsize = 0;
509
510       fp = es_stdin;
511       es_set_binary (fp);
512       buf = NULL;
513       buflen = 0;
514 #define NCHUNK 32767
515       do
516         {
517           bufsize += NCHUNK;
518           if (!buf)
519             buf = xmalloc (bufsize+1);
520           else
521             buf = xrealloc (buf, bufsize+1);
522
523           nread = es_fread (buf+buflen, 1, NCHUNK, fp);
524           if (nread < NCHUNK && es_ferror (fp))
525             {
526               log_error ("error reading '[stdin]': %s\n", strerror (errno));
527               xfree (buf);
528               return NULL;
529             }
530           buflen += nread;
531         }
532       while (nread == NCHUNK);
533 #undef NCHUNK
534     }
535   else
536     {
537       struct stat st;
538
539       fp = es_fopen (fname, "rb");
540       if (!fp)
541         {
542           log_error ("can't open '%s': %s\n", fname, strerror (errno));
543           return NULL;
544         }
545
546       if (fstat (es_fileno (fp), &st))
547         {
548           log_error ("can't stat '%s': %s\n", fname, strerror (errno));
549           es_fclose (fp);
550           return NULL;
551         }
552
553       buflen = st.st_size;
554       buf = xmalloc (buflen+1);
555       if (es_fread (buf, buflen, 1, fp) != 1)
556         {
557           log_error ("error reading '%s': %s\n", fname, strerror (errno));
558           es_fclose (fp);
559           xfree (buf);
560           return NULL;
561         }
562       es_fclose (fp);
563     }
564   buf[buflen] = 0;
565   if (r_length)
566     *r_length = buflen;
567   return buf;
568 }
569
570
571 static int
572 cmp_blacklist (const void *arg_a, const void *arg_b)
573 {
574   const char *a = *(const char **)arg_a;
575   const char *b = *(const char **)arg_b;
576   return strcmp (a, b);
577 }
578
579
580 /* Add a blacklist to our global table.  This is called during option
581  * parsing and thus any use of log_error will eventually stop further
582  * processing.  */
583 static void
584 add_blacklist (const char *fname)
585 {
586   char *buffer;
587   char *p, *pend;
588   char **array;
589   size_t arraysize, arrayidx;
590
591   buffer = read_file (fname, NULL);
592   if (!buffer)
593     return;
594
595   /* Estimate the number of entries by counting the non-comment lines.  */
596   arraysize = 2; /* For the first and an extra NULL item.  */
597   for (p=buffer; *p; p++)
598     if (*p == '\n' && p[1] && p[1] != '#')
599       arraysize++;
600
601   array = xcalloc (arraysize, sizeof *array);
602   arrayidx = 0;
603
604   /* Loop over all lines.  */
605   for (p = buffer; p && *p; p = pend)
606     {
607       pend = strchr (p, '\n');
608       if (pend)
609         *pend++ = 0;
610       trim_spaces (p);
611       if (!*p || *p == '#' )
612         continue;
613       ascii_strlwr (p);
614       log_assert (arrayidx < arraysize);
615       array[arrayidx] = p;
616       arrayidx++;
617     }
618   log_assert (arrayidx < arraysize);
619
620   qsort (array, arrayidx, sizeof *array, cmp_blacklist);
621
622   blacklist_array = array;
623   blacklist_array_len = arrayidx;
624   gpgrt_annotate_leaked_object (buffer);
625   gpgrt_annotate_leaked_object (blacklist_array);
626 }
627
628
629 /* Return true if NAME is in a blacklist.  */
630 static int
631 is_in_blacklist (const char *name)
632 {
633   if (!name || !blacklist_array)
634     return 0;
635   return !!bsearch (&name, blacklist_array, blacklist_array_len,
636                     sizeof *blacklist_array, cmp_blacklist);
637 }
638
639
640 \f
641 /* Read user ids from stdin and call FUNC for each user id.  TEXT is
642  * used for error messages.  */
643 static gpg_error_t
644 proc_userid_from_stdin (gpg_error_t (*func)(const char *), const char *text)
645 {
646   gpg_error_t err = 0;
647   gpg_error_t delayed_err = 0;
648   char line[2048];
649   size_t n = 0;
650
651   /* If we are on a terminal disable buffering to get direct response.  */
652   if (gnupg_isatty (es_fileno (es_stdin))
653       && gnupg_isatty (es_fileno (es_stdout)))
654     {
655       es_setvbuf (es_stdin, NULL, _IONBF, 0);
656       es_setvbuf (es_stdout, NULL, _IOLBF, 0);
657     }
658
659   while (es_fgets (line, sizeof line - 1, es_stdin))
660     {
661       n = strlen (line);
662       if (!n || line[n-1] != '\n')
663         {
664           err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
665                            : GPG_ERR_INCOMPLETE_LINE);
666           log_error ("error reading stdin: %s\n", gpg_strerror (err));
667           break;
668         }
669       trim_spaces (line);
670       err = func (line);
671       if (gpg_err_code (err) == GPG_ERR_INV_USER_ID)
672         {
673           delayed_err = err;
674           err = 0;
675         }
676       else if (err)
677         log_error ("%s failed: %s\n", text, gpg_strerror (err));
678     }
679   if (es_ferror (es_stdin))
680     {
681       err = gpg_error_from_syserror ();
682       log_error ("error reading stdin: %s\n", gpg_strerror (err));
683       goto leave;
684     }
685
686  leave:
687   if (!err)
688     err = delayed_err;
689   return err;
690 }
691
692
693
694 \f
695 /* Add the user id UID to the key identified by FINGERPRINT.  */
696 static gpg_error_t
697 add_user_id (const char *fingerprint, const char *uid)
698 {
699   gpg_error_t err;
700   ccparray_t ccp;
701   const char **argv = NULL;
702
703   ccparray_init (&ccp, 0);
704
705   ccparray_put (&ccp, "--no-options");
706   if (opt.verbose < 2)
707     ccparray_put (&ccp, "--quiet");
708   else
709     ccparray_put (&ccp, "--verbose");
710   ccparray_put (&ccp, "--batch");
711   ccparray_put (&ccp, "--always-trust");
712   ccparray_put (&ccp, "--quick-add-uid");
713   ccparray_put (&ccp, fingerprint);
714   ccparray_put (&ccp, uid);
715
716   ccparray_put (&ccp, NULL);
717   argv = ccparray_get (&ccp, NULL);
718   if (!argv)
719     {
720       err = gpg_error_from_syserror ();
721       goto leave;
722     }
723   err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
724                                 NULL, NULL,
725                                 NULL, NULL);
726   if (err)
727     {
728       log_error ("adding user id failed: %s\n", gpg_strerror (err));
729       goto leave;
730     }
731
732  leave:
733   xfree (argv);
734   return err;
735 }
736
737
738 \f
739 struct decrypt_stream_parm_s
740 {
741   char *fpr;
742   char *mainfpr;
743   int  otrust;
744 };
745
746 static void
747 decrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
748 {
749   struct decrypt_stream_parm_s *decinfo = opaque;
750
751   if (DBG_CRYPTO)
752     log_debug ("gpg status: %s %s\n", keyword, args);
753   if (!strcmp (keyword, "DECRYPTION_KEY") && !decinfo->fpr)
754     {
755       const char *fields[3];
756
757       if (split_fields (args, fields, DIM (fields)) >= 3)
758         {
759           decinfo->fpr = xstrdup (fields[0]);
760           decinfo->mainfpr = xstrdup (fields[1]);
761           decinfo->otrust = *fields[2];
762         }
763     }
764 }
765
766 /* Decrypt the INPUT stream to a new stream which is stored at success
767  * at R_OUTPUT.  */
768 static gpg_error_t
769 decrypt_stream (estream_t *r_output, struct decrypt_stream_parm_s *decinfo,
770                 estream_t input)
771 {
772   gpg_error_t err;
773   ccparray_t ccp;
774   const char **argv;
775   estream_t output;
776
777   *r_output = NULL;
778   memset (decinfo, 0, sizeof *decinfo);
779
780   output = es_fopenmem (0, "w+b");
781   if (!output)
782     {
783       err = gpg_error_from_syserror ();
784       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
785       return err;
786     }
787
788   ccparray_init (&ccp, 0);
789
790   ccparray_put (&ccp, "--no-options");
791   /* We limit the output to 64 KiB to avoid DoS using compression
792    * tricks.  A regular client will anyway only send a minimal key;
793    * that is one w/o key signatures and attribute packets.  */
794   ccparray_put (&ccp, "--max-output=0x10000");
795   if (opt.verbose < 2)
796     ccparray_put (&ccp, "--quiet");
797   else
798     ccparray_put (&ccp, "--verbose");
799   ccparray_put (&ccp, "--batch");
800   ccparray_put (&ccp, "--status-fd=2");
801   ccparray_put (&ccp, "--decrypt");
802   ccparray_put (&ccp, "--");
803
804   ccparray_put (&ccp, NULL);
805   argv = ccparray_get (&ccp, NULL);
806   if (!argv)
807     {
808       err = gpg_error_from_syserror ();
809       goto leave;
810     }
811   err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
812                                 NULL, output,
813                                 decrypt_stream_status_cb, decinfo);
814   if (!err && (!decinfo->fpr || !decinfo->mainfpr || !decinfo->otrust))
815     err = gpg_error (GPG_ERR_INV_ENGINE);
816   if (err)
817     {
818       log_error ("decryption failed: %s\n", gpg_strerror (err));
819       goto leave;
820     }
821   else if (opt.verbose)
822     log_info ("decryption succeeded\n");
823
824   es_rewind (output);
825   *r_output = output;
826   output = NULL;
827
828  leave:
829   if (err)
830     {
831       xfree (decinfo->fpr);
832       xfree (decinfo->mainfpr);
833       memset (decinfo, 0, sizeof *decinfo);
834     }
835   es_fclose (output);
836   xfree (argv);
837   return err;
838 }
839
840
841 /* Return the submission address for the address or just the domain in
842  * ADDRSPEC.  The submission address is stored as a malloced string at
843  * R_SUBMISSION_ADDRESS.  At R_POLICY the policy flags of the domain
844  * are stored.  The caller needs to free them with wks_free_policy.
845  * The function returns an error code on failure to find a submission
846  * address or policy file.  Note: The function may store NULL at
847  * R_SUBMISSION_ADDRESS but return success to indicate that the web
848  * key directory is supported but not the web key service.  As per WKD
849  * specs a policy file is always required and will thus be return on
850  * success.  */
851 static gpg_error_t
852 get_policy_and_sa (const char *addrspec, int silent,
853                    policy_flags_t *r_policy, char **r_submission_address)
854 {
855   gpg_error_t err;
856   estream_t mbuf = NULL;
857   const char *domain;
858   const char *s;
859   policy_flags_t policy = NULL;
860   char *submission_to = NULL;
861
862   *r_submission_address = NULL;
863   *r_policy = NULL;
864
865   domain = strchr (addrspec, '@');
866   if (domain)
867     domain++;
868
869   if (opt.with_colons)
870     {
871       s = domain? domain : addrspec;
872       es_write_sanitized (es_stdout, s, strlen (s), ":", NULL);
873       es_putc (':', es_stdout);
874     }
875
876   /* We first try to get the submission address from the policy file
877    * (this is the new method).  If both are available we check that
878    * they match and print a warning if not.  In the latter case we
879    * keep on using the one from the submission-address file.    */
880   err = wkd_get_policy_flags (addrspec, &mbuf);
881   if (err && gpg_err_code (err) != GPG_ERR_NO_DATA
882       && gpg_err_code (err) != GPG_ERR_NO_NAME)
883     {
884       if (!opt.with_colons)
885         log_error ("error reading policy flags for '%s': %s\n",
886                    domain, gpg_strerror (err));
887       goto leave;
888     }
889   if (!mbuf)
890     {
891       if (!opt.with_colons)
892         log_error ("provider for '%s' does NOT support the Web Key Directory\n",
893                    addrspec);
894       err = gpg_error (GPG_ERR_FALSE);
895       goto leave;
896     }
897
898   policy = xtrycalloc (1, sizeof *policy);
899   if (!policy)
900     err = gpg_error_from_syserror ();
901   else
902     err = wks_parse_policy (policy, mbuf, 1);
903   es_fclose (mbuf);
904   mbuf = NULL;
905   if (err)
906     goto leave;
907
908   err = wkd_get_submission_address (addrspec, &submission_to);
909   if (err && !policy->submission_address)
910     {
911       if (!silent && !opt.with_colons)
912         log_error (_("error looking up submission address for domain '%s'"
913                      ": %s\n"), domain, gpg_strerror (err));
914       if (!silent && gpg_err_code (err) == GPG_ERR_NO_DATA && !opt.with_colons)
915         log_error (_("this domain probably doesn't support WKS.\n"));
916       goto leave;
917     }
918
919   if (submission_to && policy->submission_address
920       && ascii_strcasecmp (submission_to, policy->submission_address))
921     log_info ("Warning: different submission addresses (sa=%s, po=%s)\n",
922               submission_to, policy->submission_address);
923
924   if (!submission_to && policy->submission_address)
925     {
926       submission_to = xtrystrdup (policy->submission_address);
927       if (!submission_to)
928         {
929           err = gpg_error_from_syserror ();
930           goto leave;
931         }
932     }
933
934  leave:
935   *r_submission_address = submission_to;
936   submission_to = NULL;
937   *r_policy = policy;
938   policy = NULL;
939
940   if (opt.with_colons)
941     {
942       if (*r_policy && !*r_submission_address)
943         es_fprintf (es_stdout, "1:0::");
944       else if (*r_policy && *r_submission_address)
945         es_fprintf (es_stdout, "1:1::");
946       else if (err && !(gpg_err_code (err) == GPG_ERR_FALSE
947                         || gpg_err_code (err) == GPG_ERR_NO_DATA
948                         || gpg_err_code (err) == GPG_ERR_UNKNOWN_HOST))
949         es_fprintf (es_stdout, "0:0:%d:", err);
950       else
951         es_fprintf (es_stdout, "0:0::");
952       if (*r_policy)
953         {
954           es_fprintf (es_stdout, "%u:%u:%u:",
955                       (*r_policy)->protocol_version,
956                       (*r_policy)->auth_submit,
957                       (*r_policy)->mailbox_only);
958         }
959       es_putc ('\n', es_stdout);
960     }
961
962   xfree (submission_to);
963   wks_free_policy (policy);
964   xfree (policy);
965   es_fclose (mbuf);
966   return err;
967 }
968
969
970 \f
971 /* Check whether the  provider supports the WKS protocol.  */
972 static gpg_error_t
973 command_supported (char *userid)
974 {
975   gpg_error_t err;
976   char *addrspec = NULL;
977   char *submission_to = NULL;
978   policy_flags_t policy = NULL;
979
980   if (!strchr (userid, '@'))
981     {
982       char *tmp = xstrconcat ("foo@", userid, NULL);
983       addrspec = mailbox_from_userid (tmp, 0);
984       xfree (tmp);
985     }
986   else
987     addrspec = mailbox_from_userid (userid, 0);
988   if (!addrspec)
989     {
990       log_error (_("\"%s\" is not a proper mail address\n"), userid);
991       err = gpg_error (GPG_ERR_INV_USER_ID);
992       goto leave;
993     }
994
995   /* Get the submission address.  */
996   err = get_policy_and_sa (addrspec, 1, &policy, &submission_to);
997   if (err || !submission_to)
998     {
999       if (!submission_to
1000           || gpg_err_code (err) == GPG_ERR_FALSE
1001           || gpg_err_code (err) == GPG_ERR_NO_DATA
1002           || gpg_err_code (err) == GPG_ERR_UNKNOWN_HOST
1003           )
1004         {
1005           /* FALSE is returned if we already figured out that even the
1006            * Web Key Directory is not supported and thus printed an
1007            * error message.  */
1008           if (opt.verbose && gpg_err_code (err) != GPG_ERR_FALSE
1009               && !opt.with_colons)
1010             {
1011               if (gpg_err_code (err) == GPG_ERR_NO_DATA)
1012                 log_info ("provider for '%s' does NOT support WKS\n",
1013                           addrspec);
1014               else
1015                 log_info ("provider for '%s' does NOT support WKS (%s)\n",
1016                           addrspec, gpg_strerror (err));
1017             }
1018           err = gpg_error (GPG_ERR_FALSE);
1019           if (!opt.with_colons)
1020             log_inc_errorcount ();
1021         }
1022       goto leave;
1023     }
1024
1025   if (opt.verbose && !opt.with_colons)
1026     log_info ("provider for '%s' supports WKS\n", addrspec);
1027
1028  leave:
1029   wks_free_policy (policy);
1030   xfree (policy);
1031   xfree (submission_to);
1032   xfree (addrspec);
1033   return err;
1034 }
1035
1036
1037 \f
1038 /* Check whether the key for USERID is available in the WKD.  */
1039 static gpg_error_t
1040 command_check (char *userid)
1041 {
1042   gpg_error_t err;
1043   char *addrspec = NULL;
1044   estream_t key = NULL;
1045   char *fpr = NULL;
1046   uidinfo_list_t mboxes = NULL;
1047   uidinfo_list_t sl;
1048   int found = 0;
1049
1050   addrspec = mailbox_from_userid (userid, 0);
1051   if (!addrspec)
1052     {
1053       log_error (_("\"%s\" is not a proper mail address\n"), userid);
1054       err = gpg_error (GPG_ERR_INV_USER_ID);
1055       goto leave;
1056     }
1057
1058   /* Get the submission address.  */
1059   err = wkd_get_key (addrspec, &key);
1060   switch (gpg_err_code (err))
1061     {
1062     case 0:
1063       if (opt.verbose)
1064         log_info ("public key for '%s' found via WKD\n", addrspec);
1065       /* Fixme: Check that the key contains the user id.  */
1066       break;
1067
1068     case GPG_ERR_NO_DATA: /* No such key.  */
1069       if (opt.verbose)
1070         log_info ("public key for '%s' NOT found via WKD\n", addrspec);
1071       err = gpg_error (GPG_ERR_NO_PUBKEY);
1072       log_inc_errorcount ();
1073       break;
1074
1075     case GPG_ERR_UNKNOWN_HOST:
1076       if (opt.verbose)
1077         log_info ("error looking up '%s' via WKD: %s\n",
1078                   addrspec, gpg_strerror (err));
1079       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
1080       break;
1081
1082     default:
1083       log_error ("error looking up '%s' via WKD: %s\n",
1084                  addrspec, gpg_strerror (err));
1085       break;
1086     }
1087
1088   if (err)
1089     goto leave;
1090
1091   /* Look closer at the key.  */
1092   err = wks_list_key (key, &fpr, &mboxes);
1093   if (err)
1094     {
1095       log_error ("error parsing key: %s\n", gpg_strerror (err));
1096       err = gpg_error (GPG_ERR_NO_PUBKEY);
1097       goto leave;
1098     }
1099
1100   if (opt.verbose)
1101     log_info ("fingerprint: %s\n", fpr);
1102
1103   for (sl = mboxes; sl; sl = sl->next)
1104     {
1105       if (sl->mbox && !strcmp (sl->mbox, addrspec))
1106         found = 1;
1107       if (opt.verbose)
1108         {
1109           log_info ("    user-id: %s\n", sl->uid);
1110           log_info ("    created: %s\n", asctimestamp (sl->created));
1111           if (sl->mbox)
1112             log_info ("  addr-spec: %s\n", sl->mbox);
1113         }
1114     }
1115   if (!found)
1116     {
1117       log_error ("public key for '%s' has no user id with the mail address\n",
1118                  addrspec);
1119       err = gpg_error (GPG_ERR_CERT_REVOKED);
1120     }
1121
1122  leave:
1123   xfree (fpr);
1124   free_uidinfo_list (mboxes);
1125   es_fclose (key);
1126   xfree (addrspec);
1127   return err;
1128 }
1129
1130
1131 \f
1132 /* Locate the key by fingerprint and userid and send a publication
1133  * request.  */
1134 static gpg_error_t
1135 command_send (const char *fingerprint, const char *userid)
1136 {
1137   gpg_error_t err;
1138   KEYDB_SEARCH_DESC desc;
1139   char *addrspec = NULL;
1140   estream_t key = NULL;
1141   estream_t keyenc = NULL;
1142   char *submission_to = NULL;
1143   mime_maker_t mime = NULL;
1144   policy_flags_t policy = NULL;
1145   int no_encrypt = 0;
1146   int posteo_hack = 0;
1147   const char *domain;
1148   uidinfo_list_t uidlist = NULL;
1149   uidinfo_list_t uid, thisuid;
1150   time_t thistime;
1151
1152   if (classify_user_id (fingerprint, &desc, 1)
1153       || desc.mode != KEYDB_SEARCH_MODE_FPR)
1154     {
1155       log_error (_("\"%s\" is not a fingerprint\n"), fingerprint);
1156       err = gpg_error (GPG_ERR_INV_NAME);
1157       goto leave;
1158     }
1159
1160   addrspec = mailbox_from_userid (userid, 0);
1161   if (!addrspec)
1162     {
1163       log_error (_("\"%s\" is not a proper mail address\n"), userid);
1164       err = gpg_error (GPG_ERR_INV_USER_ID);
1165       goto leave;
1166     }
1167   err = wks_get_key (&key, fingerprint, addrspec, 0);
1168   if (err)
1169     goto leave;
1170
1171   domain = strchr (addrspec, '@');
1172   log_assert (domain);
1173   domain++;
1174
1175   /* Get the submission address.  */
1176   if (fake_submission_addr)
1177     {
1178       policy = xcalloc (1, sizeof *policy);
1179       submission_to = xstrdup (fake_submission_addr);
1180       err = 0;
1181     }
1182   else
1183     {
1184       err = get_policy_and_sa (addrspec, 0, &policy, &submission_to);
1185       if (err)
1186         goto leave;
1187       if (!submission_to)
1188         {
1189           log_error (_("this domain probably doesn't support WKS.\n"));
1190           err = gpg_error (GPG_ERR_NO_DATA);
1191           goto leave;
1192         }
1193     }
1194
1195   log_info ("submitting request to '%s'\n", submission_to);
1196
1197   if (policy->auth_submit)
1198     log_info ("no confirmation required for '%s'\n", addrspec);
1199
1200   /* In case the key has several uids with the same addr-spec we will
1201    * use the newest one.  */
1202   err = wks_list_key (key, NULL, &uidlist);
1203   if (err)
1204     {
1205       log_error ("error parsing key: %s\n",gpg_strerror (err));
1206       err = gpg_error (GPG_ERR_NO_PUBKEY);
1207       goto leave;
1208     }
1209   thistime = 0;
1210   thisuid = NULL;
1211   for (uid = uidlist; uid; uid = uid->next)
1212     {
1213       if (!uid->mbox)
1214         continue; /* Should not happen anyway.  */
1215       if (policy->mailbox_only && ascii_strcasecmp (uid->uid, uid->mbox))
1216         continue; /* UID has more than just the mailbox.  */
1217       if (uid->created > thistime)
1218         {
1219           thistime = uid->created;
1220           thisuid = uid;
1221         }
1222     }
1223   if (!thisuid)
1224     thisuid = uidlist;  /* This is the case for a missing timestamp.  */
1225   if (opt.verbose)
1226     log_info ("submitting key with user id '%s'\n", thisuid->uid);
1227
1228   /* If we have more than one user id we need to filter the key to
1229    * include only THISUID.  */
1230   if (uidlist->next)
1231     {
1232       estream_t newkey;
1233
1234       es_rewind (key);
1235       err = wks_filter_uid (&newkey, key, thisuid->uid, 0);
1236       if (err)
1237         {
1238           log_error ("error filtering key: %s\n", gpg_strerror (err));
1239           err = gpg_error (GPG_ERR_NO_PUBKEY);
1240           goto leave;
1241         }
1242       es_fclose (key);
1243       key = newkey;
1244     }
1245
1246   if (policy->mailbox_only
1247       && (!thisuid->mbox || ascii_strcasecmp (thisuid->uid, thisuid->mbox)))
1248     {
1249       log_info ("Warning: policy requires 'mailbox-only'"
1250                 " - adding user id '%s'\n", addrspec);
1251       err = add_user_id (fingerprint, addrspec);
1252       if (err)
1253         goto leave;
1254
1255       /* Need to get the key again.  This time we request filtering
1256        * for the full user id, so that we do not need check and filter
1257        * the key again.  */
1258       es_fclose (key);
1259       key = NULL;
1260       err = wks_get_key (&key, fingerprint, addrspec, 1);
1261       if (err)
1262         goto leave;
1263     }
1264
1265   /* Hack to support posteo but let them disable this by setting the
1266    * new policy-version flag.  */
1267   if (policy->protocol_version < 3
1268       && !ascii_strcasecmp (domain, "posteo.de"))
1269     {
1270       log_info ("Warning: Using draft-1 method for domain '%s'\n", domain);
1271       no_encrypt = 1;
1272       posteo_hack = 1;
1273     }
1274
1275   /* Encrypt the key part.  */
1276   if (!no_encrypt)
1277     {
1278       es_rewind (key);
1279       err = encrypt_response (&keyenc, key, submission_to, fingerprint);
1280       if (err)
1281         goto leave;
1282       es_fclose (key);
1283       key = NULL;
1284     }
1285
1286   /* Send the key.  */
1287   err = mime_maker_new (&mime, NULL);
1288   if (err)
1289     goto leave;
1290   err = mime_maker_add_header (mime, "From", addrspec);
1291   if (err)
1292     goto leave;
1293   err = mime_maker_add_header (mime, "To", submission_to);
1294   if (err)
1295     goto leave;
1296   err = mime_maker_add_header (mime, "Subject", "Key publishing request");
1297   if (err)
1298     goto leave;
1299
1300   /* Tell server which draft we support.  */
1301   err = mime_maker_add_header (mime, "Wks-Draft-Version",
1302                                  STR2(WKS_DRAFT_VERSION));
1303   if (err)
1304     goto leave;
1305
1306   if (no_encrypt)
1307     {
1308       void *data;
1309       size_t datalen, n;
1310
1311       if (posteo_hack)
1312         {
1313           /* Needs a multipart/mixed with one(!) attachment.  It does
1314            * not grok a non-multipart mail.  */
1315           err = mime_maker_add_header (mime, "Content-Type", "multipart/mixed");
1316           if (err)
1317             goto leave;
1318           err = mime_maker_add_container (mime);
1319           if (err)
1320             goto leave;
1321         }
1322
1323       err = mime_maker_add_header (mime, "Content-type",
1324                                    "application/pgp-keys");
1325       if (err)
1326         goto leave;
1327
1328       if (es_fclose_snatch (key, &data, &datalen))
1329         {
1330           err = gpg_error_from_syserror ();
1331           goto leave;
1332         }
1333       key = NULL;
1334       /* We need to skip over the first line which has a content-type
1335        * header not needed here.  */
1336       for (n=0; n < datalen ; n++)
1337         if (((const char *)data)[n] == '\n')
1338           {
1339             n++;
1340             break;
1341           }
1342
1343       err = mime_maker_add_body_data (mime, (char*)data + n, datalen - n);
1344       xfree (data);
1345       if (err)
1346         goto leave;
1347     }
1348   else
1349     {
1350       err = mime_maker_add_header (mime, "Content-Type",
1351                                    "multipart/encrypted; "
1352                                    "protocol=\"application/pgp-encrypted\"");
1353       if (err)
1354         goto leave;
1355       err = mime_maker_add_container (mime);
1356       if (err)
1357         goto leave;
1358
1359       err = mime_maker_add_header (mime, "Content-Type",
1360                                    "application/pgp-encrypted");
1361       if (err)
1362         goto leave;
1363       err = mime_maker_add_body (mime, "Version: 1\n");
1364       if (err)
1365         goto leave;
1366       err = mime_maker_add_header (mime, "Content-Type",
1367                                    "application/octet-stream");
1368       if (err)
1369         goto leave;
1370
1371       err = mime_maker_add_stream (mime, &keyenc);
1372       if (err)
1373         goto leave;
1374     }
1375
1376   err = wks_send_mime (mime);
1377
1378  leave:
1379   mime_maker_release (mime);
1380   xfree (submission_to);
1381   free_uidinfo_list (uidlist);
1382   es_fclose (keyenc);
1383   es_fclose (key);
1384   wks_free_policy (policy);
1385   xfree (policy);
1386   xfree (addrspec);
1387   return err;
1388 }
1389
1390
1391 \f
1392 static void
1393 encrypt_response_status_cb (void *opaque, const char *keyword, char *args)
1394 {
1395   gpg_error_t *failure = opaque;
1396   const char *fields[2];
1397
1398   if (DBG_CRYPTO)
1399     log_debug ("gpg status: %s %s\n", keyword, args);
1400
1401   if (!strcmp (keyword, "FAILURE"))
1402     {
1403       if (split_fields (args, fields, DIM (fields)) >= 2
1404           && !strcmp (fields[0], "encrypt"))
1405         *failure = strtoul (fields[1], NULL, 10);
1406     }
1407
1408 }
1409
1410
1411 /* Encrypt the INPUT stream to a new stream which is stored at success
1412  * at R_OUTPUT.  Encryption is done for ADDRSPEC and for FINGERPRINT
1413  * (so that the sent message may later be inspected by the user).  We
1414  * currently retrieve that key from the WKD, DANE, or from "local".
1415  * "local" is last to prefer the latest key version but use a local
1416  * copy in case we are working offline.  It might be useful for the
1417  * server to send the fingerprint of its encryption key - or even the
1418  * entire key back.  */
1419 static gpg_error_t
1420 encrypt_response (estream_t *r_output, estream_t input, const char *addrspec,
1421                   const char *fingerprint)
1422 {
1423   gpg_error_t err;
1424   ccparray_t ccp;
1425   const char **argv;
1426   estream_t output;
1427   gpg_error_t gpg_err = 0;
1428
1429   *r_output = NULL;
1430
1431   output = es_fopenmem (0, "w+b");
1432   if (!output)
1433     {
1434       err = gpg_error_from_syserror ();
1435       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
1436       return err;
1437     }
1438
1439   ccparray_init (&ccp, 0);
1440
1441   ccparray_put (&ccp, "--no-options");
1442   if (opt.verbose < 2)
1443     ccparray_put (&ccp, "--quiet");
1444   else
1445     ccparray_put (&ccp, "--verbose");
1446   ccparray_put (&ccp, "--batch");
1447   ccparray_put (&ccp, "--status-fd=2");
1448   ccparray_put (&ccp, "--always-trust");
1449   ccparray_put (&ccp, "--armor");
1450   ccparray_put (&ccp, "-z0");  /* No compression for improved robustness.  */
1451   if (fake_submission_addr)
1452     ccparray_put (&ccp, "--auto-key-locate=clear,local");
1453   else
1454     ccparray_put (&ccp, "--auto-key-locate=clear,wkd,dane,local");
1455   ccparray_put (&ccp, "--recipient");
1456   ccparray_put (&ccp, addrspec);
1457   ccparray_put (&ccp, "--recipient");
1458   ccparray_put (&ccp, fingerprint);
1459   ccparray_put (&ccp, "--encrypt");
1460   ccparray_put (&ccp, "--");
1461
1462   ccparray_put (&ccp, NULL);
1463   argv = ccparray_get (&ccp, NULL);
1464   if (!argv)
1465     {
1466       err = gpg_error_from_syserror ();
1467       goto leave;
1468     }
1469   err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
1470                                 NULL, output,
1471                                 encrypt_response_status_cb, &gpg_err);
1472   if (err)
1473     {
1474       if (gpg_err)
1475         err = gpg_err;
1476       log_error ("encryption failed: %s\n", gpg_strerror (err));
1477       goto leave;
1478     }
1479
1480   es_rewind (output);
1481   *r_output = output;
1482   output = NULL;
1483
1484  leave:
1485   es_fclose (output);
1486   xfree (argv);
1487   return err;
1488 }
1489
1490
1491 static gpg_error_t
1492 send_confirmation_response (const char *sender, const char *address,
1493                             const char *nonce, int encrypt,
1494                             const char *fingerprint)
1495 {
1496   gpg_error_t err;
1497   estream_t body = NULL;
1498   estream_t bodyenc = NULL;
1499   mime_maker_t mime = NULL;
1500
1501   body = es_fopenmem (0, "w+b");
1502   if (!body)
1503     {
1504       err = gpg_error_from_syserror ();
1505       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
1506       return err;
1507     }
1508
1509   /* It is fine to use 8 bit encoding because that is encrypted and
1510    * only our client will see it.  */
1511   if (encrypt)
1512     {
1513       es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
1514                 "Content-Transfer-Encoding: 8bit\n"
1515                 "\n",
1516                 body);
1517     }
1518
1519   es_fprintf (body, ("type: confirmation-response\n"
1520                      "sender: %s\n"
1521                      "address: %s\n"
1522                      "nonce: %s\n"),
1523               sender,
1524               address,
1525               nonce);
1526
1527   es_rewind (body);
1528   if (encrypt)
1529     {
1530       err = encrypt_response (&bodyenc, body, sender, fingerprint);
1531       if (err)
1532         goto leave;
1533       es_fclose (body);
1534       body = NULL;
1535     }
1536
1537   err = mime_maker_new (&mime, NULL);
1538   if (err)
1539     goto leave;
1540   err = mime_maker_add_header (mime, "From", address);
1541   if (err)
1542     goto leave;
1543   err = mime_maker_add_header (mime, "To", sender);
1544   if (err)
1545     goto leave;
1546   err = mime_maker_add_header (mime, "Subject", "Key publication confirmation");
1547   if (err)
1548     goto leave;
1549   err = mime_maker_add_header (mime, "Wks-Draft-Version",
1550                                STR2(WKS_DRAFT_VERSION));
1551   if (err)
1552     goto leave;
1553
1554   if (encrypt)
1555     {
1556       err = mime_maker_add_header (mime, "Content-Type",
1557                                    "multipart/encrypted; "
1558                                    "protocol=\"application/pgp-encrypted\"");
1559       if (err)
1560         goto leave;
1561       err = mime_maker_add_container (mime);
1562       if (err)
1563         goto leave;
1564
1565       err = mime_maker_add_header (mime, "Content-Type",
1566                                    "application/pgp-encrypted");
1567       if (err)
1568         goto leave;
1569       err = mime_maker_add_body (mime, "Version: 1\n");
1570       if (err)
1571         goto leave;
1572       err = mime_maker_add_header (mime, "Content-Type",
1573                                    "application/octet-stream");
1574       if (err)
1575         goto leave;
1576
1577       err = mime_maker_add_stream (mime, &bodyenc);
1578       if (err)
1579         goto leave;
1580     }
1581   else
1582     {
1583       err = mime_maker_add_header (mime, "Content-Type",
1584                                    "application/vnd.gnupg.wks");
1585       if (err)
1586         goto leave;
1587       err = mime_maker_add_stream (mime, &body);
1588       if (err)
1589         goto leave;
1590     }
1591
1592   err = wks_send_mime (mime);
1593
1594  leave:
1595   mime_maker_release (mime);
1596   es_fclose (bodyenc);
1597   es_fclose (body);
1598   return err;
1599 }
1600
1601
1602 /* Reply to a confirmation request.  The MSG has already been
1603  * decrypted and we only need to send the nonce back.  MAINFPR is
1604  * either NULL or the primary key fingerprint of the key used to
1605  * decrypt the request.  */
1606 static gpg_error_t
1607 process_confirmation_request (estream_t msg, const char *mainfpr)
1608 {
1609   gpg_error_t err;
1610   nvc_t nvc;
1611   nve_t item;
1612   const char *value, *sender, *address, *fingerprint, *nonce;
1613
1614   err = nvc_parse (&nvc, NULL, msg);
1615   if (err)
1616     {
1617       log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
1618       goto leave;
1619     }
1620
1621   if (DBG_MIME)
1622     {
1623       log_debug ("request follows:\n");
1624       nvc_write (nvc, log_get_stream ());
1625     }
1626
1627   /* Check that this is a confirmation request.  */
1628   if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
1629         && !strcmp (value, "confirmation-request")))
1630     {
1631       if (item && value)
1632         log_error ("received unexpected wks message '%s'\n", value);
1633       else
1634         log_error ("received invalid wks message: %s\n", "'type' missing");
1635       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1636       goto leave;
1637     }
1638
1639   /* Get the fingerprint.  */
1640   if (!((item = nvc_lookup (nvc, "fingerprint:"))
1641         && (value = nve_value (item))
1642         && strlen (value) >= 40))
1643     {
1644       log_error ("received invalid wks message: %s\n",
1645                  "'fingerprint' missing or invalid");
1646       err = gpg_error (GPG_ERR_INV_DATA);
1647       goto leave;
1648     }
1649   fingerprint = value;
1650
1651   /* Check that the fingerprint matches the key used to decrypt the
1652    * message.  In --read mode or with the old format we don't have the
1653    * decryption key; thus we can't bail out.  */
1654   if (!mainfpr || ascii_strcasecmp (mainfpr, fingerprint))
1655     {
1656       log_info ("target fingerprint: %s\n", fingerprint);
1657       log_info ("but decrypted with: %s\n", mainfpr);
1658       log_error ("confirmation request not decrypted with target key\n");
1659       if (mainfpr)
1660         {
1661           err = gpg_error (GPG_ERR_INV_DATA);
1662           goto leave;
1663         }
1664     }
1665
1666   /* Get the address.  */
1667   if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
1668         && is_valid_mailbox (value)))
1669     {
1670       log_error ("received invalid wks message: %s\n",
1671                  "'address' missing or invalid");
1672       err = gpg_error (GPG_ERR_INV_DATA);
1673       goto leave;
1674     }
1675   address = value;
1676   /* FIXME: Check that the "address" matches the User ID we want to
1677    * publish.  */
1678
1679   /* Get the sender.  */
1680   if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
1681         && is_valid_mailbox (value)))
1682     {
1683       log_error ("received invalid wks message: %s\n",
1684                  "'sender' missing or invalid");
1685       err = gpg_error (GPG_ERR_INV_DATA);
1686       goto leave;
1687     }
1688   sender = value;
1689   /* FIXME: Check that the "sender" matches the From: address.  */
1690
1691   /* Get the nonce.  */
1692   if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
1693         && strlen (value) > 16))
1694     {
1695       log_error ("received invalid wks message: %s\n",
1696                  "'nonce' missing or too short");
1697       err = gpg_error (GPG_ERR_INV_DATA);
1698       goto leave;
1699     }
1700   nonce = value;
1701
1702   /* Send the confirmation.  If no key was found, try again without
1703    * encryption.  */
1704   err = send_confirmation_response (sender, address, nonce, 1, fingerprint);
1705   if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1706     {
1707       log_info ("no encryption key found - sending response in the clear\n");
1708       err = send_confirmation_response (sender, address, nonce, 0, NULL);
1709     }
1710
1711  leave:
1712   nvc_release (nvc);
1713   return err;
1714 }
1715
1716
1717 /* Read a confirmation request and decrypt it if needed.  This
1718  * function may not be used with a mail or MIME message but only with
1719  * the actual encrypted or plaintext WKS data.  */
1720 static gpg_error_t
1721 read_confirmation_request (estream_t msg)
1722 {
1723   gpg_error_t err;
1724   int c;
1725   estream_t plaintext = NULL;
1726
1727   /* We take a really simple approach to check whether MSG is
1728    * encrypted: We know that an encrypted message is always armored
1729    * and thus starts with a few dashes.  It is even sufficient to
1730    * check for a single dash, because that can never be a proper first
1731    * WKS data octet.  We need to skip leading spaces, though. */
1732   while ((c = es_fgetc (msg)) == ' ' || c == '\t' || c == '\r' || c == '\n')
1733     ;
1734   if (c == EOF)
1735     {
1736       log_error ("can't process an empty message\n");
1737       return gpg_error (GPG_ERR_INV_DATA);
1738     }
1739   if (es_ungetc (c, msg) != c)
1740     {
1741       log_error ("error ungetting octet from message\n");
1742       return gpg_error (GPG_ERR_INTERNAL);
1743     }
1744
1745   if (c != '-')
1746     err = process_confirmation_request (msg, NULL);
1747   else
1748     {
1749       struct decrypt_stream_parm_s decinfo;
1750
1751       err = decrypt_stream (&plaintext, &decinfo, msg);
1752       if (err)
1753         log_error ("decryption failed: %s\n", gpg_strerror (err));
1754       else if (decinfo.otrust != 'u')
1755         {
1756           err = gpg_error (GPG_ERR_WRONG_SECKEY);
1757           log_error ("key used to decrypt the confirmation request"
1758                      " was not generated by us (otrust=%c)\n", decinfo.otrust);
1759         }
1760       else
1761         err = process_confirmation_request (plaintext, decinfo.mainfpr);
1762       xfree (decinfo.fpr);
1763       xfree (decinfo.mainfpr);
1764     }
1765
1766   es_fclose (plaintext);
1767   return err;
1768 }
1769
1770
1771 /* Called from the MIME receiver to process the plain text data in MSG.  */
1772 static gpg_error_t
1773 command_receive_cb (void *opaque, const char *mediatype,
1774                     estream_t msg, unsigned int flags)
1775 {
1776   gpg_error_t err;
1777
1778   (void)opaque;
1779   (void)flags;
1780
1781   if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
1782     err = read_confirmation_request (msg);
1783   else
1784     {
1785       log_info ("ignoring unexpected message of type '%s'\n", mediatype);
1786       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1787     }
1788
1789   return err;
1790 }
1791
1792
1793 \f
1794 /* An object used to communicate with the mirror_one_key callback.  */
1795 struct
1796 {
1797   const char *domain;
1798   int anyerror;
1799   unsigned int nkeys;   /* Number of keys processed.  */
1800   unsigned int nuids;   /* Number of published user ids.  */
1801 } mirror_one_key_parm;
1802
1803
1804 /* Return true if the Given a mail DOMAIN and the full addrspec MBOX
1805  * match.  */
1806 static int
1807 domain_matches_mbox (const char *domain, const char *mbox)
1808 {
1809   const char *s;
1810
1811   if (!domain || !mbox)
1812     return 0;
1813   s = strchr (domain, '@');
1814   if (s)
1815     domain = s+1;
1816   if (!*domain)
1817     return 0; /* Not a valid domain.  */
1818
1819   s = strchr (mbox, '@');
1820   if (!s || !s[1])
1821     return 0; /* Not a valid mbox.  */
1822   mbox = s+1;
1823
1824   return !ascii_strcasecmp (domain, mbox);
1825 }
1826
1827
1828 /* Core of mirror_one_key with the goal of mirroring just one uid.
1829  * UIDLIST is used to figure out whether the given MBOX occurs several
1830  * times in UIDLIST and then to single out the newwest one.  This is
1831  * so that for a key with
1832  *    uid: Joe Someone <joe@example.org>
1833  *    uid: Joe <joe@example.org>
1834  * only the news user id (and thus its self-signature) is used.
1835  * UIDLIST is nodified to set all MBOX fields to NULL for a processed
1836  * user id.  FPR is the fingerprint of the key.
1837  */
1838 static gpg_error_t
1839 mirror_one_keys_userid (estream_t key, const char *mbox, uidinfo_list_t uidlist,
1840                         const char *fpr)
1841 {
1842   gpg_error_t err;
1843   uidinfo_list_t uid, thisuid, firstuid;
1844   time_t thistime;
1845   estream_t newkey = NULL;
1846
1847   /* Find the UID we want to use.  */
1848   thistime = 0;
1849   thisuid = firstuid = NULL;
1850   for (uid = uidlist; uid; uid = uid->next)
1851     {
1852       if ((uid->flags & 1) || !uid->mbox || strcmp (uid->mbox, mbox))
1853         continue; /* Already processed or no matching mbox.  */
1854       uid->flags |= 1;  /* Set "processed" flag.  */
1855       if (!firstuid)
1856         firstuid = uid;
1857       if (uid->created > thistime)
1858         {
1859           thistime = uid->created;
1860           thisuid = uid;
1861         }
1862     }
1863   if (!thisuid)
1864     thisuid = firstuid;  /* This is the case for a missing timestamp.  */
1865   if (!thisuid)
1866     {
1867       log_error ("error finding the user id for %s (%s)\n", fpr, mbox);
1868       err = gpg_error (GPG_ERR_NO_USER_ID);
1869       goto leave;
1870     }
1871   /* FIXME: Consult blacklist.  */
1872
1873
1874   /* Only if we have more than one user id we bother to run the
1875    * filter.  In this case the result will be put into NEWKEY*/
1876   es_rewind (key);
1877   if (uidlist->next)
1878     {
1879       err = wks_filter_uid (&newkey, key, thisuid->uid, 0);
1880       if (err)
1881         {
1882           log_error ("error filtering key %s: %s\n", fpr, gpg_strerror (err));
1883           err = gpg_error (GPG_ERR_NO_PUBKEY);
1884           goto leave;
1885         }
1886     }
1887
1888   err = wks_install_key_core (newkey? newkey : key, mbox);
1889   if (opt.verbose)
1890     log_info ("key %s published for '%s'\n", fpr, mbox);
1891   mirror_one_key_parm.nuids++;
1892   if (!opt.quiet && !(mirror_one_key_parm.nuids % 25))
1893     log_info ("%u user ids from %d keys so far\n",
1894               mirror_one_key_parm.nuids, mirror_one_key_parm.nkeys);
1895
1896  leave:
1897   es_fclose (newkey);
1898   return err;
1899 }
1900
1901
1902 /* The callback used by command_mirror.  It received an estream with
1903  * one key and should return success to process the next key.  */
1904 static gpg_error_t
1905 mirror_one_key (estream_t key)
1906 {
1907   gpg_error_t err = 0;
1908   char *fpr;
1909   uidinfo_list_t uidlist = NULL;
1910   uidinfo_list_t uid;
1911   const char *domain = mirror_one_key_parm.domain;
1912
1913   /* List the key to get all user ids.  */
1914   err = wks_list_key (key, &fpr, &uidlist);
1915   if (err)
1916     {
1917       log_error ("error parsing a key: %s - skipped\n",
1918                  gpg_strerror (err));
1919       mirror_one_key_parm.anyerror = 1;
1920       err = 0;
1921       goto leave;
1922     }
1923   for (uid = uidlist; uid; uid = uid->next)
1924     {
1925       if (!uid->mbox || (uid->flags & 1))
1926         continue; /* No mail box or already processed.  */
1927       if (!domain_matches_mbox (domain, uid->mbox))
1928         continue; /* We don't want this one.  */
1929       if (is_in_blacklist (uid->mbox))
1930         continue;
1931
1932       err = mirror_one_keys_userid (key, uid->mbox, uidlist, fpr);
1933       if (err)
1934         {
1935           log_error ("error processing key %s: %s - skipped\n",
1936                      fpr, gpg_strerror (err));
1937           mirror_one_key_parm.anyerror = 1;
1938           err = 0;
1939           goto leave;
1940         }
1941     }
1942   mirror_one_key_parm.nkeys++;
1943
1944
1945  leave:
1946   free_uidinfo_list (uidlist);
1947   xfree (fpr);
1948   return err;
1949 }
1950
1951
1952 /* Copy the keys from the configured LDAP server into a local WKD.
1953  * DOMAINLIST is an array of domain names to restrict the copy to only
1954  * the given domains; if it is NULL all keys are mirrored.  */
1955 static gpg_error_t
1956 command_mirror (char *domainlist[])
1957 {
1958   gpg_error_t err;
1959   const char *domain;
1960   char *domainbuf = NULL;
1961
1962   mirror_one_key_parm.anyerror = 0;
1963   mirror_one_key_parm.nkeys = 0;
1964   mirror_one_key_parm.nuids = 0;
1965
1966   if (!domainlist)
1967     {
1968       mirror_one_key_parm.domain = "";
1969       err = wkd_dirmngr_ks_get (NULL, mirror_one_key);
1970     }
1971   else
1972     {
1973       while ((domain = *domainlist++))
1974         {
1975           if (*domain != '.' && domain[1] != '@')
1976             {
1977               /* This does not already specify a mail search by
1978                * domain.  Change it.  */
1979               xfree (domainbuf);
1980               domainbuf = xstrconcat (".@", domain, NULL);
1981               domain = domainbuf;
1982             }
1983           mirror_one_key_parm.domain = domain;
1984           if (opt.verbose)
1985             log_info ("mirroring keys for domain '%s'\n", domain+2);
1986           err = wkd_dirmngr_ks_get (domain, mirror_one_key);
1987           if (err)
1988             break;
1989         }
1990     }
1991
1992   if (!opt.quiet)
1993     log_info ("a total of %u user ids from %d keys published\n",
1994               mirror_one_key_parm.nuids, mirror_one_key_parm.nkeys);
1995   if (err)
1996     log_error ("error mirroring LDAP directory: %s <%s>\n",
1997                gpg_strerror (err), gpg_strsource (err));
1998   else if (mirror_one_key_parm.anyerror)
1999     log_info ("warning: errors encountered - not all keys are mirrored\n");
2000
2001   xfree (domainbuf);
2002   return err;
2003 }