wks: Send only the newest UID to the server.
[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   uidinfo_list_t mboxes;  /* List with 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   uidinfo_list_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_uidinfo_list (ctx->mboxes);
1105   err = wks_list_key (key, &ctx->fpr, &ctx->mboxes);
1106   if (err)
1107     goto leave;
1108   log_assert (ctx->fpr);
1109   log_info ("fingerprint: %s\n", ctx->fpr);
1110   for (sl = ctx->mboxes; sl; sl = sl->next)
1111     {
1112       if (sl->mbox)
1113         log_info ("  addr-spec: %s\n", sl->mbox);
1114     }
1115
1116   /* Walk over all user ids and send confirmation requests for those
1117    * we support.  */
1118   for (sl = ctx->mboxes; sl; sl = sl->next)
1119     {
1120       if (!sl->mbox)
1121         continue;
1122       s = strchr (sl->mbox, '@');
1123       log_assert (s && s[1]);
1124       xfree (dname);
1125       dname = make_filename_try (opt.directory, s+1, NULL);
1126       if (!dname)
1127         {
1128           err = gpg_error_from_syserror ();
1129           goto leave;
1130         }
1131
1132       if (access (dname, W_OK))
1133         {
1134           log_info ("skipping address '%s': Domain not configured\n", sl->mbox);
1135           continue;
1136         }
1137       if (get_policy_flags (&policybuf, sl->mbox))
1138         {
1139           log_info ("skipping address '%s': Bad policy flags\n", sl->mbox);
1140           continue;
1141         }
1142
1143       if (policybuf.auth_submit)
1144         {
1145           /* Bypass the confirmation stuff and publish the key as is.  */
1146           log_info ("publishing address '%s'\n", sl->mbox);
1147           /* FIXME: We need to make sure that we do this only for the
1148            * address in the mail.  */
1149           log_debug ("auth-submit not yet working!\n");
1150         }
1151       else
1152         {
1153           log_info ("storing address '%s'\n", sl->mbox);
1154
1155           xfree (nonce);
1156           xfree (fname);
1157           err = store_key_as_pending (dname, key, &nonce, &fname);
1158           if (err)
1159             goto leave;
1160
1161           err = send_confirmation_request (ctx, sl->mbox, nonce, fname);
1162           if (err)
1163             goto leave;
1164         }
1165     }
1166
1167  leave:
1168   if (nonce)
1169     wipememory (nonce, strlen (nonce));
1170   xfree (nonce);
1171   xfree (fname);
1172   xfree (dname);
1173   return err;
1174 }
1175
1176
1177 \f
1178 /* Send a message to tell the user at MBOX that their key has been
1179  * published.  FNAME the name of the file with the key.  */
1180 static gpg_error_t
1181 send_congratulation_message (const char *mbox, const char *keyfile)
1182 {
1183   gpg_error_t err;
1184   estream_t body = NULL;
1185   estream_t bodyenc = NULL;
1186   mime_maker_t mime = NULL;
1187   char *from_buffer = NULL;
1188   const char *from;
1189   strlist_t sl;
1190
1191   from = from_buffer = get_submission_address (mbox);
1192   if (!from)
1193     {
1194       from = opt.default_from;
1195       if (!from)
1196         {
1197           log_error ("no sender address found for '%s'\n", mbox);
1198           err = gpg_error (GPG_ERR_CONFIGURATION);
1199           goto leave;
1200         }
1201       log_info ("Note: using default sender address '%s'\n", from);
1202     }
1203
1204   body = es_fopenmem (0, "w+b");
1205   if (!body)
1206     {
1207       err = gpg_error_from_syserror ();
1208       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
1209       goto leave;
1210     }
1211   /* It is fine to use 8 bit encoding because that is encrypted and
1212    * only our client will see it.  */
1213   es_fputs ("Content-Type: text/plain; charset=utf-8\n"
1214             "Content-Transfer-Encoding: 8bit\n"
1215             "\n",
1216             body);
1217
1218   es_fprintf (body,
1219               "Hello!\n\n"
1220               "The key for your address '%s' has been published\n"
1221               "and can now be retrieved from the Web Key Directory.\n"
1222               "\n"
1223               "For more information on this system see:\n"
1224               "\n"
1225               "  https://gnupg.org/faq/wkd.html\n"
1226               "\n"
1227               "Best regards\n"
1228               "\n"
1229               "  Gnu Key Publisher\n\n\n"
1230               "-- \n"
1231               "The GnuPG Project welcomes donations: %s\n",
1232               mbox, "https://gnupg.org/donate");
1233
1234   es_rewind (body);
1235   err = encrypt_stream (&bodyenc, body, keyfile);
1236   if (err)
1237     goto leave;
1238   es_fclose (body);
1239   body = NULL;
1240
1241   err = mime_maker_new (&mime, NULL);
1242   if (err)
1243     goto leave;
1244   err = mime_maker_add_header (mime, "From", from);
1245   if (err)
1246     goto leave;
1247   err = mime_maker_add_header (mime, "To", mbox);
1248   if (err)
1249     goto leave;
1250   err = mime_maker_add_header (mime, "Subject", "Your key has been published");
1251   if (err)
1252     goto leave;
1253   err = mime_maker_add_header (mime, "Wks-Draft-Version",
1254                                STR2(WKS_DRAFT_VERSION));
1255   if (err)
1256     goto leave;
1257   err = mime_maker_add_header (mime, "WKS-Phase", "done");
1258   if (err)
1259     goto leave;
1260   for (sl = opt.extra_headers; sl; sl = sl->next)
1261     {
1262       err = mime_maker_add_header (mime, sl->d, NULL);
1263       if (err)
1264         goto leave;
1265     }
1266
1267   err = mime_maker_add_header (mime, "Content-Type",
1268                                "multipart/encrypted; "
1269                                "protocol=\"application/pgp-encrypted\"");
1270   if (err)
1271     goto leave;
1272   err = mime_maker_add_container (mime);
1273   if (err)
1274     goto leave;
1275
1276   err = mime_maker_add_header (mime, "Content-Type",
1277                                "application/pgp-encrypted");
1278   if (err)
1279     goto leave;
1280   err = mime_maker_add_body (mime, "Version: 1\n");
1281   if (err)
1282     goto leave;
1283   err = mime_maker_add_header (mime, "Content-Type",
1284                                "application/octet-stream");
1285   if (err)
1286     goto leave;
1287
1288   err = mime_maker_add_stream (mime, &bodyenc);
1289   if (err)
1290     goto leave;
1291
1292   err = wks_send_mime (mime);
1293
1294  leave:
1295   mime_maker_release (mime);
1296   es_fclose (bodyenc);
1297   es_fclose (body);
1298   xfree (from_buffer);
1299   return err;
1300 }
1301
1302
1303 /* Check that we have send a request with NONCE and publish the key.  */
1304 static gpg_error_t
1305 check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
1306 {
1307   gpg_error_t err;
1308   char *fname = NULL;
1309   char *fnewname = NULL;
1310   estream_t key = NULL;
1311   char *hash = NULL;
1312   const char *domain;
1313   const char *s;
1314   uidinfo_list_t sl;
1315   char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
1316
1317   /* FIXME: There is a bug in name-value.c which adds white space for
1318    * the last pair and thus we strip the nonce here until this has
1319    * been fixed.  */
1320   char *nonce2 = xstrdup (nonce);
1321   trim_trailing_spaces (nonce2);
1322   nonce = nonce2;
1323
1324
1325   domain = strchr (address, '@');
1326   log_assert (domain && domain[1]);
1327   domain++;
1328   fname = make_filename_try (opt.directory, domain, "pending", nonce, NULL);
1329   if (!fname)
1330     {
1331       err = gpg_error_from_syserror ();
1332       goto leave;
1333     }
1334
1335   /* Try to open the file with the key.  */
1336   key = es_fopen (fname, "rb");
1337   if (!key)
1338     {
1339       err = gpg_error_from_syserror ();
1340       if (gpg_err_code (err) == GPG_ERR_ENOENT)
1341         {
1342           log_info ("no pending request for '%s'\n", address);
1343           err = gpg_error (GPG_ERR_NOT_FOUND);
1344         }
1345       else
1346         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
1347       goto leave;
1348     }
1349
1350   /* We need to get the fingerprint from the key.  */
1351   xfree (ctx->fpr);
1352   free_uidinfo_list (ctx->mboxes);
1353   err = wks_list_key (key, &ctx->fpr, &ctx->mboxes);
1354   if (err)
1355     goto leave;
1356   log_assert (ctx->fpr);
1357   log_info ("fingerprint: %s\n", ctx->fpr);
1358   for (sl = ctx->mboxes; sl; sl = sl->next)
1359     if (sl->mbox)
1360       log_info ("  addr-spec: %s\n", sl->mbox);
1361
1362   /* Check that the key has 'address' as a user id.  We use
1363    * case-insensitive matching because the client is expected to
1364    * return the address verbatim.  */
1365   for (sl = ctx->mboxes; sl; sl = sl->next)
1366     if (sl->mbox && !strcmp (sl->mbox, address))
1367       break;
1368   if (!sl)
1369     {
1370       log_error ("error publishing key: '%s' is not a user ID of %s\n",
1371                  address, ctx->fpr);
1372       err = gpg_error (GPG_ERR_NO_PUBKEY);
1373       goto leave;
1374     }
1375
1376
1377   /* Hash user ID and create filename.  */
1378   s = strchr (address, '@');
1379   log_assert (s);
1380   gcry_md_hash_buffer (GCRY_MD_SHA1, shaxbuf, address, s - address);
1381   hash = zb32_encode (shaxbuf, 8*20);
1382   if (!hash)
1383     {
1384       err = gpg_error_from_syserror ();
1385       goto leave;
1386     }
1387
1388   fnewname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
1389   if (!fnewname)
1390     {
1391       err = gpg_error_from_syserror ();
1392       goto leave;
1393     }
1394
1395   /* Publish.  */
1396   err = copy_key_as_binary (fname, fnewname, address);
1397   if (err)
1398     {
1399       err = gpg_error_from_syserror ();
1400       log_error ("copying '%s' to '%s' failed: %s\n",
1401                  fname, fnewname, gpg_strerror (err));
1402       goto leave;
1403     }
1404
1405   /* Make sure it is world readable.  */
1406   if (gnupg_chmod (fnewname, "-rwxr--r--"))
1407     log_error ("can't set permissions of '%s': %s\n",
1408                fnewname, gpg_strerror (gpg_err_code_from_syserror()));
1409
1410   log_info ("key %s published for '%s'\n", ctx->fpr, address);
1411   send_congratulation_message (address, fnewname);
1412
1413   /* Try to publish as DANE record if the DANE directory exists.  */
1414   xfree (fname);
1415   fname = fnewname;
1416   fnewname = make_filename_try (opt.directory, domain, "dane", NULL);
1417   if (!fnewname)
1418     {
1419       err = gpg_error_from_syserror ();
1420       goto leave;
1421     }
1422   if (!access (fnewname, W_OK))
1423     {
1424       /* Yes, we have a dane directory.  */
1425       s = strchr (address, '@');
1426       log_assert (s);
1427       gcry_md_hash_buffer (GCRY_MD_SHA256, shaxbuf, address, s - address);
1428       xfree (hash);
1429       hash = bin2hex (shaxbuf, 28, NULL);
1430       if (!hash)
1431         {
1432           err = gpg_error_from_syserror ();
1433           goto leave;
1434         }
1435       xfree (fnewname);
1436       fnewname = make_filename_try (opt.directory, domain, "dane", hash, NULL);
1437       if (!fnewname)
1438         {
1439           err = gpg_error_from_syserror ();
1440           goto leave;
1441         }
1442       err = copy_key_as_dane (fname, fnewname);
1443       if (err)
1444         goto leave;
1445       log_info ("key %s published for '%s' (DANE record)\n", ctx->fpr, address);
1446     }
1447
1448  leave:
1449   es_fclose (key);
1450   xfree (hash);
1451   xfree (fnewname);
1452   xfree (fname);
1453   xfree (nonce2);
1454   return err;
1455 }
1456
1457
1458 /* Process a confirmation response in MSG.  */
1459 static gpg_error_t
1460 process_confirmation_response (server_ctx_t ctx, estream_t msg)
1461 {
1462   gpg_error_t err;
1463   nvc_t nvc;
1464   nve_t item;
1465   const char *value, *sender, *address, *nonce;
1466
1467   err = nvc_parse (&nvc, NULL, msg);
1468   if (err)
1469     {
1470       log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
1471       goto leave;
1472     }
1473
1474   if (opt.debug)
1475     {
1476       log_debug ("response follows:\n");
1477       nvc_write (nvc, log_get_stream ());
1478     }
1479
1480   /* Check that this is a confirmation response.  */
1481   if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
1482         && !strcmp (value, "confirmation-response")))
1483     {
1484       if (item && value)
1485         log_error ("received unexpected wks message '%s'\n", value);
1486       else
1487         log_error ("received invalid wks message: %s\n", "'type' missing");
1488       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1489       goto leave;
1490     }
1491
1492   /* Get the sender.  */
1493   if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
1494         && is_valid_mailbox (value)))
1495     {
1496       log_error ("received invalid wks message: %s\n",
1497                  "'sender' missing or invalid");
1498       err = gpg_error (GPG_ERR_INV_DATA);
1499       goto leave;
1500     }
1501   sender = value;
1502   (void)sender;
1503   /* FIXME: Do we really need the sender?.  */
1504
1505   /* Get the address.  */
1506   if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
1507         && is_valid_mailbox (value)))
1508     {
1509       log_error ("received invalid wks message: %s\n",
1510                  "'address' missing or invalid");
1511       err = gpg_error (GPG_ERR_INV_DATA);
1512       goto leave;
1513     }
1514   address = value;
1515
1516   /* Get the nonce.  */
1517   if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
1518         && strlen (value) > 16))
1519     {
1520       log_error ("received invalid wks message: %s\n",
1521                  "'nonce' missing or too short");
1522       err = gpg_error (GPG_ERR_INV_DATA);
1523       goto leave;
1524     }
1525   nonce = value;
1526
1527   err = check_and_publish (ctx, address, nonce);
1528
1529
1530  leave:
1531   nvc_release (nvc);
1532   return err;
1533 }
1534
1535
1536 \f
1537 /* Called from the MIME receiver to process the plain text data in MSG .  */
1538 static gpg_error_t
1539 command_receive_cb (void *opaque, const char *mediatype,
1540                     estream_t msg, unsigned int flags)
1541 {
1542   gpg_error_t err;
1543   struct server_ctx_s ctx;
1544
1545   (void)opaque;
1546
1547   memset (&ctx, 0, sizeof ctx);
1548   if ((flags & WKS_RECEIVE_DRAFT2))
1549     ctx.draft_version_2 = 1;
1550
1551   if (!strcmp (mediatype, "application/pgp-keys"))
1552     err = process_new_key (&ctx, msg);
1553   else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
1554     err = process_confirmation_response (&ctx, msg);
1555   else
1556     {
1557       log_info ("ignoring unexpected message of type '%s'\n", mediatype);
1558       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1559     }
1560
1561   xfree (ctx.fpr);
1562   free_uidinfo_list (ctx.mboxes);
1563
1564   return err;
1565 }
1566
1567
1568 \f
1569 /* Return a list of all configured domains.  ECh list element is the
1570  * top directory for the domain.  To figure out the actual domain
1571  * name strrchr(name, '/') can be used.  */
1572 static gpg_error_t
1573 get_domain_list (strlist_t *r_list)
1574 {
1575   gpg_error_t err;
1576   DIR *dir = NULL;
1577   char *fname = NULL;
1578   struct dirent *dentry;
1579   struct stat sb;
1580   strlist_t list = NULL;
1581
1582   *r_list = NULL;
1583
1584   dir = opendir (opt.directory);
1585   if (!dir)
1586     {
1587       err = gpg_error_from_syserror ();
1588       goto leave;
1589     }
1590
1591   while ((dentry = readdir (dir)))
1592     {
1593       if (*dentry->d_name == '.')
1594         continue;
1595       if (!strchr (dentry->d_name, '.'))
1596         continue; /* No dot - can't be a domain subdir.  */
1597
1598       xfree (fname);
1599       fname = make_filename_try (opt.directory, dentry->d_name, NULL);
1600       if (!fname)
1601         {
1602           err = gpg_error_from_syserror ();
1603           log_error ("make_filename failed in %s: %s\n",
1604                      __func__, gpg_strerror (err));
1605           goto leave;
1606         }
1607
1608       if (stat (fname, &sb))
1609         {
1610           err = gpg_error_from_syserror ();
1611           log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
1612           continue;
1613         }
1614       if (!S_ISDIR(sb.st_mode))
1615         continue;
1616
1617       if (!add_to_strlist_try (&list, fname))
1618         {
1619           err = gpg_error_from_syserror ();
1620           log_error ("add_to_strlist failed in %s: %s\n",
1621                      __func__, gpg_strerror (err));
1622           goto leave;
1623         }
1624     }
1625   err = 0;
1626   *r_list = list;
1627   list = NULL;
1628
1629  leave:
1630   free_strlist (list);
1631   if (dir)
1632     closedir (dir);
1633   xfree (fname);
1634   return err;
1635 }
1636
1637
1638 \f
1639 static gpg_error_t
1640 expire_one_domain (const char *top_dirname, const char *domain)
1641 {
1642   gpg_error_t err;
1643   char *dirname;
1644   char *fname = NULL;
1645   DIR *dir = NULL;
1646   struct dirent *dentry;
1647   struct stat sb;
1648   time_t now = gnupg_get_time ();
1649
1650   dirname = make_filename_try (top_dirname, "pending", NULL);
1651   if (!dirname)
1652     {
1653       err = gpg_error_from_syserror ();
1654       log_error ("make_filename failed in %s: %s\n",
1655                  __func__, gpg_strerror (err));
1656       goto leave;
1657     }
1658
1659   dir = opendir (dirname);
1660   if (!dir)
1661     {
1662       err = gpg_error_from_syserror ();
1663       log_error (("can't access directory '%s': %s\n"),
1664                  dirname, gpg_strerror (err));
1665       goto leave;
1666     }
1667
1668   while ((dentry = readdir (dir)))
1669     {
1670       if (*dentry->d_name == '.')
1671         continue;
1672       xfree (fname);
1673       fname = make_filename_try (dirname, dentry->d_name, NULL);
1674       if (!fname)
1675         {
1676           err = gpg_error_from_syserror ();
1677           log_error ("make_filename failed in %s: %s\n",
1678                      __func__, gpg_strerror (err));
1679           goto leave;
1680         }
1681       if (strlen (dentry->d_name) != 32)
1682         {
1683           log_info ("garbage file '%s' ignored\n", fname);
1684           continue;
1685         }
1686       if (stat (fname, &sb))
1687         {
1688           err = gpg_error_from_syserror ();
1689           log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
1690           continue;
1691         }
1692       if (S_ISDIR(sb.st_mode))
1693         {
1694           log_info ("garbage directory '%s' ignored\n", fname);
1695           continue;
1696         }
1697       if (sb.st_mtime + PENDING_TTL < now)
1698         {
1699           if (opt.verbose)
1700             log_info ("domain %s: removing pending key '%s'\n",
1701                       domain, dentry->d_name);
1702           if (remove (fname))
1703             {
1704               err = gpg_error_from_syserror ();
1705               /* In case the file has just been renamed or another
1706                * processes is cleaning up, we don't print a diagnostic
1707                * for ENOENT.  */
1708               if (gpg_err_code (err) != GPG_ERR_ENOENT)
1709                 log_error ("error removing '%s': %s\n",
1710                            fname, gpg_strerror (err));
1711             }
1712         }
1713     }
1714   err = 0;
1715
1716  leave:
1717   if (dir)
1718     closedir (dir);
1719   xfree (dirname);
1720   xfree (fname);
1721   return err;
1722
1723 }
1724
1725
1726 /* Scan spool directories and expire too old pending keys.  */
1727 static gpg_error_t
1728 expire_pending_confirmations (strlist_t domaindirs)
1729 {
1730   gpg_error_t err = 0;
1731   strlist_t sl;
1732   const char *domain;
1733
1734   for (sl = domaindirs; sl; sl = sl->next)
1735     {
1736       domain = strrchr (sl->d, '/');
1737       log_assert (domain);
1738       domain++;
1739
1740       expire_one_domain (sl->d, domain);
1741     }
1742
1743   return err;
1744 }
1745
1746
1747 /* List all configured domains.  */
1748 static gpg_error_t
1749 command_list_domains (void)
1750 {
1751   static struct {
1752     const char *name;
1753     const char *perm;
1754   } requireddirs[] = {
1755     { "pending", "-rwx" },
1756     { "hu",      "-rwxr-xr-x" }
1757   };
1758
1759   gpg_error_t err;
1760   strlist_t domaindirs;
1761   strlist_t sl;
1762   const char *domain;
1763   char *fname = NULL;
1764   int i;
1765   estream_t fp;
1766
1767   err = get_domain_list (&domaindirs);
1768   if (err)
1769     {
1770       log_error ("error reading list of domains: %s\n", gpg_strerror (err));
1771       return err;
1772     }
1773
1774   for (sl = domaindirs; sl; sl = sl->next)
1775     {
1776       domain = strrchr (sl->d, '/');
1777       log_assert (domain);
1778       domain++;
1779       es_printf ("%s\n", domain);
1780
1781       /* Check that the required directories are there.  */
1782       for (i=0; i < DIM (requireddirs); i++)
1783         {
1784           xfree (fname);
1785           fname = make_filename_try (sl->d, requireddirs[i].name, NULL);
1786           if (!fname)
1787             {
1788               err = gpg_error_from_syserror ();
1789               goto leave;
1790             }
1791           if (access (fname, W_OK))
1792             {
1793               err = gpg_error_from_syserror ();
1794               if (gpg_err_code (err) == GPG_ERR_ENOENT)
1795                 {
1796                   if (gnupg_mkdir (fname, requireddirs[i].perm))
1797                     {
1798                       err = gpg_error_from_syserror ();
1799                       log_error ("domain %s: error creating subdir '%s': %s\n",
1800                                  domain, requireddirs[i].name,
1801                                  gpg_strerror (err));
1802                     }
1803                   else
1804                     log_info ("domain %s: subdir '%s' created\n",
1805                               domain, requireddirs[i].name);
1806                 }
1807               else if (err)
1808                 log_error ("domain %s: problem with subdir '%s': %s\n",
1809                            domain, requireddirs[i].name, gpg_strerror (err));
1810             }
1811         }
1812
1813       /* Print a warning if the submission address is not configured.  */
1814       xfree (fname);
1815       fname = make_filename_try (sl->d, "submission-address", NULL);
1816       if (!fname)
1817         {
1818           err = gpg_error_from_syserror ();
1819           goto leave;
1820         }
1821       if (access (fname, F_OK))
1822         {
1823           err = gpg_error_from_syserror ();
1824           if (gpg_err_code (err) == GPG_ERR_ENOENT)
1825             log_error ("domain %s: submission address not configured\n",
1826                        domain);
1827           else
1828             log_error ("domain %s: problem with '%s': %s\n",
1829                        domain, fname, gpg_strerror (err));
1830         }
1831
1832       /* Check the syntax of the optional policy file.  */
1833       xfree (fname);
1834       fname = make_filename_try (sl->d, "policy", NULL);
1835       if (!fname)
1836         {
1837           err = gpg_error_from_syserror ();
1838           goto leave;
1839         }
1840       fp = es_fopen (fname, "r");
1841       if (!fp)
1842         {
1843           err = gpg_error_from_syserror ();
1844           if (gpg_err_code (err) != GPG_ERR_ENOENT)
1845             log_error ("domain %s: error in policy file: %s\n",
1846                        domain, gpg_strerror (err));
1847         }
1848       else
1849         {
1850           struct policy_flags_s policy;
1851           err = wks_parse_policy (&policy, fp, 0);
1852           es_fclose (fp);
1853           if (!err)
1854             {
1855               struct policy_flags_s empty_policy;
1856               memset (&empty_policy, 0, sizeof empty_policy);
1857               if (!memcmp (&empty_policy, &policy, sizeof policy))
1858                 log_error ("domain %s: empty policy file\n", domain);
1859             }
1860         }
1861
1862
1863     }
1864   err = 0;
1865
1866  leave:
1867   xfree (fname);
1868   free_strlist (domaindirs);
1869   return err;
1870 }
1871
1872
1873 /* Run regular maintenance jobs.  */
1874 static gpg_error_t
1875 command_cron (void)
1876 {
1877   gpg_error_t err;
1878   strlist_t domaindirs;
1879
1880   err = get_domain_list (&domaindirs);
1881   if (err)
1882     {
1883       log_error ("error reading list of domains: %s\n", gpg_strerror (err));
1884       return err;
1885     }
1886
1887   err = expire_pending_confirmations (domaindirs);
1888
1889   free_strlist (domaindirs);
1890   return err;
1891 }
1892
1893
1894 /* Install a single key into the WKD by reading FNAME.  */
1895 static gpg_error_t
1896 command_install_key (const char *fname)
1897 {
1898   (void)fname;
1899   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1900 }
1901
1902
1903 /* Remove the key with mail address MAILADDR.  */
1904 static gpg_error_t
1905 command_remove_key (const char *mailaddr)
1906 {
1907   (void)mailaddr;
1908   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1909 }
1910
1911
1912 /* Revoke the key with mail address MAILADDR.  */
1913 static gpg_error_t
1914 command_revoke_key (const char *mailaddr)
1915 {
1916   (void)mailaddr;
1917   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1918 }