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