Improve some comments.
[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 <https://www.gnu.org/licenses/>.
18  */
19
20 /* The Web Key Service I-D defines an update protocol to store 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 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
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 /* The time we wait for a confirmation response.  */
48 #define PENDING_TTL (86400 * 3)  /* 3 days.  */
49
50
51 /* Constants to identify the commands and options. */
52 enum cmd_and_opt_values
53   {
54     aNull = 0,
55
56     oQuiet      = 'q',
57     oVerbose    = 'v',
58     oOutput     = 'o',
59
60     oDebug      = 500,
61
62     aReceive,
63     aCron,
64     aListDomains,
65
66     oGpgProgram,
67     oSend,
68     oFrom,
69     oHeader,
70
71     oDummy
72   };
73
74
75 /* The list of commands and options. */
76 static ARGPARSE_OPTS opts[] = {
77   ARGPARSE_group (300, ("@Commands:\n ")),
78
79   ARGPARSE_c (aReceive,   "receive",
80               ("receive a submission or confirmation")),
81   ARGPARSE_c (aCron,      "cron",
82               ("run regular jobs")),
83   ARGPARSE_c (aListDomains, "list-domains",
84               ("list configured domains")),
85
86   ARGPARSE_group (301, ("@\nOptions:\n ")),
87
88   ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
89   ARGPARSE_s_n (oQuiet, "quiet",  ("be somewhat more quiet")),
90   ARGPARSE_s_s (oDebug, "debug", "@"),
91   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
92   ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
93   ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
94   ARGPARSE_s_s (oFrom, "from", "|ADDR|use ADDR as the default sender"),
95   ARGPARSE_s_s (oHeader, "header" ,
96                 "|NAME=VALUE|add \"NAME: VALUE\" as header to all mails"),
97
98   ARGPARSE_end ()
99 };
100
101
102 /* The list of supported debug flags.  */
103 static struct debug_flags_s debug_flags [] =
104   {
105     { DBG_MIME_VALUE   , "mime"    },
106     { DBG_PARSER_VALUE , "parser"  },
107     { DBG_CRYPTO_VALUE , "crypto"  },
108     { DBG_MEMORY_VALUE , "memory"  },
109     { DBG_MEMSTAT_VALUE, "memstat" },
110     { DBG_IPC_VALUE    , "ipc"     },
111     { DBG_EXTPROG_VALUE, "extprog" },
112     { 0, NULL }
113   };
114
115
116 /* State for processing a message.  */
117 struct server_ctx_s
118 {
119   char *fpr;
120   strlist_t mboxes;  /* List of addr-specs taken from the UIDs.  */
121   unsigned int draft_version_2:1; /* Client supports the draft 2.  */
122 };
123 typedef struct server_ctx_s *server_ctx_t;
124
125 /* Prototypes.  */
126 static gpg_error_t get_domain_list (strlist_t *r_list);
127
128 static gpg_error_t command_receive_cb (void *opaque,
129                                        const char *mediatype, estream_t fp,
130                                        unsigned int flags);
131 static gpg_error_t command_list_domains (void);
132 static gpg_error_t command_cron (void);
133
134
135 \f
136 /* Print usage information and and provide strings for help. */
137 static const char *
138 my_strusage( int level )
139 {
140   const char *p;
141
142   switch (level)
143     {
144     case 11: p = "gpg-wks-server (@GNUPG@)";
145       break;
146     case 13: p = VERSION; break;
147     case 17: p = PRINTABLE_OS_NAME; break;
148     case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
149
150     case 1:
151     case 40:
152       p = ("Usage: gpg-wks-server command [options] (-h for help)");
153       break;
154     case 41:
155       p = ("Syntax: gpg-wks-server command [options]\n"
156            "Server for the Web Key Service protocol\n");
157       break;
158
159     default: p = NULL; break;
160     }
161   return p;
162 }
163
164
165 static void
166 wrong_args (const char *text)
167 {
168   es_fprintf (es_stderr, "usage: %s [options] %s\n", strusage (11), text);
169   exit (2);
170 }
171
172
173 \f
174 /* Command line parsing.  */
175 static enum cmd_and_opt_values
176 parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
177 {
178   enum cmd_and_opt_values cmd = 0;
179   int no_more_options = 0;
180
181   while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
182     {
183       switch (pargs->r_opt)
184         {
185         case oQuiet:     opt.quiet = 1; break;
186         case oVerbose:   opt.verbose++; break;
187         case oDebug:
188           if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
189             {
190               pargs->r_opt = ARGPARSE_INVALID_ARG;
191               pargs->err = ARGPARSE_PRINT_ERROR;
192             }
193           break;
194
195         case oGpgProgram:
196           opt.gpg_program = pargs->r.ret_str;
197           break;
198         case oFrom:
199           opt.default_from = pargs->r.ret_str;
200           break;
201         case oHeader:
202           append_to_strlist (&opt.extra_headers, pargs->r.ret_str);
203           break;
204         case oSend:
205           opt.use_sendmail = 1;
206           break;
207         case oOutput:
208           opt.output = pargs->r.ret_str;
209           break;
210
211         case aReceive:
212         case aCron:
213         case aListDomains:
214           cmd = pargs->r_opt;
215           break;
216
217         default: pargs->err = 2; break;
218         }
219     }
220
221   return cmd;
222 }
223
224
225 \f
226 /* gpg-wks-server main. */
227 int
228 main (int argc, char **argv)
229 {
230   gpg_error_t err;
231   ARGPARSE_ARGS pargs;
232   enum cmd_and_opt_values cmd;
233
234   gnupg_reopen_std ("gpg-wks-server");
235   set_strusage (my_strusage);
236   log_set_prefix ("gpg-wks-server", GPGRT_LOG_WITH_PREFIX);
237
238   /* Make sure that our subsystems are ready.  */
239   init_common_subsystems (&argc, &argv);
240
241   /* Parse the command line. */
242   pargs.argc  = &argc;
243   pargs.argv  = &argv;
244   pargs.flags = ARGPARSE_FLAG_KEEP;
245   cmd = parse_arguments (&pargs, opts);
246
247   if (log_get_errorcount (0))
248     exit (2);
249
250   /* Print a warning if an argument looks like an option.  */
251   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
252     {
253       int i;
254
255       for (i=0; i < argc; i++)
256         if (argv[i][0] == '-' && argv[i][1] == '-')
257           log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
258     }
259
260   /* Set defaults for non given options.  */
261   if (!opt.gpg_program)
262     opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
263
264   if (!opt.directory)
265     opt.directory = "/var/lib/gnupg/wks";
266
267   /* Check for syntax errors in the --header option to avoid later
268    * error messages with a not easy to find cause */
269   if (opt.extra_headers)
270     {
271       strlist_t sl;
272
273       for (sl = opt.extra_headers; sl; sl = sl->next)
274         {
275           err = mime_maker_add_header (NULL, sl->d, NULL);
276           if (err)
277             log_error ("syntax error in \"--header %s\": %s\n",
278                        sl->d, gpg_strerror (err));
279         }
280     }
281
282   if (log_get_errorcount (0))
283     exit (2);
284
285
286   /* Check that we have a working directory.  */
287 #if defined(HAVE_STAT)
288   {
289     struct stat sb;
290
291     if (stat (opt.directory, &sb))
292       {
293         err = gpg_error_from_syserror ();
294         log_error ("error accessing directory '%s': %s\n",
295                    opt.directory, gpg_strerror (err));
296         exit (2);
297       }
298     if (!S_ISDIR(sb.st_mode))
299       {
300         log_error ("error accessing directory '%s': %s\n",
301                    opt.directory, "not a directory");
302         exit (2);
303       }
304     if (sb.st_uid != getuid())
305       {
306         log_error ("directory '%s' not owned by user\n", opt.directory);
307         exit (2);
308       }
309     if ((sb.st_mode & (S_IROTH|S_IWOTH)))
310       {
311         log_error ("directory '%s' has too relaxed permissions\n",
312                    opt.directory);
313         exit (2);
314       }
315   }
316 #else /*!HAVE_STAT*/
317   log_fatal ("program build w/o stat() call\n");
318 #endif /*!HAVE_STAT*/
319
320   /* Run the selected command.  */
321   switch (cmd)
322     {
323     case aReceive:
324       if (argc)
325         wrong_args ("--receive");
326       err = wks_receive (es_stdin, command_receive_cb, NULL);
327       break;
328
329     case aCron:
330       if (argc)
331         wrong_args ("--cron");
332       err = command_cron ();
333       break;
334
335     case aListDomains:
336       err = command_list_domains ();
337       break;
338
339     default:
340       usage (1);
341       err = gpg_error (GPG_ERR_BUG);
342       break;
343     }
344
345   if (err)
346     log_error ("command failed: %s\n", gpg_strerror (err));
347   return log_get_errorcount (0)? 1:0;
348 }
349
350
351 \f
352 static void
353 list_key_status_cb (void *opaque, const char *keyword, char *args)
354 {
355   server_ctx_t ctx = opaque;
356   (void)ctx;
357   if (DBG_CRYPTO)
358     log_debug ("gpg status: %s %s\n", keyword, args);
359 }
360
361
362 static gpg_error_t
363 list_key (server_ctx_t ctx, estream_t key)
364 {
365   gpg_error_t err;
366   ccparray_t ccp;
367   const char **argv;
368   estream_t listing;
369   char *line = NULL;
370   size_t length_of_line = 0;
371   size_t  maxlen;
372   ssize_t len;
373   char **fields = NULL;
374   int nfields;
375   int lnr;
376   char *mbox = NULL;
377
378   /* We store our results in the context - clear it first.  */
379   xfree (ctx->fpr);
380   ctx->fpr = NULL;
381   free_strlist (ctx->mboxes);
382   ctx->mboxes = NULL;
383
384   /* Open a memory stream.  */
385   listing = es_fopenmem (0, "w+b");
386   if (!listing)
387     {
388       err = gpg_error_from_syserror ();
389       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
390       return err;
391     }
392
393   ccparray_init (&ccp, 0);
394
395   ccparray_put (&ccp, "--no-options");
396   if (!opt.verbose)
397     ccparray_put (&ccp, "--quiet");
398   else if (opt.verbose > 1)
399     ccparray_put (&ccp, "--verbose");
400   ccparray_put (&ccp, "--batch");
401   ccparray_put (&ccp, "--status-fd=2");
402   ccparray_put (&ccp, "--always-trust");
403   ccparray_put (&ccp, "--with-colons");
404   ccparray_put (&ccp, "--dry-run");
405   ccparray_put (&ccp, "--import-options=import-minimal,import-show");
406   ccparray_put (&ccp, "--import");
407
408   ccparray_put (&ccp, NULL);
409   argv = ccparray_get (&ccp, NULL);
410   if (!argv)
411     {
412       err = gpg_error_from_syserror ();
413       goto leave;
414     }
415   err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
416                                 NULL, listing,
417                                 list_key_status_cb, ctx);
418   if (err)
419     {
420       log_error ("import failed: %s\n", gpg_strerror (err));
421       goto leave;
422     }
423
424   es_rewind (listing);
425   lnr = 0;
426   maxlen = 2048; /* Set limit.  */
427   while ((len = es_read_line (listing, &line, &length_of_line, &maxlen)) > 0)
428     {
429       lnr++;
430       if (!maxlen)
431         {
432           log_error ("received line too long\n");
433           err = gpg_error (GPG_ERR_LINE_TOO_LONG);
434           goto leave;
435         }
436       /* Strip newline and carriage return, if present.  */
437       while (len > 0
438              && (line[len - 1] == '\n' || line[len - 1] == '\r'))
439         line[--len] = '\0';
440       /* log_debug ("line '%s'\n", line); */
441
442       xfree (fields);
443       fields = strtokenize (line, ":");
444       if (!fields)
445         {
446           err = gpg_error_from_syserror ();
447           log_error ("strtokenize failed: %s\n", gpg_strerror (err));
448           goto leave;
449         }
450       for (nfields = 0; fields[nfields]; nfields++)
451         ;
452       if (!nfields)
453         {
454           err = gpg_error (GPG_ERR_INV_ENGINE);
455           goto leave;
456         }
457       if (!strcmp (fields[0], "sec"))
458         {
459           /* gpg may return "sec" as the first record - but we do not
460            * accept secret keys.  */
461           err = gpg_error (GPG_ERR_NO_PUBKEY);
462           goto leave;
463         }
464       if (lnr == 1 && strcmp (fields[0], "pub"))
465         {
466           /* First record is not a public key.  */
467           err = gpg_error (GPG_ERR_INV_ENGINE);
468           goto leave;
469         }
470       if (lnr > 1 && !strcmp (fields[0], "pub"))
471         {
472           /* More than one public key.  */
473           err = gpg_error (GPG_ERR_TOO_MANY);
474           goto leave;
475         }
476       if (!strcmp (fields[0], "sub") || !strcmp (fields[0], "ssb"))
477         break; /* We can stop parsing here.  */
478
479       if (!strcmp (fields[0], "fpr") && nfields > 9 && !ctx->fpr)
480         {
481           ctx->fpr = xtrystrdup (fields[9]);
482           if (!ctx->fpr)
483             {
484               err = gpg_error_from_syserror ();
485               goto leave;
486             }
487         }
488       else if (!strcmp (fields[0], "uid") && nfields > 9)
489         {
490           /* Fixme: Unescape fields[9] */
491           xfree (mbox);
492           mbox = mailbox_from_userid (fields[9]);
493           if (mbox && !append_to_strlist_try (&ctx->mboxes, mbox))
494             {
495               err = gpg_error_from_syserror ();
496               goto leave;
497             }
498         }
499     }
500   if (len < 0 || es_ferror (listing))
501     log_error ("error reading memory stream\n");
502
503  leave:
504   xfree (mbox);
505   xfree (fields);
506   es_free (line);
507   xfree (argv);
508   es_fclose (listing);
509   return err;
510 }
511
512
513 /* Take the key in KEYFILE and write it to OUTFILE in binary encoding.
514  * If ADDRSPEC is given only matching user IDs are included in the
515  * output.  */
516 static gpg_error_t
517 copy_key_as_binary (const char *keyfile, const char *outfile,
518                     const char *addrspec)
519 {
520   gpg_error_t err;
521   ccparray_t ccp;
522   const char **argv = NULL;
523   char *filterexp = NULL;
524
525   if (addrspec)
526     {
527       filterexp = es_bsprintf ("keep-uid=mbox = %s", addrspec);
528       if (!filterexp)
529         {
530           err = gpg_error_from_syserror ();
531           log_error ("error allocating memory buffer: %s\n",
532                      gpg_strerror (err));
533           goto leave;
534         }
535     }
536
537   ccparray_init (&ccp, 0);
538
539   ccparray_put (&ccp, "--no-options");
540   if (!opt.verbose)
541     ccparray_put (&ccp, "--quiet");
542   else if (opt.verbose > 1)
543     ccparray_put (&ccp, "--verbose");
544   ccparray_put (&ccp, "--batch");
545   ccparray_put (&ccp, "--yes");
546   ccparray_put (&ccp, "--always-trust");
547   ccparray_put (&ccp, "--no-keyring");
548   ccparray_put (&ccp, "--output");
549   ccparray_put (&ccp, outfile);
550   ccparray_put (&ccp, "--import-options=import-export");
551   if (filterexp)
552     {
553       ccparray_put (&ccp, "--import-filter");
554       ccparray_put (&ccp, filterexp);
555     }
556   ccparray_put (&ccp, "--import");
557   ccparray_put (&ccp, "--");
558   ccparray_put (&ccp, keyfile);
559
560   ccparray_put (&ccp, NULL);
561   argv = ccparray_get (&ccp, NULL);
562   if (!argv)
563     {
564       err = gpg_error_from_syserror ();
565       goto leave;
566     }
567   err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
568                                 NULL, NULL, NULL, NULL);
569   if (err)
570     {
571       log_error ("%s failed: %s\n", __func__, gpg_strerror (err));
572       goto leave;
573     }
574
575  leave:
576   xfree (filterexp);
577   xfree (argv);
578   return err;
579 }
580
581
582 /* Take the key in KEYFILE and write it to DANEFILE using the DANE
583  * output format. */
584 static gpg_error_t
585 copy_key_as_dane (const char *keyfile, const char *danefile)
586 {
587   gpg_error_t err;
588   ccparray_t ccp;
589   const char **argv;
590
591   ccparray_init (&ccp, 0);
592
593   ccparray_put (&ccp, "--no-options");
594   if (!opt.verbose)
595     ccparray_put (&ccp, "--quiet");
596   else if (opt.verbose > 1)
597     ccparray_put (&ccp, "--verbose");
598   ccparray_put (&ccp, "--batch");
599   ccparray_put (&ccp, "--yes");
600   ccparray_put (&ccp, "--always-trust");
601   ccparray_put (&ccp, "--no-keyring");
602   ccparray_put (&ccp, "--output");
603   ccparray_put (&ccp, danefile);
604   ccparray_put (&ccp, "--export-options=export-dane");
605   ccparray_put (&ccp, "--import-options=import-export");
606   ccparray_put (&ccp, "--import");
607   ccparray_put (&ccp, "--");
608   ccparray_put (&ccp, keyfile);
609
610   ccparray_put (&ccp, NULL);
611   argv = ccparray_get (&ccp, NULL);
612   if (!argv)
613     {
614       err = gpg_error_from_syserror ();
615       goto leave;
616     }
617   err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
618                                 NULL, NULL, NULL, NULL);
619   if (err)
620     {
621       log_error ("%s failed: %s\n", __func__, gpg_strerror (err));
622       goto leave;
623     }
624
625  leave:
626   xfree (argv);
627   return err;
628 }
629
630
631 static void
632 encrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
633 {
634   (void)opaque;
635
636   if (DBG_CRYPTO)
637     log_debug ("gpg status: %s %s\n", keyword, args);
638 }
639
640
641 /* Encrypt the INPUT stream to a new stream which is stored at success
642  * at R_OUTPUT.  Encryption is done for the key in file KEYFIL.  */
643 static gpg_error_t
644 encrypt_stream (estream_t *r_output, estream_t input, const char *keyfile)
645 {
646   gpg_error_t err;
647   ccparray_t ccp;
648   const char **argv;
649   estream_t output;
650
651   *r_output = NULL;
652
653   output = es_fopenmem (0, "w+b");
654   if (!output)
655     {
656       err = gpg_error_from_syserror ();
657       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
658       return err;
659     }
660
661   ccparray_init (&ccp, 0);
662
663   ccparray_put (&ccp, "--no-options");
664   if (!opt.verbose)
665     ccparray_put (&ccp, "--quiet");
666   else if (opt.verbose > 1)
667     ccparray_put (&ccp, "--verbose");
668   ccparray_put (&ccp, "--batch");
669   ccparray_put (&ccp, "--status-fd=2");
670   ccparray_put (&ccp, "--always-trust");
671   ccparray_put (&ccp, "--no-keyring");
672   ccparray_put (&ccp, "--armor");
673   ccparray_put (&ccp, "--recipient-file");
674   ccparray_put (&ccp, keyfile);
675   ccparray_put (&ccp, "--encrypt");
676   ccparray_put (&ccp, "--");
677
678   ccparray_put (&ccp, NULL);
679   argv = ccparray_get (&ccp, NULL);
680   if (!argv)
681     {
682       err = gpg_error_from_syserror ();
683       goto leave;
684     }
685   err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
686                                 NULL, output,
687                                 encrypt_stream_status_cb, NULL);
688   if (err)
689     {
690       log_error ("encryption failed: %s\n", gpg_strerror (err));
691       goto leave;
692     }
693
694   es_rewind (output);
695   *r_output = output;
696   output = NULL;
697
698  leave:
699   es_fclose (output);
700   xfree (argv);
701   return err;
702 }
703
704
705 static void
706 sign_stream_status_cb (void *opaque, const char *keyword, char *args)
707 {
708   (void)opaque;
709
710   if (DBG_CRYPTO)
711     log_debug ("gpg status: %s %s\n", keyword, args);
712 }
713
714 /* Sign the INPUT stream to a new stream which is stored at success at
715  * R_OUTPUT.  A detached signature is created using the key specified
716  * by USERID.  */
717 static gpg_error_t
718 sign_stream (estream_t *r_output, estream_t input, const char *userid)
719 {
720   gpg_error_t err;
721   ccparray_t ccp;
722   const char **argv;
723   estream_t output;
724
725   *r_output = NULL;
726
727   output = es_fopenmem (0, "w+b");
728   if (!output)
729     {
730       err = gpg_error_from_syserror ();
731       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
732       return err;
733     }
734
735   ccparray_init (&ccp, 0);
736
737   ccparray_put (&ccp, "--no-options");
738   if (!opt.verbose)
739     ccparray_put (&ccp, "--quiet");
740   else if (opt.verbose > 1)
741     ccparray_put (&ccp, "--verbose");
742   ccparray_put (&ccp, "--batch");
743   ccparray_put (&ccp, "--status-fd=2");
744   ccparray_put (&ccp, "--armor");
745   ccparray_put (&ccp, "--local-user");
746   ccparray_put (&ccp, userid);
747   ccparray_put (&ccp, "--detach-sign");
748   ccparray_put (&ccp, "--");
749
750   ccparray_put (&ccp, NULL);
751   argv = ccparray_get (&ccp, NULL);
752   if (!argv)
753     {
754       err = gpg_error_from_syserror ();
755       goto leave;
756     }
757   err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
758                                 NULL, output,
759                                 sign_stream_status_cb, NULL);
760   if (err)
761     {
762       log_error ("signing failed: %s\n", gpg_strerror (err));
763       goto leave;
764     }
765
766   es_rewind (output);
767   *r_output = output;
768   output = NULL;
769
770  leave:
771   es_fclose (output);
772   xfree (argv);
773   return err;
774 }
775
776
777 /* Get the submission address for address MBOX.  Caller must free the
778  * value.  If no address can be found NULL is returned.  */
779 static char *
780 get_submission_address (const char *mbox)
781 {
782   gpg_error_t err;
783   const char *domain;
784   char *fname, *line, *p;
785   size_t n;
786   estream_t fp;
787
788   domain = strchr (mbox, '@');
789   if (!domain)
790     return NULL;
791   domain++;
792
793   fname = make_filename_try (opt.directory, domain, "submission-address", NULL);
794   if (!fname)
795     {
796       err = gpg_error_from_syserror ();
797       log_error ("make_filename failed in %s: %s\n",
798                  __func__, gpg_strerror (err));
799       return NULL;
800     }
801
802   fp = es_fopen (fname, "r");
803   if (!fp)
804     {
805       err = gpg_error_from_syserror ();
806       if (gpg_err_code (err) == GPG_ERR_ENOENT)
807         log_info ("Note: no specific submission address configured"
808                   " for domain '%s'\n", domain);
809       else
810         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
811       xfree (fname);
812       return NULL;
813     }
814
815   line = NULL;
816   n = 0;
817   if (es_getline (&line, &n, fp) < 0)
818     {
819       err = gpg_error_from_syserror ();
820       log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
821       xfree (line);
822       es_fclose (fp);
823       xfree (fname);
824       return NULL;
825     }
826   es_fclose (fp);
827   xfree (fname);
828
829   p = strchr (line, '\n');
830   if (p)
831     *p = 0;
832   trim_spaces (line);
833   if (!is_valid_mailbox (line))
834     {
835       log_error ("invalid submission address for domain '%s' detected\n",
836                  domain);
837       xfree (line);
838       return NULL;
839     }
840
841   return line;
842 }
843
844
845 /* Get the policy flags for address MBOX and store them in POLICY.  */
846 static gpg_error_t
847 get_policy_flags (policy_flags_t policy, const char *mbox)
848 {
849   gpg_error_t err;
850   const char *domain;
851   char *fname;
852   estream_t fp;
853
854   memset (policy, 0, sizeof *policy);
855
856   domain = strchr (mbox, '@');
857   if (!domain)
858     return gpg_error (GPG_ERR_INV_USER_ID);
859   domain++;
860
861   fname = make_filename_try (opt.directory, domain, "policy", NULL);
862   if (!fname)
863     {
864       err = gpg_error_from_syserror ();
865       log_error ("make_filename failed in %s: %s\n",
866                  __func__, gpg_strerror (err));
867       return err;
868     }
869
870   fp = es_fopen (fname, "r");
871   if (!fp)
872     {
873       err = gpg_error_from_syserror ();
874       if (gpg_err_code (err) == GPG_ERR_ENOENT)
875         err = 0;
876       else
877         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
878       xfree (fname);
879       return err;
880     }
881
882   err = wks_parse_policy (policy, fp, 0);
883   es_fclose (fp);
884   xfree (fname);
885   return err;
886 }
887
888
889 /* We store the key under the name of the nonce we will then send to
890  * the user.  On success the nonce is stored at R_NONCE and the file
891  * name at R_FNAME.  */
892 static gpg_error_t
893 store_key_as_pending (const char *dir, estream_t key,
894                       char **r_nonce, char **r_fname)
895 {
896   gpg_error_t err;
897   char *dname = NULL;
898   char *fname = NULL;
899   char *nonce = NULL;
900   estream_t outfp = NULL;
901   char buffer[1024];
902   size_t nbytes, nwritten;
903
904   *r_nonce = NULL;
905   *r_fname = NULL;
906
907   dname = make_filename_try (dir, "pending", NULL);
908   if (!dname)
909     {
910       err = gpg_error_from_syserror ();
911       goto leave;
912     }
913
914   /* Create the nonce.  We use 20 bytes so that we don't waste a
915    * character in our zBase-32 encoding.  Using the gcrypt's nonce
916    * function is faster than using the strong random function; this is
917    * Good Enough for our purpose.  */
918   log_assert (sizeof buffer > 20);
919   gcry_create_nonce (buffer, 20);
920   nonce = zb32_encode (buffer, 8 * 20);
921   memset (buffer, 0, 20);  /* Not actually needed but it does not harm. */
922   if (!nonce)
923     {
924       err = gpg_error_from_syserror ();
925       goto leave;
926     }
927
928   fname = strconcat (dname, "/", nonce, NULL);
929   if (!fname)
930     {
931       err = gpg_error_from_syserror ();
932       goto leave;
933     }
934
935   /* With 128 bits of random we can expect that no other file exists
936    * under this name.  We use "x" to detect internal errors.  */
937   outfp = es_fopen (fname, "wbx,mode=-rw");
938   if (!outfp)
939     {
940       err = gpg_error_from_syserror ();
941       log_error ("error creating '%s': %s\n", fname, gpg_strerror (err));
942       goto leave;
943     }
944   es_rewind (key);
945   for (;;)
946     {
947       if (es_read (key, buffer, sizeof buffer, &nbytes))
948         {
949           err = gpg_error_from_syserror ();
950           log_error ("error reading '%s': %s\n",
951                      es_fname_get (key), gpg_strerror (err));
952           break;
953         }
954
955       if (!nbytes)
956         {
957           err = 0;
958           goto leave; /* Ready.  */
959         }
960       if (es_write (outfp, buffer, nbytes, &nwritten))
961         {
962           err = gpg_error_from_syserror ();
963           log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
964           goto leave;
965         }
966       else if (nwritten != nbytes)
967         {
968           err = gpg_error (GPG_ERR_EIO);
969           log_error ("error writing '%s': %s\n", fname, "short write");
970           goto leave;
971         }
972     }
973
974  leave:
975   if (err)
976     {
977       es_fclose (outfp);
978       gnupg_remove (fname);
979     }
980   else if (es_fclose (outfp))
981     {
982       err = gpg_error_from_syserror ();
983       log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
984     }
985
986   if (!err)
987     {
988       *r_nonce = nonce;
989       *r_fname = fname;
990     }
991   else
992     {
993       xfree (nonce);
994       xfree (fname);
995     }
996   xfree (dname);
997   return err;
998 }
999
1000
1001 /* Send a confirmation request.  DIR is the directory used for the
1002  * address MBOX.  NONCE is the nonce we want to see in the response to
1003  * this mail.  FNAME the name of the file with the key.  */
1004 static gpg_error_t
1005 send_confirmation_request (server_ctx_t ctx,
1006                            const char *mbox, const char *nonce,
1007                            const char *keyfile)
1008 {
1009   gpg_error_t err;
1010   estream_t body = NULL;
1011   estream_t bodyenc = NULL;
1012   estream_t signeddata = NULL;
1013   estream_t signature = NULL;
1014   mime_maker_t mime = NULL;
1015   char *from_buffer = NULL;
1016   const char *from;
1017   strlist_t sl;
1018
1019   from = from_buffer = get_submission_address (mbox);
1020   if (!from)
1021     {
1022       from = opt.default_from;
1023       if (!from)
1024         {
1025           log_error ("no sender address found for '%s'\n", mbox);
1026           err = gpg_error (GPG_ERR_CONFIGURATION);
1027           goto leave;
1028         }
1029       log_info ("Note: using default sender address '%s'\n", from);
1030     }
1031
1032   body = es_fopenmem (0, "w+b");
1033   if (!body)
1034     {
1035       err = gpg_error_from_syserror ();
1036       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
1037       goto leave;
1038     }
1039
1040   if (!ctx->draft_version_2)
1041     {
1042       /* It is fine to use 8 bit encoding because that is encrypted and
1043        * only our client will see it.  */
1044       es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
1045                 "Content-Transfer-Encoding: 8bit\n"
1046                 "\n",
1047                 body);
1048     }
1049
1050   es_fprintf (body, ("type: confirmation-request\n"
1051                      "sender: %s\n"
1052                      "address: %s\n"
1053                      "fingerprint: %s\n"
1054                      "nonce: %s\n"),
1055               from,
1056               mbox,
1057               ctx->fpr,
1058               nonce);
1059
1060   es_rewind (body);
1061   err = encrypt_stream (&bodyenc, body, keyfile);
1062   if (err)
1063     goto leave;
1064   es_fclose (body);
1065   body = NULL;
1066
1067
1068   err = mime_maker_new (&mime, NULL);
1069   if (err)
1070     goto leave;
1071   err = mime_maker_add_header (mime, "From", from);
1072   if (err)
1073     goto leave;
1074   err = mime_maker_add_header (mime, "To", mbox);
1075   if (err)
1076     goto leave;
1077   err = mime_maker_add_header (mime, "Subject", "Confirm your key publication");
1078   if (err)
1079     goto leave;
1080   for (sl = opt.extra_headers; sl; sl = sl->next)
1081     {
1082       err = mime_maker_add_header (mime, sl->d, NULL);
1083       if (err)
1084         goto leave;
1085     }
1086
1087   if (!ctx->draft_version_2)
1088     {
1089       err = mime_maker_add_header (mime, "Content-Type",
1090                                    "multipart/encrypted; "
1091                                    "protocol=\"application/pgp-encrypted\"");
1092       if (err)
1093         goto leave;
1094       err = mime_maker_add_container (mime);
1095       if (err)
1096         goto leave;
1097
1098       err = mime_maker_add_header (mime, "Content-Type",
1099                                    "application/pgp-encrypted");
1100       if (err)
1101         goto leave;
1102       err = mime_maker_add_body (mime, "Version: 1\n");
1103       if (err)
1104         goto leave;
1105       err = mime_maker_add_header (mime, "Content-Type",
1106                                    "application/octet-stream");
1107       if (err)
1108         goto leave;
1109
1110       err = mime_maker_add_stream (mime, &bodyenc);
1111       if (err)
1112         goto leave;
1113
1114     }
1115   else
1116     {
1117       unsigned int partid;
1118
1119       /* FIXME: Add micalg.  */
1120       err = mime_maker_add_header (mime, "Content-Type",
1121                                    "multipart/signed; "
1122                                    "protocol=\"application/pgp-signature\"");
1123       if (err)
1124         goto leave;
1125       err = mime_maker_add_container (mime);
1126       if (err)
1127         goto leave;
1128
1129       err = mime_maker_add_header (mime, "Content-Type", "multipart/mixed");
1130       if (err)
1131         goto leave;
1132
1133       err = mime_maker_add_container (mime);
1134       if (err)
1135         goto leave;
1136       partid = mime_maker_get_partid (mime);
1137
1138       err = mime_maker_add_header (mime, "Content-Type", "text/plain");
1139       if (err)
1140         goto leave;
1141
1142       err = mime_maker_add_body
1143         (mime,
1144          "This message has been send to confirm your request\n"
1145          "to publish your key.  If you did not request a key\n"
1146          "publication, simply ignore this message.\n"
1147          "\n"
1148          "Most mail software can handle this kind of message\n"
1149          "automatically and thus you would not have seen this\n"
1150          "message.  It seems that your client does not fully\n"
1151          "support this service.  The web page\n"
1152          "\n"
1153          "       https://gnupg.org/faq/wkd.html\n"
1154          "\n"
1155          "explains how you can process this message anyway in\n"
1156          "a few manual steps.\n");
1157       if (err)
1158         goto leave;
1159
1160       err = mime_maker_add_header (mime, "Content-Type",
1161                                    "application/vnd.gnupg.wks");
1162       if (err)
1163         goto leave;
1164
1165       err = mime_maker_add_stream (mime, &bodyenc);
1166       if (err)
1167         goto leave;
1168
1169       err = mime_maker_end_container (mime);
1170       if (err)
1171         goto leave;
1172
1173       mime_maker_dump_tree (mime);
1174       err = mime_maker_get_part (mime, partid, &signeddata);
1175       if (err)
1176         goto leave;
1177
1178       err = sign_stream (&signature, signeddata, from);
1179       if (err)
1180         goto leave;
1181
1182       err = mime_maker_add_header (mime, "Content-Type",
1183                                    "application/pgp-signature");
1184       if (err)
1185         goto leave;
1186
1187       err = mime_maker_add_stream (mime, &signature);
1188       if (err)
1189         goto leave;
1190     }
1191
1192   err = wks_send_mime (mime);
1193
1194  leave:
1195   mime_maker_release (mime);
1196   es_fclose (signature);
1197   es_fclose (signeddata);
1198   es_fclose (bodyenc);
1199   es_fclose (body);
1200   xfree (from_buffer);
1201   return err;
1202 }
1203
1204
1205 /* Store the key given by KEY into the pending directory and send a
1206  * confirmation requests.  */
1207 static gpg_error_t
1208 process_new_key (server_ctx_t ctx, estream_t key)
1209 {
1210   gpg_error_t err;
1211   strlist_t sl;
1212   const char *s;
1213   char *dname = NULL;
1214   char *nonce = NULL;
1215   char *fname = NULL;
1216   struct policy_flags_s policybuf;
1217
1218   /* First figure out the user id from the key.  */
1219   err = list_key (ctx, key);
1220   if (err)
1221     goto leave;
1222   if (!ctx->fpr)
1223     {
1224       log_error ("error parsing key (no fingerprint)\n");
1225       err = gpg_error (GPG_ERR_NO_PUBKEY);
1226       goto leave;
1227     }
1228   log_info ("fingerprint: %s\n", ctx->fpr);
1229   for (sl = ctx->mboxes; sl; sl = sl->next)
1230     {
1231       log_info ("  addr-spec: %s\n", sl->d);
1232     }
1233
1234   /* Walk over all user ids and send confirmation requests for those
1235    * we support.  */
1236   for (sl = ctx->mboxes; sl; sl = sl->next)
1237     {
1238       s = strchr (sl->d, '@');
1239       log_assert (s && s[1]);
1240       xfree (dname);
1241       dname = make_filename_try (opt.directory, s+1, NULL);
1242       if (!dname)
1243         {
1244           err = gpg_error_from_syserror ();
1245           goto leave;
1246         }
1247
1248       if (access (dname, W_OK))
1249         {
1250           log_info ("skipping address '%s': Domain not configured\n", sl->d);
1251           continue;
1252         }
1253       if (get_policy_flags (&policybuf, sl->d))
1254         {
1255           log_info ("skipping address '%s': Bad policy flags\n", sl->d);
1256           continue;
1257         }
1258
1259       if (policybuf.auth_submit)
1260         {
1261           /* Bypass the confirmation stuff and publish the the key as is.  */
1262           log_info ("publishing address '%s'\n", sl->d);
1263           /* FIXME: We need to make sure that we do this only for the
1264            * address in the mail.  */
1265           log_debug ("auth-submit not yet working!\n");
1266         }
1267       else
1268         {
1269           log_info ("storing address '%s'\n", sl->d);
1270
1271           xfree (nonce);
1272           xfree (fname);
1273           err = store_key_as_pending (dname, key, &nonce, &fname);
1274           if (err)
1275             goto leave;
1276
1277           err = send_confirmation_request (ctx, sl->d, nonce, fname);
1278           if (err)
1279             goto leave;
1280         }
1281     }
1282
1283  leave:
1284   if (nonce)
1285     wipememory (nonce, strlen (nonce));
1286   xfree (nonce);
1287   xfree (fname);
1288   xfree (dname);
1289   return err;
1290 }
1291
1292
1293 \f
1294 /* Send a message to tell the user at MBOX that their key has been
1295  * published.  FNAME the name of the file with the key.  */
1296 static gpg_error_t
1297 send_congratulation_message (const char *mbox, const char *keyfile)
1298 {
1299   gpg_error_t err;
1300   estream_t body = NULL;
1301   estream_t bodyenc = NULL;
1302   mime_maker_t mime = NULL;
1303   char *from_buffer = NULL;
1304   const char *from;
1305   strlist_t sl;
1306
1307   from = from_buffer = get_submission_address (mbox);
1308   if (!from)
1309     {
1310       from = opt.default_from;
1311       if (!from)
1312         {
1313           log_error ("no sender address found for '%s'\n", mbox);
1314           err = gpg_error (GPG_ERR_CONFIGURATION);
1315           goto leave;
1316         }
1317       log_info ("Note: using default sender address '%s'\n", from);
1318     }
1319
1320   body = es_fopenmem (0, "w+b");
1321   if (!body)
1322     {
1323       err = gpg_error_from_syserror ();
1324       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
1325       goto leave;
1326     }
1327   /* It is fine to use 8 bit encoding because that is encrypted and
1328    * only our client will see it.  */
1329   es_fputs ("Content-Type: text/plain; charset=utf-8\n"
1330             "Content-Transfer-Encoding: 8bit\n"
1331             "\n",
1332             body);
1333
1334   es_fprintf (body,
1335               "Hello!\n\n"
1336               "The key for your address '%s' has been published\n"
1337               "and can now be retrieved from the Web Key Directory.\n"
1338               "\n"
1339               "For more information on this system see:\n"
1340               "\n"
1341               "  https://gnupg.org/faq/wkd.html\n"
1342               "\n"
1343               "Best regards\n"
1344               "\n"
1345               "  Gnu Key Publisher\n\n\n"
1346               "-- \n"
1347               "The GnuPG Project welcomes donations: %s\n",
1348               mbox, "https://gnupg.org/donate");
1349
1350   es_rewind (body);
1351   err = encrypt_stream (&bodyenc, body, keyfile);
1352   if (err)
1353     goto leave;
1354   es_fclose (body);
1355   body = NULL;
1356
1357   err = mime_maker_new (&mime, NULL);
1358   if (err)
1359     goto leave;
1360   err = mime_maker_add_header (mime, "From", from);
1361   if (err)
1362     goto leave;
1363   err = mime_maker_add_header (mime, "To", mbox);
1364   if (err)
1365     goto leave;
1366   err = mime_maker_add_header (mime, "Subject", "Your key has been published");
1367   if (err)
1368     goto leave;
1369   for (sl = opt.extra_headers; sl; sl = sl->next)
1370     {
1371       err = mime_maker_add_header (mime, sl->d, NULL);
1372       if (err)
1373         goto leave;
1374     }
1375
1376   err = mime_maker_add_header (mime, "Content-Type",
1377                                "multipart/encrypted; "
1378                                "protocol=\"application/pgp-encrypted\"");
1379   if (err)
1380     goto leave;
1381   err = mime_maker_add_container (mime);
1382   if (err)
1383     goto leave;
1384
1385   err = mime_maker_add_header (mime, "Content-Type",
1386                                "application/pgp-encrypted");
1387   if (err)
1388     goto leave;
1389   err = mime_maker_add_body (mime, "Version: 1\n");
1390   if (err)
1391     goto leave;
1392   err = mime_maker_add_header (mime, "Content-Type",
1393                                "application/octet-stream");
1394   if (err)
1395     goto leave;
1396
1397   err = mime_maker_add_stream (mime, &bodyenc);
1398   if (err)
1399     goto leave;
1400
1401   err = wks_send_mime (mime);
1402
1403  leave:
1404   mime_maker_release (mime);
1405   es_fclose (bodyenc);
1406   es_fclose (body);
1407   xfree (from_buffer);
1408   return err;
1409 }
1410
1411
1412 /* Check that we have send a request with NONCE and publish the key.  */
1413 static gpg_error_t
1414 check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
1415 {
1416   gpg_error_t err;
1417   char *fname = NULL;
1418   char *fnewname = NULL;
1419   estream_t key = NULL;
1420   char *hash = NULL;
1421   const char *domain;
1422   const char *s;
1423   strlist_t sl;
1424   char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
1425
1426   /* FIXME: There is a bug in name-value.c which adds white space for
1427    * the last pair and thus we strip the nonce here until this has
1428    * been fixed.  */
1429   char *nonce2 = xstrdup (nonce);
1430   trim_trailing_spaces (nonce2);
1431   nonce = nonce2;
1432
1433
1434   domain = strchr (address, '@');
1435   log_assert (domain && domain[1]);
1436   domain++;
1437   fname = make_filename_try (opt.directory, domain, "pending", nonce, NULL);
1438   if (!fname)
1439     {
1440       err = gpg_error_from_syserror ();
1441       goto leave;
1442     }
1443
1444   /* Try to open the file with the key.  */
1445   key = es_fopen (fname, "rb");
1446   if (!key)
1447     {
1448       err = gpg_error_from_syserror ();
1449       if (gpg_err_code (err) == GPG_ERR_ENOENT)
1450         {
1451           log_info ("no pending request for '%s'\n", address);
1452           err = gpg_error (GPG_ERR_NOT_FOUND);
1453         }
1454       else
1455         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
1456       goto leave;
1457     }
1458
1459   /* We need to get the fingerprint from the key.  */
1460   err = list_key (ctx, key);
1461   if (err)
1462     goto leave;
1463   if (!ctx->fpr)
1464     {
1465       log_error ("error parsing key (no fingerprint)\n");
1466       err = gpg_error (GPG_ERR_NO_PUBKEY);
1467       goto leave;
1468     }
1469   log_info ("fingerprint: %s\n", ctx->fpr);
1470   for (sl = ctx->mboxes; sl; sl = sl->next)
1471     log_info ("  addr-spec: %s\n", sl->d);
1472
1473   /* Check that the key has 'address' as a user id.  We use
1474    * case-insensitive matching because the client is expected to
1475    * return the address verbatim.  */
1476   for (sl = ctx->mboxes; sl; sl = sl->next)
1477     if (!strcmp (sl->d, address))
1478       break;
1479   if (!sl)
1480     {
1481       log_error ("error publishing key: '%s' is not a user ID of %s\n",
1482                  address, ctx->fpr);
1483       err = gpg_error (GPG_ERR_NO_PUBKEY);
1484       goto leave;
1485     }
1486
1487
1488   /* Hash user ID and create filename.  */
1489   s = strchr (address, '@');
1490   log_assert (s);
1491   gcry_md_hash_buffer (GCRY_MD_SHA1, shaxbuf, address, s - address);
1492   hash = zb32_encode (shaxbuf, 8*20);
1493   if (!hash)
1494     {
1495       err = gpg_error_from_syserror ();
1496       goto leave;
1497     }
1498
1499   fnewname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
1500   if (!fnewname)
1501     {
1502       err = gpg_error_from_syserror ();
1503       goto leave;
1504     }
1505
1506   /* Publish.  */
1507   err = copy_key_as_binary (fname, fnewname, address);
1508   if (err)
1509     {
1510       err = gpg_error_from_syserror ();
1511       log_error ("copying '%s' to '%s' failed: %s\n",
1512                  fname, fnewname, gpg_strerror (err));
1513       goto leave;
1514     }
1515
1516   log_info ("key %s published for '%s'\n", ctx->fpr, address);
1517   send_congratulation_message (address, fnewname);
1518
1519   /* Try to publish as DANE record if the DANE directory exists.  */
1520   xfree (fname);
1521   fname = fnewname;
1522   fnewname = make_filename_try (opt.directory, domain, "dane", NULL);
1523   if (!fnewname)
1524     {
1525       err = gpg_error_from_syserror ();
1526       goto leave;
1527     }
1528   if (!access (fnewname, W_OK))
1529     {
1530       /* Yes, we have a dane directory.  */
1531       s = strchr (address, '@');
1532       log_assert (s);
1533       gcry_md_hash_buffer (GCRY_MD_SHA256, shaxbuf, address, s - address);
1534       xfree (hash);
1535       hash = bin2hex (shaxbuf, 28, NULL);
1536       if (!hash)
1537         {
1538           err = gpg_error_from_syserror ();
1539           goto leave;
1540         }
1541       xfree (fnewname);
1542       fnewname = make_filename_try (opt.directory, domain, "dane", hash, NULL);
1543       if (!fnewname)
1544         {
1545           err = gpg_error_from_syserror ();
1546           goto leave;
1547         }
1548       err = copy_key_as_dane (fname, fnewname);
1549       if (err)
1550         goto leave;
1551       log_info ("key %s published for '%s' (DANE record)\n", ctx->fpr, address);
1552     }
1553
1554  leave:
1555   es_fclose (key);
1556   xfree (hash);
1557   xfree (fnewname);
1558   xfree (fname);
1559   xfree (nonce2);
1560   return err;
1561 }
1562
1563
1564 /* Process a confirmation response in MSG.  */
1565 static gpg_error_t
1566 process_confirmation_response (server_ctx_t ctx, estream_t msg)
1567 {
1568   gpg_error_t err;
1569   nvc_t nvc;
1570   nve_t item;
1571   const char *value, *sender, *address, *nonce;
1572
1573   err = nvc_parse (&nvc, NULL, msg);
1574   if (err)
1575     {
1576       log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
1577       goto leave;
1578     }
1579
1580   if (opt.debug)
1581     {
1582       log_debug ("response follows:\n");
1583       nvc_write (nvc, log_get_stream ());
1584     }
1585
1586   /* Check that this is a confirmation response.  */
1587   if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
1588         && !strcmp (value, "confirmation-response")))
1589     {
1590       if (item && value)
1591         log_error ("received unexpected wks message '%s'\n", value);
1592       else
1593         log_error ("received invalid wks message: %s\n", "'type' missing");
1594       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1595       goto leave;
1596     }
1597
1598   /* Get the sender.  */
1599   if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
1600         && is_valid_mailbox (value)))
1601     {
1602       log_error ("received invalid wks message: %s\n",
1603                  "'sender' missing or invalid");
1604       err = gpg_error (GPG_ERR_INV_DATA);
1605       goto leave;
1606     }
1607   sender = value;
1608   (void)sender;
1609   /* FIXME: Do we really need the sender?.  */
1610
1611   /* Get the address.  */
1612   if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
1613         && is_valid_mailbox (value)))
1614     {
1615       log_error ("received invalid wks message: %s\n",
1616                  "'address' missing or invalid");
1617       err = gpg_error (GPG_ERR_INV_DATA);
1618       goto leave;
1619     }
1620   address = value;
1621
1622   /* Get the nonce.  */
1623   if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
1624         && strlen (value) > 16))
1625     {
1626       log_error ("received invalid wks message: %s\n",
1627                  "'nonce' missing or too short");
1628       err = gpg_error (GPG_ERR_INV_DATA);
1629       goto leave;
1630     }
1631   nonce = value;
1632
1633   err = check_and_publish (ctx, address, nonce);
1634
1635
1636  leave:
1637   nvc_release (nvc);
1638   return err;
1639 }
1640
1641
1642 \f
1643 /* Called from the MIME receiver to process the plain text data in MSG .  */
1644 static gpg_error_t
1645 command_receive_cb (void *opaque, const char *mediatype,
1646                     estream_t msg, unsigned int flags)
1647 {
1648   gpg_error_t err;
1649   struct server_ctx_s ctx;
1650
1651   (void)opaque;
1652
1653   memset (&ctx, 0, sizeof ctx);
1654   if ((flags & WKS_RECEIVE_DRAFT2))
1655     ctx.draft_version_2 = 1;
1656
1657   if (!strcmp (mediatype, "application/pgp-keys"))
1658     err = process_new_key (&ctx, msg);
1659   else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
1660     err = process_confirmation_response (&ctx, msg);
1661   else
1662     {
1663       log_info ("ignoring unexpected message of type '%s'\n", mediatype);
1664       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1665     }
1666
1667   xfree (ctx.fpr);
1668   free_strlist (ctx.mboxes);
1669
1670   return err;
1671 }
1672
1673
1674 \f
1675 /* Return a list of all configured domains.  ECh list element is the
1676  * top directory for for the domain.  To figure out the actual domain
1677  * name strrchr(name, '/') can be used.  */
1678 static gpg_error_t
1679 get_domain_list (strlist_t *r_list)
1680 {
1681   gpg_error_t err;
1682   DIR *dir = NULL;
1683   char *fname = NULL;
1684   struct dirent *dentry;
1685   struct stat sb;
1686   strlist_t list = NULL;
1687
1688   *r_list = NULL;
1689
1690   dir = opendir (opt.directory);
1691   if (!dir)
1692     {
1693       err = gpg_error_from_syserror ();
1694       goto leave;
1695     }
1696
1697   while ((dentry = readdir (dir)))
1698     {
1699       if (*dentry->d_name == '.')
1700         continue;
1701       if (!strchr (dentry->d_name, '.'))
1702         continue; /* No dot - can't be a domain subdir.  */
1703
1704       xfree (fname);
1705       fname = make_filename_try (opt.directory, dentry->d_name, NULL);
1706       if (!fname)
1707         {
1708           err = gpg_error_from_syserror ();
1709           log_error ("make_filename failed in %s: %s\n",
1710                      __func__, gpg_strerror (err));
1711           goto leave;
1712         }
1713
1714       if (stat (fname, &sb))
1715         {
1716           err = gpg_error_from_syserror ();
1717           log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
1718           continue;
1719         }
1720       if (!S_ISDIR(sb.st_mode))
1721         continue;
1722
1723       if (!add_to_strlist_try (&list, fname))
1724         {
1725           err = gpg_error_from_syserror ();
1726           log_error ("add_to_strlist failed in %s: %s\n",
1727                      __func__, gpg_strerror (err));
1728           goto leave;
1729         }
1730     }
1731   err = 0;
1732   *r_list = list;
1733   list = NULL;
1734
1735  leave:
1736   free_strlist (list);
1737   if (dir)
1738     closedir (dir);
1739   xfree (fname);
1740   return err;
1741 }
1742
1743
1744 \f
1745 static gpg_error_t
1746 expire_one_domain (const char *top_dirname, const char *domain)
1747 {
1748   gpg_error_t err;
1749   char *dirname;
1750   char *fname = NULL;
1751   DIR *dir = NULL;
1752   struct dirent *dentry;
1753   struct stat sb;
1754   time_t now = gnupg_get_time ();
1755
1756   dirname = make_filename_try (top_dirname, "pending", NULL);
1757   if (!dirname)
1758     {
1759       err = gpg_error_from_syserror ();
1760       log_error ("make_filename failed in %s: %s\n",
1761                  __func__, gpg_strerror (err));
1762       goto leave;
1763     }
1764
1765   dir = opendir (dirname);
1766   if (!dir)
1767     {
1768       err = gpg_error_from_syserror ();
1769       log_error (("can't access directory '%s': %s\n"),
1770                  dirname, gpg_strerror (err));
1771       goto leave;
1772     }
1773
1774   while ((dentry = readdir (dir)))
1775     {
1776       if (*dentry->d_name == '.')
1777         continue;
1778       xfree (fname);
1779       fname = make_filename_try (dirname, dentry->d_name, NULL);
1780       if (!fname)
1781         {
1782           err = gpg_error_from_syserror ();
1783           log_error ("make_filename failed in %s: %s\n",
1784                      __func__, gpg_strerror (err));
1785           goto leave;
1786         }
1787       if (strlen (dentry->d_name) != 32)
1788         {
1789           log_info ("garbage file '%s' ignored\n", fname);
1790           continue;
1791         }
1792       if (stat (fname, &sb))
1793         {
1794           err = gpg_error_from_syserror ();
1795           log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
1796           continue;
1797         }
1798       if (S_ISDIR(sb.st_mode))
1799         {
1800           log_info ("garbage directory '%s' ignored\n", fname);
1801           continue;
1802         }
1803       if (sb.st_mtime + PENDING_TTL < now)
1804         {
1805           if (opt.verbose)
1806             log_info ("domain %s: removing pending key '%s'\n",
1807                       domain, dentry->d_name);
1808           if (remove (fname))
1809             {
1810               err = gpg_error_from_syserror ();
1811               /* In case the file has just been renamed or another
1812                * processes is cleaning up, we don't print a diagnostic
1813                * for ENOENT.  */
1814               if (gpg_err_code (err) != GPG_ERR_ENOENT)
1815                 log_error ("error removing '%s': %s\n",
1816                            fname, gpg_strerror (err));
1817             }
1818         }
1819     }
1820   err = 0;
1821
1822  leave:
1823   if (dir)
1824     closedir (dir);
1825   xfree (dirname);
1826   xfree (fname);
1827   return err;
1828
1829 }
1830
1831
1832 /* Scan spool directories and expire too old pending keys.  */
1833 static gpg_error_t
1834 expire_pending_confirmations (strlist_t domaindirs)
1835 {
1836   gpg_error_t err = 0;
1837   strlist_t sl;
1838   const char *domain;
1839
1840   for (sl = domaindirs; sl; sl = sl->next)
1841     {
1842       domain = strrchr (sl->d, '/');
1843       log_assert (domain);
1844       domain++;
1845
1846       expire_one_domain (sl->d, domain);
1847     }
1848
1849   return err;
1850 }
1851
1852
1853 /* List all configured domains.  */
1854 static gpg_error_t
1855 command_list_domains (void)
1856 {
1857   static struct {
1858     const char *name;
1859     const char *perm;
1860   } requireddirs[] = {
1861     { "pending", "-rwx" },
1862     { "hu",      "-rwxr-xr-x" }
1863   };
1864
1865   gpg_error_t err;
1866   strlist_t domaindirs;
1867   strlist_t sl;
1868   const char *domain;
1869   char *fname = NULL;
1870   int i;
1871   estream_t fp;
1872
1873   err = get_domain_list (&domaindirs);
1874   if (err)
1875     {
1876       log_error ("error reading list of domains: %s\n", gpg_strerror (err));
1877       return err;
1878     }
1879
1880   for (sl = domaindirs; sl; sl = sl->next)
1881     {
1882       domain = strrchr (sl->d, '/');
1883       log_assert (domain);
1884       domain++;
1885       es_printf ("%s\n", domain);
1886
1887       /* Check that the required directories are there.  */
1888       for (i=0; i < DIM (requireddirs); i++)
1889         {
1890           xfree (fname);
1891           fname = make_filename_try (sl->d, requireddirs[i].name, NULL);
1892           if (!fname)
1893             {
1894               err = gpg_error_from_syserror ();
1895               goto leave;
1896             }
1897           if (access (fname, W_OK))
1898             {
1899               err = gpg_error_from_syserror ();
1900               if (gpg_err_code (err) == GPG_ERR_ENOENT)
1901                 {
1902                   if (gnupg_mkdir (fname, requireddirs[i].perm))
1903                     {
1904                       err = gpg_error_from_syserror ();
1905                       log_error ("domain %s: error creating subdir '%s': %s\n",
1906                                  domain, requireddirs[i].name,
1907                                  gpg_strerror (err));
1908                     }
1909                   else
1910                     log_info ("domain %s: subdir '%s' created\n",
1911                               domain, requireddirs[i].name);
1912                 }
1913               else if (err)
1914                 log_error ("domain %s: problem with subdir '%s': %s\n",
1915                            domain, requireddirs[i].name, gpg_strerror (err));
1916             }
1917         }
1918
1919       /* Print a warning if the submission address is not configured.  */
1920       xfree (fname);
1921       fname = make_filename_try (sl->d, "submission-address", NULL);
1922       if (!fname)
1923         {
1924           err = gpg_error_from_syserror ();
1925           goto leave;
1926         }
1927       if (access (fname, F_OK))
1928         {
1929           err = gpg_error_from_syserror ();
1930           if (gpg_err_code (err) == GPG_ERR_ENOENT)
1931             log_error ("domain %s: submission address not configured\n",
1932                        domain);
1933           else
1934             log_error ("domain %s: problem with '%s': %s\n",
1935                        domain, fname, gpg_strerror (err));
1936         }
1937
1938       /* Check the syntax of the optional policy file.  */
1939       xfree (fname);
1940       fname = make_filename_try (sl->d, "policy", NULL);
1941       if (!fname)
1942         {
1943           err = gpg_error_from_syserror ();
1944           goto leave;
1945         }
1946       fp = es_fopen (fname, "r");
1947       if (!fp)
1948         {
1949           err = gpg_error_from_syserror ();
1950           if (gpg_err_code (err) != GPG_ERR_ENOENT)
1951             log_error ("domain %s: error in policy file: %s\n",
1952                        domain, gpg_strerror (err));
1953         }
1954       else
1955         {
1956           struct policy_flags_s policy;
1957           err = wks_parse_policy (&policy, fp, 0);
1958           es_fclose (fp);
1959           if (!err)
1960             {
1961               struct policy_flags_s empty_policy;
1962               memset (&empty_policy, 0, sizeof empty_policy);
1963               if (!memcmp (&empty_policy, &policy, sizeof policy))
1964                 log_error ("domain %s: empty policy file\n", domain);
1965             }
1966         }
1967
1968
1969     }
1970   err = 0;
1971
1972  leave:
1973   xfree (fname);
1974   free_strlist (domaindirs);
1975   return err;
1976 }
1977
1978
1979 /* Run regular maintenance jobs.  */
1980 static gpg_error_t
1981 command_cron (void)
1982 {
1983   gpg_error_t err;
1984   strlist_t domaindirs;
1985
1986   err = get_domain_list (&domaindirs);
1987   if (err)
1988     {
1989       log_error ("error reading list of domains: %s\n", gpg_strerror (err));
1990       return err;
1991     }
1992
1993   err = expire_pending_confirmations (domaindirs);
1994
1995   free_strlist (domaindirs);
1996   return err;
1997 }