wks: Try to send an encrypted confirmation back.
[gnupg.git] / tools / gpg-wks-server.c
1 /* gpg-wks-server.c - A server for the Web Key Service protocols.
2  * Copyright (C) 2016 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* The Web Key Service I-D defines an update protocol to stpre a
21  * public key in the Web Key Directory.  The current specification is
22  * draft-koch-openpgp-webkey-service-01.txt.
23  */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #ifdef HAVE_STAT
31 # include <sys/stat.h>
32 #endif
33
34 #include "util.h"
35 #include "init.h"
36 #include "sysutils.h"
37 #include "ccparray.h"
38 #include "exectool.h"
39 #include "zb32.h"
40 #include "mbox-util.h"
41 #include "name-value.h"
42 #include "mime-maker.h"
43 #include "send-mail.h"
44 #include "gpg-wks.h"
45
46
47 /* Constants to identify the commands and options. */
48 enum cmd_and_opt_values
49   {
50     aNull = 0,
51
52     oQuiet      = 'q',
53     oVerbose    = 'v',
54     oOutput     = 'o',
55
56     oDebug      = 500,
57
58     aReceive,
59     aCron,
60
61     oGpgProgram,
62     oSend,
63     oFrom,
64     oHeader,
65
66     oDummy
67   };
68
69
70 /* The list of commands and options. */
71 static ARGPARSE_OPTS opts[] = {
72   ARGPARSE_group (300, ("@Commands:\n ")),
73
74   ARGPARSE_c (aReceive,   "receive",
75               ("receive a submission or confirmation")),
76   ARGPARSE_c (aCron,      "cron",
77               ("run regular jobs")),
78
79   ARGPARSE_group (301, ("@\nOptions:\n ")),
80
81   ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
82   ARGPARSE_s_n (oQuiet, "quiet",  ("be somewhat more quiet")),
83   ARGPARSE_s_s (oDebug, "debug", "@"),
84   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
85   ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
86   ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
87   ARGPARSE_s_s (oFrom, "from", "|ADDR|use ADDR as the default sender"),
88   ARGPARSE_s_s (oHeader, "header" ,
89                 "|NAME=VALUE|add \"NAME: VALUE\" as header to all mails"),
90
91   ARGPARSE_end ()
92 };
93
94
95 /* The list of supported debug flags.  */
96 static struct debug_flags_s debug_flags [] =
97   {
98     { DBG_CRYPTO_VALUE , "crypto"  },
99     { DBG_MEMORY_VALUE , "memory"  },
100     { DBG_MEMSTAT_VALUE, "memstat" },
101     { DBG_IPC_VALUE    , "ipc"     },
102     { DBG_EXTPROG_VALUE, "extprog" },
103     { 0, NULL }
104   };
105
106
107 /* State for processing a message.  */
108 struct server_ctx_s
109 {
110   char *fpr;
111   strlist_t mboxes;  /* List of addr-specs taken from the UIDs.  */
112 };
113 typedef struct server_ctx_s *server_ctx_t;
114
115
116
117 static gpg_error_t command_receive_cb (void *opaque,
118                                        const char *mediatype, estream_t fp);
119
120
121 \f
122 /* Print usage information and and provide strings for help. */
123 static const char *
124 my_strusage( int level )
125 {
126   const char *p;
127
128   switch (level)
129     {
130     case 11: p = "gpg-wks-server (@GNUPG@)";
131       break;
132     case 13: p = VERSION; break;
133     case 17: p = PRINTABLE_OS_NAME; break;
134     case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
135
136     case 1:
137     case 40:
138       p = ("Usage: gpg-wks-server command [options] (-h for help)");
139       break;
140     case 41:
141       p = ("Syntax: gpg-wks-server command [options]\n"
142            "Server for the Web Key Service protocol\n");
143       break;
144
145     default: p = NULL; break;
146     }
147   return p;
148 }
149
150
151 static void
152 wrong_args (const char *text)
153 {
154   es_fprintf (es_stderr, "usage: %s [options] %s\n", strusage (11), text);
155   exit (2);
156 }
157
158
159 \f
160 /* Command line parsing.  */
161 static enum cmd_and_opt_values
162 parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
163 {
164   enum cmd_and_opt_values cmd = 0;
165   int no_more_options = 0;
166
167   while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
168     {
169       switch (pargs->r_opt)
170         {
171         case oQuiet:     opt.quiet = 1; break;
172         case oVerbose:   opt.verbose++; break;
173         case oDebug:
174           if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
175             {
176               pargs->r_opt = ARGPARSE_INVALID_ARG;
177               pargs->err = ARGPARSE_PRINT_ERROR;
178             }
179           break;
180
181         case oGpgProgram:
182           opt.gpg_program = pargs->r.ret_str;
183           break;
184         case oFrom:
185           opt.default_from = pargs->r.ret_str;
186           break;
187         case oHeader:
188           append_to_strlist (&opt.extra_headers, pargs->r.ret_str);
189           break;
190         case oSend:
191           opt.use_sendmail = 1;
192           break;
193         case oOutput:
194           opt.output = pargs->r.ret_str;
195           break;
196
197         case aReceive:
198         case aCron:
199           cmd = pargs->r_opt;
200           break;
201
202         default: pargs->err = 2; break;
203         }
204     }
205
206   return cmd;
207 }
208
209
210 \f
211 /* gpg-wks-server main. */
212 int
213 main (int argc, char **argv)
214 {
215   gpg_error_t err;
216   ARGPARSE_ARGS pargs;
217   enum cmd_and_opt_values cmd;
218
219   gnupg_reopen_std ("gpg-wks-server");
220   set_strusage (my_strusage);
221   log_set_prefix ("gpg-wks-server", GPGRT_LOG_WITH_PREFIX);
222
223   /* Make sure that our subsystems are ready.  */
224   init_common_subsystems (&argc, &argv);
225
226   /* Parse the command line. */
227   pargs.argc  = &argc;
228   pargs.argv  = &argv;
229   pargs.flags = ARGPARSE_FLAG_KEEP;
230   cmd = parse_arguments (&pargs, opts);
231
232   if (log_get_errorcount (0))
233     exit (2);
234
235   /* Print a warning if an argument looks like an option.  */
236   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
237     {
238       int i;
239
240       for (i=0; i < argc; i++)
241         if (argv[i][0] == '-' && argv[i][1] == '-')
242           log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
243     }
244
245   /* Set defaults for non given options.  */
246   if (!opt.gpg_program)
247     opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
248
249   if (!opt.directory)
250     opt.directory = "/var/lib/gnupg/wks";
251
252   /* Check for syntax errors in the --header option to avoid later
253    * error messages with a not easy to find cause */
254   if (opt.extra_headers)
255     {
256       strlist_t sl;
257
258       for (sl = opt.extra_headers; sl; sl = sl->next)
259         {
260           err = mime_maker_add_header (NULL, sl->d, NULL);
261           if (err)
262             log_error ("syntax error in \"--header %s\": %s\n",
263                        sl->d, gpg_strerror (err));
264         }
265     }
266
267   if (log_get_errorcount (0))
268     exit (2);
269
270
271   /* Check that we have a working directory.  */
272 #if defined(HAVE_STAT)
273   {
274     struct stat sb;
275
276     if (stat (opt.directory, &sb))
277       {
278         err = gpg_error_from_syserror ();
279         log_error ("error accessing directory '%s': %s\n",
280                    opt.directory, gpg_strerror (err));
281         exit (2);
282       }
283     if (!S_ISDIR(sb.st_mode))
284       {
285         log_error ("error accessing directory '%s': %s\n",
286                    opt.directory, "not a directory");
287         exit (2);
288       }
289     if (sb.st_uid != getuid())
290       {
291         log_error ("directory '%s' not owned by user\n", opt.directory);
292         exit (2);
293       }
294     if ((sb.st_mode & S_IRWXO))
295       {
296         log_error ("directory '%s' has too relaxed permissions\n",
297                    opt.directory);
298         exit (2);
299       }
300   }
301 #else /*!HAVE_STAT*/
302   log_fatal ("program build w/o stat() call\n");
303 #endif /*!HAVE_STAT*/
304
305   /* Run the selected command.  */
306   switch (cmd)
307     {
308     case aReceive:
309       if (argc)
310         wrong_args ("--receive");
311       err = wks_receive (es_stdin, command_receive_cb, NULL);
312       if (err)
313         log_error ("processing mail failed: %s\n", gpg_strerror (err));
314       break;
315
316     case aCron:
317       if (argc)
318         wrong_args ("--cron");
319       break;
320
321     default:
322       usage (1);
323       break;
324     }
325
326   return log_get_errorcount (0)? 1:0;
327 }
328
329
330 \f
331 static void
332 list_key_status_cb (void *opaque, const char *keyword, char *args)
333 {
334   server_ctx_t ctx = opaque;
335   (void)ctx;
336   if (opt.debug)
337     log_debug ("%s: %s\n", keyword, args);
338 }
339
340
341 static gpg_error_t
342 list_key (server_ctx_t ctx, estream_t key)
343 {
344   gpg_error_t err;
345   ccparray_t ccp;
346   const char **argv;
347   estream_t listing;
348   char *line = NULL;
349   size_t length_of_line = 0;
350   size_t  maxlen;
351   ssize_t len;
352   char **fields = NULL;
353   int nfields;
354   int lnr;
355   char *mbox = NULL;
356
357   /* We store our results in the context - clear it first.  */
358   xfree (ctx->fpr);
359   ctx->fpr = NULL;
360   free_strlist (ctx->mboxes);
361   ctx->mboxes = NULL;
362
363   /* Open a memory stream.  */
364   listing = es_fopenmem (0, "w+b");
365   if (!listing)
366     {
367       err = gpg_error_from_syserror ();
368       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
369       return err;
370     }
371
372   ccparray_init (&ccp, 0);
373
374   ccparray_put (&ccp, "--no-options");
375   if (!opt.verbose)
376     ccparray_put (&ccp, "--quiet");
377   else if (opt.verbose > 1)
378     ccparray_put (&ccp, "--verbose");
379   ccparray_put (&ccp, "--batch");
380   ccparray_put (&ccp, "--status-fd=2");
381   ccparray_put (&ccp, "--always-trust");
382   ccparray_put (&ccp, "--with-colons");
383   ccparray_put (&ccp, "--dry-run");
384   ccparray_put (&ccp, "--import-options=import-minimal,import-show");
385   ccparray_put (&ccp, "--import");
386
387   ccparray_put (&ccp, NULL);
388   argv = ccparray_get (&ccp, NULL);
389   if (!argv)
390     {
391       err = gpg_error_from_syserror ();
392       goto leave;
393     }
394   err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
395                                 NULL, listing,
396                                 list_key_status_cb, ctx);
397   if (err)
398     {
399       log_error ("import failed: %s\n", gpg_strerror (err));
400       goto leave;
401     }
402
403   es_rewind (listing);
404   lnr = 0;
405   maxlen = 2048; /* Set limit.  */
406   while ((len = es_read_line (listing, &line, &length_of_line, &maxlen)) > 0)
407     {
408       lnr++;
409       if (!maxlen)
410         {
411           log_error ("received line too long\n");
412           err = gpg_error (GPG_ERR_LINE_TOO_LONG);
413           goto leave;
414         }
415       /* Strip newline and carriage return, if present.  */
416       while (len > 0
417              && (line[len - 1] == '\n' || line[len - 1] == '\r'))
418         line[--len] = '\0';
419       /* log_debug ("line '%s'\n", line); */
420
421       xfree (fields);
422       fields = strtokenize (line, ":");
423       if (!fields)
424         {
425           err = gpg_error_from_syserror ();
426           log_error ("strtokenize failed: %s\n", gpg_strerror (err));
427           goto leave;
428         }
429       for (nfields = 0; fields[nfields]; nfields++)
430         ;
431       if (!nfields)
432         {
433           err = gpg_error (GPG_ERR_INV_ENGINE);
434           goto leave;
435         }
436       if (!strcmp (fields[0], "sec"))
437         {
438           /* gpg may return "sec" as the first record - but we do not
439            * accept secret keys.  */
440           err = gpg_error (GPG_ERR_NO_PUBKEY);
441           goto leave;
442         }
443       if (lnr == 1 && strcmp (fields[0], "pub"))
444         {
445           /* First record is not a public key.  */
446           err = gpg_error (GPG_ERR_INV_ENGINE);
447           goto leave;
448         }
449       if (lnr > 1 && !strcmp (fields[0], "pub"))
450         {
451           /* More than one public key.  */
452           err = gpg_error (GPG_ERR_TOO_MANY);
453           goto leave;
454         }
455       if (!strcmp (fields[0], "sub") || !strcmp (fields[0], "ssb"))
456         break; /* We can stop parsing here.  */
457
458       if (!strcmp (fields[0], "fpr") && nfields > 9 && !ctx->fpr)
459         {
460           ctx->fpr = xtrystrdup (fields[9]);
461           if (!ctx->fpr)
462             {
463               err = gpg_error_from_syserror ();
464               goto leave;
465             }
466         }
467       else if (!strcmp (fields[0], "uid") && nfields > 9)
468         {
469           /* Fixme: Unescape fields[9] */
470           xfree (mbox);
471           mbox = mailbox_from_userid (fields[9]);
472           if (mbox && !append_to_strlist_try (&ctx->mboxes, mbox))
473             {
474               err = gpg_error_from_syserror ();
475               goto leave;
476             }
477         }
478     }
479   if (len < 0 || es_ferror (listing))
480     log_error ("error reading memory stream\n");
481
482  leave:
483   xfree (mbox);
484   xfree (fields);
485   es_free (line);
486   xfree (argv);
487   es_fclose (listing);
488   return err;
489 }
490
491
492 /* Take the key in KEYFILE and write it to DANEFILE using the DANE
493  * output format. */
494 static gpg_error_t
495 copy_key_as_dane (const char *keyfile, const char *danefile)
496 {
497   gpg_error_t err;
498   ccparray_t ccp;
499   const char **argv;
500
501   ccparray_init (&ccp, 0);
502
503   ccparray_put (&ccp, "--no-options");
504   if (!opt.verbose)
505     ccparray_put (&ccp, "--quiet");
506   else if (opt.verbose > 1)
507     ccparray_put (&ccp, "--verbose");
508   ccparray_put (&ccp, "--batch");
509   ccparray_put (&ccp, "--yes");
510   ccparray_put (&ccp, "--always-trust");
511   ccparray_put (&ccp, "--no-keyring");
512   ccparray_put (&ccp, "--output");
513   ccparray_put (&ccp, danefile);
514   ccparray_put (&ccp, "--export-options=export-dane");
515   ccparray_put (&ccp, "--import-options=import-export");
516   ccparray_put (&ccp, "--import");
517   ccparray_put (&ccp, "--");
518   ccparray_put (&ccp, keyfile);
519
520   ccparray_put (&ccp, NULL);
521   argv = ccparray_get (&ccp, NULL);
522   if (!argv)
523     {
524       err = gpg_error_from_syserror ();
525       goto leave;
526     }
527   err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
528                                 NULL, NULL, NULL, NULL);
529   if (err)
530     {
531       log_error ("%s failed: %s\n", __func__, gpg_strerror (err));
532       goto leave;
533     }
534
535  leave:
536   xfree (argv);
537   return err;
538 }
539
540
541 static void
542 encrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
543 {
544   (void)opaque;
545
546   if (opt.debug)
547     log_debug ("%s: %s\n", keyword, args);
548 }
549
550
551 /* Encrypt the INPUT stream to a new stream which is stored at success
552  * at R_OUTPUT.  Encryption is done for the key in file KEYFIL.  */
553 static gpg_error_t
554 encrypt_stream (estream_t *r_output, estream_t input, const char *keyfile)
555 {
556   gpg_error_t err;
557   ccparray_t ccp;
558   const char **argv;
559   estream_t output;
560
561   *r_output = NULL;
562
563   output = es_fopenmem (0, "w+b");
564   if (!output)
565     {
566       err = gpg_error_from_syserror ();
567       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
568       return err;
569     }
570
571   ccparray_init (&ccp, 0);
572
573   ccparray_put (&ccp, "--no-options");
574   if (!opt.verbose)
575     ccparray_put (&ccp, "--quiet");
576   else if (opt.verbose > 1)
577     ccparray_put (&ccp, "--verbose");
578   ccparray_put (&ccp, "--batch");
579   ccparray_put (&ccp, "--status-fd=2");
580   ccparray_put (&ccp, "--always-trust");
581   ccparray_put (&ccp, "--no-keyring");
582   ccparray_put (&ccp, "--armor");
583   ccparray_put (&ccp, "--recipient-file");
584   ccparray_put (&ccp, keyfile);
585   ccparray_put (&ccp, "--encrypt");
586   ccparray_put (&ccp, "--");
587
588   ccparray_put (&ccp, NULL);
589   argv = ccparray_get (&ccp, NULL);
590   if (!argv)
591     {
592       err = gpg_error_from_syserror ();
593       goto leave;
594     }
595   err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
596                                 NULL, output,
597                                 encrypt_stream_status_cb, NULL);
598   if (err)
599     {
600       log_error ("encryption failed: %s\n", gpg_strerror (err));
601       goto leave;
602     }
603
604   es_rewind (output);
605   *r_output = output;
606   output = NULL;
607
608  leave:
609   es_fclose (output);
610   xfree (argv);
611   return err;
612 }
613
614
615 /* Get the submission address for address MBOX.  Caller must free the
616  * value.  If no address can be found NULL is returned.  */
617 static char *
618 get_submission_address (const char *mbox)
619 {
620   gpg_error_t err;
621   const char *domain;
622   char *fname, *line, *p;
623   size_t n;
624   estream_t fp;
625
626   domain = strchr (mbox, '@');
627   if (!domain)
628     return NULL;
629   domain++;
630
631   fname = make_filename_try (opt.directory, domain, "submission-address", NULL);
632   if (!fname)
633     {
634       err = gpg_error_from_syserror ();
635       log_error ("make_filename failed in %s: %s\n",
636                  __func__, gpg_strerror (err));
637       return NULL;
638     }
639
640   fp = es_fopen (fname, "r");
641   if (!fp)
642     {
643       err = gpg_error_from_syserror ();
644       if (gpg_err_code (err) == GPG_ERR_ENOENT)
645         log_info ("Note: no specific submission address configured"
646                   " for domain '%s'\n", domain);
647       else
648         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
649       xfree (fname);
650       return NULL;
651     }
652
653   line = NULL;
654   n = 0;
655   if (es_getline (&line, &n, fp) < 0)
656     {
657       err = gpg_error_from_syserror ();
658       log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
659       xfree (line);
660       es_fclose (fp);
661       xfree (fname);
662       return NULL;
663     }
664   es_fclose (fp);
665   xfree (fname);
666
667   p = strchr (line, '\n');
668   if (p)
669     *p = 0;
670   trim_spaces (line);
671   if (!is_valid_mailbox (line))
672     {
673       log_error ("invalid submission address for domain '%s' detected\n",
674                  domain);
675       xfree (line);
676       return NULL;
677     }
678
679   return line;
680 }
681
682
683 /* We store the key under the name of the nonce we will then send to
684  * the user.  On success the nonce is stored at R_NONCE and the file
685  * name at R_FNAME.  */
686 static gpg_error_t
687 store_key_as_pending (const char *dir, estream_t key,
688                       char **r_nonce, char **r_fname)
689 {
690   gpg_error_t err;
691   char *dname = NULL;
692   char *fname = NULL;
693   char *nonce = NULL;
694   estream_t outfp = NULL;
695   char buffer[1024];
696   size_t nbytes, nwritten;
697
698   *r_nonce = NULL;
699   *r_fname = NULL;
700
701   dname = make_filename_try (dir, "pending", NULL);
702   if (!dname)
703     {
704       err = gpg_error_from_syserror ();
705       goto leave;
706     }
707
708   if (!gnupg_mkdir (dname, "-rwx"))
709     log_info ("directory '%s' created\n", dname);
710
711   /* Create the nonce.  We use 20 bytes so that we don't waste a
712    * character in our zBase-32 encoding.  Using the gcrypt's nonce
713    * function is faster than using the strong random function; this is
714    * Good Enough for our purpose.  */
715   log_assert (sizeof buffer > 20);
716   gcry_create_nonce (buffer, 20);
717   nonce = zb32_encode (buffer, 8 * 20);
718   memset (buffer, 0, 20);  /* Not actually needed but it does not harm. */
719   if (!nonce)
720     {
721       err = gpg_error_from_syserror ();
722       goto leave;
723     }
724
725   fname = strconcat (dname, "/", nonce, NULL);
726   if (!fname)
727     {
728       err = gpg_error_from_syserror ();
729       goto leave;
730     }
731
732   /* With 128 bits of random we can expect that no other file exists
733    * under this name.  We use "x" to detect internal errors.  */
734   outfp = es_fopen (fname, "wbx,mode=-rw");
735   if (!outfp)
736     {
737       err = gpg_error_from_syserror ();
738       log_error ("error creating '%s': %s\n", fname, gpg_strerror (err));
739       goto leave;
740     }
741   es_rewind (key);
742   for (;;)
743     {
744       if (es_read (key, buffer, sizeof buffer, &nbytes))
745         {
746           err = gpg_error_from_syserror ();
747           log_error ("error reading '%s': %s\n",
748                      es_fname_get (key), gpg_strerror (err));
749           break;
750         }
751
752       if (!nbytes)
753         {
754           err = 0;
755           goto leave; /* Ready.  */
756         }
757       if (es_write (outfp, buffer, nbytes, &nwritten))
758         {
759           err = gpg_error_from_syserror ();
760           log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
761           goto leave;
762         }
763       else if (nwritten != nbytes)
764         {
765           err = gpg_error (GPG_ERR_EIO);
766           log_error ("error writing '%s': %s\n", fname, "short write");
767           goto leave;
768         }
769     }
770
771  leave:
772   if (err)
773     {
774       es_fclose (outfp);
775       gnupg_remove (fname);
776     }
777   else if (es_fclose (outfp))
778     {
779       err = gpg_error_from_syserror ();
780       log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
781     }
782
783   if (!err)
784     {
785       *r_nonce = nonce;
786       *r_fname = fname;
787     }
788   else
789     {
790       xfree (nonce);
791       xfree (fname);
792     }
793   xfree (dname);
794   return err;
795 }
796
797
798 /* Send a confirmation rewqyest.  DIR is the directory used for the
799  * address MBOX.  NONCE is the nonce we want to see in the response to
800  * this mail.  FNAME the name of the file with the key.  */
801 static gpg_error_t
802 send_confirmation_request (server_ctx_t ctx,
803                            const char *mbox, const char *nonce,
804                            const char *keyfile)
805 {
806   gpg_error_t err;
807   estream_t body = NULL;
808   estream_t bodyenc = NULL;
809   mime_maker_t mime = NULL;
810   char *from_buffer = NULL;
811   const char *from;
812   strlist_t sl;
813
814   from = from_buffer = get_submission_address (mbox);
815   if (!from)
816     {
817       from = opt.default_from;
818       if (!from)
819         {
820           log_error ("no sender address found for '%s'\n", mbox);
821           err = gpg_error (GPG_ERR_CONFIGURATION);
822           goto leave;
823         }
824       log_info ("Note: using default sender address '%s'\n", from);
825     }
826
827   body = es_fopenmem (0, "w+b");
828   if (!body)
829     {
830       err = gpg_error_from_syserror ();
831       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
832       goto leave;
833     }
834   /* It is fine to use 8 bit encoding because that is encrypted and
835    * only our client will see it.  */
836   es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
837             "Content-Transfer-Encoding: 8bit\n"
838             "\n",
839             body);
840
841   es_fprintf (body, ("type: confirmation-request\n"
842                      "sender: %s\n"
843                      "address: %s\n"
844                      "fingerprint: %s\n"
845                      "nonce: %s\n"),
846               from,
847               mbox,
848               ctx->fpr,
849               nonce);
850
851   es_rewind (body);
852   err = encrypt_stream (&bodyenc, body, keyfile);
853   if (err)
854     goto leave;
855   es_fclose (body);
856   body = NULL;
857
858
859   err = mime_maker_new (&mime, NULL);
860   if (err)
861     goto leave;
862   err = mime_maker_add_header (mime, "From", from);
863   if (err)
864     goto leave;
865   err = mime_maker_add_header (mime, "To", mbox);
866   if (err)
867     goto leave;
868   err = mime_maker_add_header (mime, "Subject", "Confirm your key publication");
869   if (err)
870     goto leave;
871   for (sl = opt.extra_headers; sl; sl = sl->next)
872     {
873       err = mime_maker_add_header (mime, sl->d, NULL);
874       if (err)
875         goto leave;
876     }
877
878   err = mime_maker_add_header (mime, "Content-Type",
879                                "multipart/encrypted; "
880                                "protocol=\"application/pgp-encrypted\"");
881   if (err)
882     goto leave;
883   err = mime_maker_add_container (mime, "multipart/encrypted");
884   if (err)
885     goto leave;
886
887   err = mime_maker_add_header (mime, "Content-Type",
888                                "application/pgp-encrypted");
889   if (err)
890     goto leave;
891   err = mime_maker_add_body (mime, "Version: 1\n");
892   if (err)
893     goto leave;
894   err = mime_maker_add_header (mime, "Content-Type",
895                                "application/octet-stream");
896   if (err)
897     goto leave;
898
899   err = mime_maker_add_stream (mime, &bodyenc);
900   if (err)
901     goto leave;
902
903   err = wks_send_mime (mime);
904
905  leave:
906   mime_maker_release (mime);
907   es_fclose (bodyenc);
908   es_fclose (body);
909   xfree (from_buffer);
910   return err;
911 }
912
913
914 /* Store the key given by KEY into the pending directory and send a
915  * confirmation requests.  */
916 static gpg_error_t
917 process_new_key (server_ctx_t ctx, estream_t key)
918 {
919   gpg_error_t err;
920   strlist_t sl;
921   const char *s;
922   char *dname = NULL;
923   char *nonce = NULL;
924   char *fname = NULL;
925
926   /* First figure out the user id from the key.  */
927   err = list_key (ctx, key);
928   if (err)
929     goto leave;
930   if (!ctx->fpr)
931     {
932       log_error ("error parsing key (no fingerprint)\n");
933       err = gpg_error (GPG_ERR_NO_PUBKEY);
934       goto leave;
935     }
936   log_info ("fingerprint: %s\n", ctx->fpr);
937   for (sl = ctx->mboxes; sl; sl = sl->next)
938     {
939       log_info ("  addr-spec: %s\n", sl->d);
940     }
941
942   /* Walk over all user ids and send confirmation requests for those
943    * we support.  */
944   for (sl = ctx->mboxes; sl; sl = sl->next)
945     {
946       s = strchr (sl->d, '@');
947       log_assert (s && s[1]);
948       xfree (dname);
949       dname = make_filename_try (opt.directory, s+1, NULL);
950       if (!dname)
951         {
952           err = gpg_error_from_syserror ();
953           goto leave;
954         }
955       /* Fixme: check for proper directory permissions.  */
956       if (access (dname, W_OK))
957         {
958           log_info ("skipping address '%s': Domain not configured\n", sl->d);
959           continue;
960         }
961       log_info ("storing address '%s'\n", sl->d);
962
963       xfree (nonce);
964       xfree (fname);
965       err = store_key_as_pending (dname, key, &nonce, &fname);
966       if (err)
967         goto leave;
968
969       err = send_confirmation_request (ctx, sl->d, nonce, fname);
970       if (err)
971         goto leave;
972     }
973
974  leave:
975   if (nonce)
976     wipememory (nonce, strlen (nonce));
977   xfree (nonce);
978   xfree (fname);
979   xfree (dname);
980   return err;
981 }
982
983
984 \f
985 /* Check that we have send a request with NONCE and publish the key.  */
986 static gpg_error_t
987 check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
988 {
989   gpg_error_t err;
990   char *fname = NULL;
991   char *fnewname = NULL;
992   estream_t key = NULL;
993   char *hash = NULL;
994   const char *domain;
995   const char *s;
996   strlist_t sl;
997   char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
998
999   /* FIXME: There is a bug in name-value.c which adds white space for
1000    * the last pair and thus we strip the nonce here until this has
1001    * been fixed.  */
1002   char *nonce2 = xstrdup (nonce);
1003   trim_trailing_spaces (nonce2);
1004   nonce = nonce2;
1005
1006
1007   domain = strchr (address, '@');
1008   log_assert (domain && domain[1]);
1009   domain++;
1010   fname = make_filename_try (opt.directory, domain, "pending", nonce, NULL);
1011   if (!fname)
1012     {
1013       err = gpg_error_from_syserror ();
1014       goto leave;
1015     }
1016
1017   /* Try to open the file with the key.  */
1018   key = es_fopen (fname, "rb");
1019   if (!key)
1020     {
1021       err = gpg_error_from_syserror ();
1022       if (gpg_err_code (err) == GPG_ERR_ENOENT)
1023         {
1024           log_info ("no pending request for '%s'\n", address);
1025           err = gpg_error (GPG_ERR_NOT_FOUND);
1026         }
1027       else
1028         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
1029       goto leave;
1030     }
1031
1032   /* We need to get the fingerprint from the key.  */
1033   err = list_key (ctx, key);
1034   if (err)
1035     goto leave;
1036   if (!ctx->fpr)
1037     {
1038       log_error ("error parsing key (no fingerprint)\n");
1039       err = gpg_error (GPG_ERR_NO_PUBKEY);
1040       goto leave;
1041     }
1042   log_info ("fingerprint: %s\n", ctx->fpr);
1043   for (sl = ctx->mboxes; sl; sl = sl->next)
1044     log_info ("  addr-spec: %s\n", sl->d);
1045
1046   /* Check that the key has 'address' as a user id.  We use
1047    * case-insensitive matching because the client is expected to
1048    * return the address verbatim.  */
1049   for (sl = ctx->mboxes; sl; sl = sl->next)
1050     if (!strcmp (sl->d, address))
1051       break;
1052   if (!sl)
1053     {
1054       log_error ("error publishing key: '%s' is not a user ID of %s\n",
1055                  address, ctx->fpr);
1056       err = gpg_error (GPG_ERR_NO_PUBKEY);
1057       goto leave;
1058     }
1059
1060
1061   /* Hash user ID and create filename.  */
1062   s = strchr (address, '@');
1063   log_assert (s);
1064   gcry_md_hash_buffer (GCRY_MD_SHA1, shaxbuf, address, s - address);
1065   hash = zb32_encode (shaxbuf, 8*20);
1066   if (!hash)
1067     {
1068       err = gpg_error_from_syserror ();
1069       goto leave;
1070     }
1071
1072   {
1073     /*FIXME: This is a hack to make installation easier.  It is better
1074      * to let --cron create the required directories.  */
1075     fnewname = make_filename_try (opt.directory, domain, "hu", NULL);
1076     if (!fnewname)
1077       {
1078         err = gpg_error_from_syserror ();
1079         goto leave;
1080     }
1081     if (!gnupg_mkdir (fnewname, "-rwxr-xr-x"))
1082       log_info ("directory '%s' created\n", fnewname);
1083     xfree (fnewname);
1084   }
1085   fnewname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
1086   if (!fnewname)
1087     {
1088       err = gpg_error_from_syserror ();
1089       goto leave;
1090     }
1091
1092   /* Publish.  */
1093   if (rename (fname, fnewname))
1094     {
1095       err = gpg_error_from_syserror ();
1096       log_error ("renaming '%s' to '%s' failed: %s\n",
1097                  fname, fnewname, gpg_strerror (err));
1098       goto leave;
1099     }
1100
1101   log_info ("key %s published for '%s'\n", ctx->fpr, address);
1102
1103
1104   /* Try to publish as DANE record if the DANE directory exists.  */
1105   xfree (fname);
1106   fname = fnewname;
1107   fnewname = make_filename_try (opt.directory, domain, "dane", NULL);
1108   if (!fnewname)
1109     {
1110       err = gpg_error_from_syserror ();
1111       goto leave;
1112     }
1113   if (!access (fnewname, W_OK))
1114     {
1115       /* Yes, we have a dane directory.  */
1116       s = strchr (address, '@');
1117       log_assert (s);
1118       gcry_md_hash_buffer (GCRY_MD_SHA256, shaxbuf, address, s - address);
1119       xfree (hash);
1120       hash = bin2hex (shaxbuf, 28, NULL);
1121       if (!hash)
1122         {
1123           err = gpg_error_from_syserror ();
1124           goto leave;
1125         }
1126       xfree (fnewname);
1127       fnewname = make_filename_try (opt.directory, domain, "dane", hash, NULL);
1128       if (!fnewname)
1129         {
1130           err = gpg_error_from_syserror ();
1131           goto leave;
1132         }
1133       err = copy_key_as_dane (fname, fnewname);
1134       if (err)
1135         goto leave;
1136       log_info ("key %s published for '%s' (DANE record)\n", ctx->fpr, address);
1137     }
1138
1139
1140  leave:
1141   es_fclose (key);
1142   xfree (hash);
1143   xfree (fnewname);
1144   xfree (fname);
1145   xfree (nonce2);
1146   return err;
1147 }
1148
1149
1150 /* Process a confirmation response in MSG.  */
1151 static gpg_error_t
1152 process_confirmation_response (server_ctx_t ctx, estream_t msg)
1153 {
1154   gpg_error_t err;
1155   nvc_t nvc;
1156   nve_t item;
1157   const char *value, *sender, *address, *nonce;
1158
1159   err = nvc_parse (&nvc, NULL, msg);
1160   if (err)
1161     {
1162       log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
1163       goto leave;
1164     }
1165
1166   if (opt.debug)
1167     {
1168       log_debug ("response follows:\n");
1169       nvc_write (nvc, log_get_stream ());
1170     }
1171
1172   /* Check that this is a confirmation response.  */
1173   if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
1174         && !strcmp (value, "confirmation-response")))
1175     {
1176       if (item && value)
1177         log_error ("received unexpected wks message '%s'\n", value);
1178       else
1179         log_error ("received invalid wks message: %s\n", "'type' missing");
1180       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1181       goto leave;
1182     }
1183
1184   /* Get the sender.  */
1185   if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
1186         && is_valid_mailbox (value)))
1187     {
1188       log_error ("received invalid wks message: %s\n",
1189                  "'sender' missing or invalid");
1190       err = gpg_error (GPG_ERR_INV_DATA);
1191       goto leave;
1192     }
1193   sender = value;
1194   (void)sender;
1195   /* FIXME: Do we really need the sender?.  */
1196
1197   /* Get the address.  */
1198   if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
1199         && is_valid_mailbox (value)))
1200     {
1201       log_error ("received invalid wks message: %s\n",
1202                  "'address' missing or invalid");
1203       err = gpg_error (GPG_ERR_INV_DATA);
1204       goto leave;
1205     }
1206   address = value;
1207
1208   /* Get the nonce.  */
1209   if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
1210         && strlen (value) > 16))
1211     {
1212       log_error ("received invalid wks message: %s\n",
1213                  "'nonce' missing or too short");
1214       err = gpg_error (GPG_ERR_INV_DATA);
1215       goto leave;
1216     }
1217   nonce = value;
1218
1219   err = check_and_publish (ctx, address, nonce);
1220
1221
1222  leave:
1223   nvc_release (nvc);
1224   return err;
1225 }
1226
1227
1228 \f
1229 /* Called from the MIME receiver to process the plain text data in MSG .  */
1230 static gpg_error_t
1231 command_receive_cb (void *opaque, const char *mediatype, estream_t msg)
1232 {
1233   gpg_error_t err;
1234   struct server_ctx_s ctx;
1235
1236   memset (&ctx, 0, sizeof ctx);
1237
1238   (void)opaque;
1239
1240   if (!strcmp (mediatype, "application/pgp-keys"))
1241     err = process_new_key (&ctx, msg);
1242   else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
1243     err = process_confirmation_response (&ctx, msg);
1244   else
1245     {
1246       log_info ("ignoring unexpected message of type '%s'\n", mediatype);
1247       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1248     }
1249
1250   xfree (ctx.fpr);
1251   free_strlist (ctx.mboxes);
1252
1253   return err;
1254 }