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