Clean up word replication.
[gnupg.git] / tools / gpg-wks-server.c
1 /* gpg-wks-server.c - A server for the Web Key Service protocols.
2  * Copyright (C) 2016 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20 /* The Web Key Service I-D defines an update protocol to store a
21  * public key in the Web Key Directory.  The current specification is
22  * draft-koch-openpgp-webkey-service-01.txt.
23  */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
33
34 #include "util.h"
35 #include "init.h"
36 #include "sysutils.h"
37 #include "ccparray.h"
38 #include "exectool.h"
39 #include "zb32.h"
40 #include "mbox-util.h"
41 #include "name-value.h"
42 #include "mime-maker.h"
43 #include "send-mail.h"
44 #include "gpg-wks.h"
45
46
47 /* The time we wait for a confirmation response.  */
48 #define PENDING_TTL (86400 * 3)  /* 3 days.  */
49
50
51 /* Constants to identify the commands and options. */
52 enum cmd_and_opt_values
53   {
54     aNull = 0,
55
56     oQuiet      = 'q',
57     oVerbose    = 'v',
58     oOutput     = 'o',
59
60     oDebug      = 500,
61
62     aReceive,
63     aCron,
64     aListDomains,
65
66     oGpgProgram,
67     oSend,
68     oFrom,
69     oHeader,
70
71     oDummy
72   };
73
74
75 /* The list of commands and options. */
76 static ARGPARSE_OPTS opts[] = {
77   ARGPARSE_group (300, ("@Commands:\n ")),
78
79   ARGPARSE_c (aReceive,   "receive",
80               ("receive a submission or confirmation")),
81   ARGPARSE_c (aCron,      "cron",
82               ("run regular jobs")),
83   ARGPARSE_c (aListDomains, "list-domains",
84               ("list configured domains")),
85
86   ARGPARSE_group (301, ("@\nOptions:\n ")),
87
88   ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
89   ARGPARSE_s_n (oQuiet, "quiet",  ("be somewhat more quiet")),
90   ARGPARSE_s_s (oDebug, "debug", "@"),
91   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
92   ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
93   ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
94   ARGPARSE_s_s (oFrom, "from", "|ADDR|use ADDR as the default sender"),
95   ARGPARSE_s_s (oHeader, "header" ,
96                 "|NAME=VALUE|add \"NAME: VALUE\" as header to all mails"),
97
98   ARGPARSE_end ()
99 };
100
101
102 /* The list of supported debug flags.  */
103 static struct debug_flags_s debug_flags [] =
104   {
105     { DBG_MIME_VALUE   , "mime"    },
106     { DBG_PARSER_VALUE , "parser"  },
107     { DBG_CRYPTO_VALUE , "crypto"  },
108     { DBG_MEMORY_VALUE , "memory"  },
109     { DBG_MEMSTAT_VALUE, "memstat" },
110     { DBG_IPC_VALUE    , "ipc"     },
111     { DBG_EXTPROG_VALUE, "extprog" },
112     { 0, NULL }
113   };
114
115
116 /* State for processing a message.  */
117 struct server_ctx_s
118 {
119   char *fpr;
120   strlist_t mboxes;  /* List of addr-specs taken from the UIDs.  */
121   unsigned int draft_version_2:1; /* Client supports the draft 2.  */
122 };
123 typedef struct server_ctx_s *server_ctx_t;
124
125 /* Prototypes.  */
126 static gpg_error_t get_domain_list (strlist_t *r_list);
127
128 static gpg_error_t command_receive_cb (void *opaque,
129                                        const char *mediatype, estream_t fp,
130                                        unsigned int flags);
131 static gpg_error_t command_list_domains (void);
132 static gpg_error_t command_cron (void);
133
134
135 \f
136 /* Print usage information and 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
919   /* Help Enigmail to identify messages.  Note that this is on no way
920    * secured.  */
921   err = mime_maker_add_header (mime, "WKS-Phase", "confirm");
922   if (err)
923     goto leave;
924
925   for (sl = opt.extra_headers; sl; sl = sl->next)
926     {
927       err = mime_maker_add_header (mime, sl->d, NULL);
928       if (err)
929         goto leave;
930     }
931
932   if (!ctx->draft_version_2)
933     {
934       err = mime_maker_add_header (mime, "Content-Type",
935                                    "multipart/encrypted; "
936                                    "protocol=\"application/pgp-encrypted\"");
937       if (err)
938         goto leave;
939       err = mime_maker_add_container (mime);
940       if (err)
941         goto leave;
942
943       err = mime_maker_add_header (mime, "Content-Type",
944                                    "application/pgp-encrypted");
945       if (err)
946         goto leave;
947       err = mime_maker_add_body (mime, "Version: 1\n");
948       if (err)
949         goto leave;
950       err = mime_maker_add_header (mime, "Content-Type",
951                                    "application/octet-stream");
952       if (err)
953         goto leave;
954
955       err = mime_maker_add_stream (mime, &bodyenc);
956       if (err)
957         goto leave;
958
959     }
960   else
961     {
962       unsigned int partid;
963
964       /* FIXME: Add micalg.  */
965       err = mime_maker_add_header (mime, "Content-Type",
966                                    "multipart/signed; "
967                                    "protocol=\"application/pgp-signature\"");
968       if (err)
969         goto leave;
970       err = mime_maker_add_container (mime);
971       if (err)
972         goto leave;
973
974       err = mime_maker_add_header (mime, "Content-Type", "multipart/mixed");
975       if (err)
976         goto leave;
977
978       err = mime_maker_add_container (mime);
979       if (err)
980         goto leave;
981       partid = mime_maker_get_partid (mime);
982
983       err = mime_maker_add_header (mime, "Content-Type", "text/plain");
984       if (err)
985         goto leave;
986
987       err = mime_maker_add_body
988         (mime,
989          "This message has been send to confirm your request\n"
990          "to publish your key.  If you did not request a key\n"
991          "publication, simply ignore this message.\n"
992          "\n"
993          "Most mail software can handle this kind of message\n"
994          "automatically and thus you would not have seen this\n"
995          "message.  It seems that your client does not fully\n"
996          "support this service.  The web page\n"
997          "\n"
998          "       https://gnupg.org/faq/wkd.html\n"
999          "\n"
1000          "explains how you can process this message anyway in\n"
1001          "a few manual steps.\n");
1002       if (err)
1003         goto leave;
1004
1005       err = mime_maker_add_header (mime, "Content-Type",
1006                                    "application/vnd.gnupg.wks");
1007       if (err)
1008         goto leave;
1009
1010       err = mime_maker_add_stream (mime, &bodyenc);
1011       if (err)
1012         goto leave;
1013
1014       err = mime_maker_end_container (mime);
1015       if (err)
1016         goto leave;
1017
1018       mime_maker_dump_tree (mime);
1019       err = mime_maker_get_part (mime, partid, &signeddata);
1020       if (err)
1021         goto leave;
1022
1023       err = sign_stream (&signature, signeddata, from);
1024       if (err)
1025         goto leave;
1026
1027       err = mime_maker_add_header (mime, "Content-Type",
1028                                    "application/pgp-signature");
1029       if (err)
1030         goto leave;
1031
1032       err = mime_maker_add_stream (mime, &signature);
1033       if (err)
1034         goto leave;
1035     }
1036
1037   err = wks_send_mime (mime);
1038
1039  leave:
1040   mime_maker_release (mime);
1041   es_fclose (signature);
1042   es_fclose (signeddata);
1043   es_fclose (bodyenc);
1044   es_fclose (body);
1045   xfree (from_buffer);
1046   return err;
1047 }
1048
1049
1050 /* Store the key given by KEY into the pending directory and send a
1051  * confirmation requests.  */
1052 static gpg_error_t
1053 process_new_key (server_ctx_t ctx, estream_t key)
1054 {
1055   gpg_error_t err;
1056   strlist_t sl;
1057   const char *s;
1058   char *dname = NULL;
1059   char *nonce = NULL;
1060   char *fname = NULL;
1061   struct policy_flags_s policybuf;
1062
1063   /* First figure out the user id from the key.  */
1064   xfree (ctx->fpr);
1065   free_strlist (ctx->mboxes);
1066   err = wks_list_key (key, &ctx->fpr, &ctx->mboxes);
1067   if (err)
1068     goto leave;
1069   if (!ctx->fpr)
1070     {
1071       log_error ("error parsing key (no fingerprint)\n");
1072       err = gpg_error (GPG_ERR_NO_PUBKEY);
1073       goto leave;
1074     }
1075   log_info ("fingerprint: %s\n", ctx->fpr);
1076   for (sl = ctx->mboxes; sl; sl = sl->next)
1077     {
1078       log_info ("  addr-spec: %s\n", sl->d);
1079     }
1080
1081   /* Walk over all user ids and send confirmation requests for those
1082    * we support.  */
1083   for (sl = ctx->mboxes; sl; sl = sl->next)
1084     {
1085       s = strchr (sl->d, '@');
1086       log_assert (s && s[1]);
1087       xfree (dname);
1088       dname = make_filename_try (opt.directory, s+1, NULL);
1089       if (!dname)
1090         {
1091           err = gpg_error_from_syserror ();
1092           goto leave;
1093         }
1094
1095       if (access (dname, W_OK))
1096         {
1097           log_info ("skipping address '%s': Domain not configured\n", sl->d);
1098           continue;
1099         }
1100       if (get_policy_flags (&policybuf, sl->d))
1101         {
1102           log_info ("skipping address '%s': Bad policy flags\n", sl->d);
1103           continue;
1104         }
1105
1106       if (policybuf.auth_submit)
1107         {
1108           /* Bypass the confirmation stuff and publish the key as is.  */
1109           log_info ("publishing address '%s'\n", sl->d);
1110           /* FIXME: We need to make sure that we do this only for the
1111            * address in the mail.  */
1112           log_debug ("auth-submit not yet working!\n");
1113         }
1114       else
1115         {
1116           log_info ("storing address '%s'\n", sl->d);
1117
1118           xfree (nonce);
1119           xfree (fname);
1120           err = store_key_as_pending (dname, key, &nonce, &fname);
1121           if (err)
1122             goto leave;
1123
1124           err = send_confirmation_request (ctx, sl->d, nonce, fname);
1125           if (err)
1126             goto leave;
1127         }
1128     }
1129
1130  leave:
1131   if (nonce)
1132     wipememory (nonce, strlen (nonce));
1133   xfree (nonce);
1134   xfree (fname);
1135   xfree (dname);
1136   return err;
1137 }
1138
1139
1140 \f
1141 /* Send a message to tell the user at MBOX that their key has been
1142  * published.  FNAME the name of the file with the key.  */
1143 static gpg_error_t
1144 send_congratulation_message (const char *mbox, const char *keyfile)
1145 {
1146   gpg_error_t err;
1147   estream_t body = NULL;
1148   estream_t bodyenc = NULL;
1149   mime_maker_t mime = NULL;
1150   char *from_buffer = NULL;
1151   const char *from;
1152   strlist_t sl;
1153
1154   from = from_buffer = get_submission_address (mbox);
1155   if (!from)
1156     {
1157       from = opt.default_from;
1158       if (!from)
1159         {
1160           log_error ("no sender address found for '%s'\n", mbox);
1161           err = gpg_error (GPG_ERR_CONFIGURATION);
1162           goto leave;
1163         }
1164       log_info ("Note: using default sender address '%s'\n", from);
1165     }
1166
1167   body = es_fopenmem (0, "w+b");
1168   if (!body)
1169     {
1170       err = gpg_error_from_syserror ();
1171       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
1172       goto leave;
1173     }
1174   /* It is fine to use 8 bit encoding because that is encrypted and
1175    * only our client will see it.  */
1176   es_fputs ("Content-Type: text/plain; charset=utf-8\n"
1177             "Content-Transfer-Encoding: 8bit\n"
1178             "\n",
1179             body);
1180
1181   es_fprintf (body,
1182               "Hello!\n\n"
1183               "The key for your address '%s' has been published\n"
1184               "and can now be retrieved from the Web Key Directory.\n"
1185               "\n"
1186               "For more information on this system see:\n"
1187               "\n"
1188               "  https://gnupg.org/faq/wkd.html\n"
1189               "\n"
1190               "Best regards\n"
1191               "\n"
1192               "  Gnu Key Publisher\n\n\n"
1193               "-- \n"
1194               "The GnuPG Project welcomes donations: %s\n",
1195               mbox, "https://gnupg.org/donate");
1196
1197   es_rewind (body);
1198   err = encrypt_stream (&bodyenc, body, keyfile);
1199   if (err)
1200     goto leave;
1201   es_fclose (body);
1202   body = NULL;
1203
1204   err = mime_maker_new (&mime, NULL);
1205   if (err)
1206     goto leave;
1207   err = mime_maker_add_header (mime, "From", from);
1208   if (err)
1209     goto leave;
1210   err = mime_maker_add_header (mime, "To", mbox);
1211   if (err)
1212     goto leave;
1213   err = mime_maker_add_header (mime, "Subject", "Your key has been published");
1214   if (err)
1215     goto leave;
1216   err = mime_maker_add_header (mime, "WKS-Phase", "done");
1217   if (err)
1218     goto leave;
1219   for (sl = opt.extra_headers; sl; sl = sl->next)
1220     {
1221       err = mime_maker_add_header (mime, sl->d, NULL);
1222       if (err)
1223         goto leave;
1224     }
1225
1226   err = mime_maker_add_header (mime, "Content-Type",
1227                                "multipart/encrypted; "
1228                                "protocol=\"application/pgp-encrypted\"");
1229   if (err)
1230     goto leave;
1231   err = mime_maker_add_container (mime);
1232   if (err)
1233     goto leave;
1234
1235   err = mime_maker_add_header (mime, "Content-Type",
1236                                "application/pgp-encrypted");
1237   if (err)
1238     goto leave;
1239   err = mime_maker_add_body (mime, "Version: 1\n");
1240   if (err)
1241     goto leave;
1242   err = mime_maker_add_header (mime, "Content-Type",
1243                                "application/octet-stream");
1244   if (err)
1245     goto leave;
1246
1247   err = mime_maker_add_stream (mime, &bodyenc);
1248   if (err)
1249     goto leave;
1250
1251   err = wks_send_mime (mime);
1252
1253  leave:
1254   mime_maker_release (mime);
1255   es_fclose (bodyenc);
1256   es_fclose (body);
1257   xfree (from_buffer);
1258   return err;
1259 }
1260
1261
1262 /* Check that we have send a request with NONCE and publish the key.  */
1263 static gpg_error_t
1264 check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
1265 {
1266   gpg_error_t err;
1267   char *fname = NULL;
1268   char *fnewname = NULL;
1269   estream_t key = NULL;
1270   char *hash = NULL;
1271   const char *domain;
1272   const char *s;
1273   strlist_t sl;
1274   char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
1275
1276   /* FIXME: There is a bug in name-value.c which adds white space for
1277    * the last pair and thus we strip the nonce here until this has
1278    * been fixed.  */
1279   char *nonce2 = xstrdup (nonce);
1280   trim_trailing_spaces (nonce2);
1281   nonce = nonce2;
1282
1283
1284   domain = strchr (address, '@');
1285   log_assert (domain && domain[1]);
1286   domain++;
1287   fname = make_filename_try (opt.directory, domain, "pending", nonce, NULL);
1288   if (!fname)
1289     {
1290       err = gpg_error_from_syserror ();
1291       goto leave;
1292     }
1293
1294   /* Try to open the file with the key.  */
1295   key = es_fopen (fname, "rb");
1296   if (!key)
1297     {
1298       err = gpg_error_from_syserror ();
1299       if (gpg_err_code (err) == GPG_ERR_ENOENT)
1300         {
1301           log_info ("no pending request for '%s'\n", address);
1302           err = gpg_error (GPG_ERR_NOT_FOUND);
1303         }
1304       else
1305         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
1306       goto leave;
1307     }
1308
1309   /* We need to get the fingerprint from the key.  */
1310   xfree (ctx->fpr);
1311   free_strlist (ctx->mboxes);
1312   err = wks_list_key (key, &ctx->fpr, &ctx->mboxes);
1313   if (err)
1314     goto leave;
1315   if (!ctx->fpr)
1316     {
1317       log_error ("error parsing key (no fingerprint)\n");
1318       err = gpg_error (GPG_ERR_NO_PUBKEY);
1319       goto leave;
1320     }
1321   log_info ("fingerprint: %s\n", ctx->fpr);
1322   for (sl = ctx->mboxes; sl; sl = sl->next)
1323     log_info ("  addr-spec: %s\n", sl->d);
1324
1325   /* Check that the key has 'address' as a user id.  We use
1326    * case-insensitive matching because the client is expected to
1327    * return the address verbatim.  */
1328   for (sl = ctx->mboxes; sl; sl = sl->next)
1329     if (!strcmp (sl->d, address))
1330       break;
1331   if (!sl)
1332     {
1333       log_error ("error publishing key: '%s' is not a user ID of %s\n",
1334                  address, ctx->fpr);
1335       err = gpg_error (GPG_ERR_NO_PUBKEY);
1336       goto leave;
1337     }
1338
1339
1340   /* Hash user ID and create filename.  */
1341   s = strchr (address, '@');
1342   log_assert (s);
1343   gcry_md_hash_buffer (GCRY_MD_SHA1, shaxbuf, address, s - address);
1344   hash = zb32_encode (shaxbuf, 8*20);
1345   if (!hash)
1346     {
1347       err = gpg_error_from_syserror ();
1348       goto leave;
1349     }
1350
1351   fnewname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
1352   if (!fnewname)
1353     {
1354       err = gpg_error_from_syserror ();
1355       goto leave;
1356     }
1357
1358   /* Publish.  */
1359   err = copy_key_as_binary (fname, fnewname, address);
1360   if (err)
1361     {
1362       err = gpg_error_from_syserror ();
1363       log_error ("copying '%s' to '%s' failed: %s\n",
1364                  fname, fnewname, gpg_strerror (err));
1365       goto leave;
1366     }
1367
1368   log_info ("key %s published for '%s'\n", ctx->fpr, address);
1369   send_congratulation_message (address, fnewname);
1370
1371   /* Try to publish as DANE record if the DANE directory exists.  */
1372   xfree (fname);
1373   fname = fnewname;
1374   fnewname = make_filename_try (opt.directory, domain, "dane", NULL);
1375   if (!fnewname)
1376     {
1377       err = gpg_error_from_syserror ();
1378       goto leave;
1379     }
1380   if (!access (fnewname, W_OK))
1381     {
1382       /* Yes, we have a dane directory.  */
1383       s = strchr (address, '@');
1384       log_assert (s);
1385       gcry_md_hash_buffer (GCRY_MD_SHA256, shaxbuf, address, s - address);
1386       xfree (hash);
1387       hash = bin2hex (shaxbuf, 28, NULL);
1388       if (!hash)
1389         {
1390           err = gpg_error_from_syserror ();
1391           goto leave;
1392         }
1393       xfree (fnewname);
1394       fnewname = make_filename_try (opt.directory, domain, "dane", hash, NULL);
1395       if (!fnewname)
1396         {
1397           err = gpg_error_from_syserror ();
1398           goto leave;
1399         }
1400       err = copy_key_as_dane (fname, fnewname);
1401       if (err)
1402         goto leave;
1403       log_info ("key %s published for '%s' (DANE record)\n", ctx->fpr, address);
1404     }
1405
1406  leave:
1407   es_fclose (key);
1408   xfree (hash);
1409   xfree (fnewname);
1410   xfree (fname);
1411   xfree (nonce2);
1412   return err;
1413 }
1414
1415
1416 /* Process a confirmation response in MSG.  */
1417 static gpg_error_t
1418 process_confirmation_response (server_ctx_t ctx, estream_t msg)
1419 {
1420   gpg_error_t err;
1421   nvc_t nvc;
1422   nve_t item;
1423   const char *value, *sender, *address, *nonce;
1424
1425   err = nvc_parse (&nvc, NULL, msg);
1426   if (err)
1427     {
1428       log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
1429       goto leave;
1430     }
1431
1432   if (opt.debug)
1433     {
1434       log_debug ("response follows:\n");
1435       nvc_write (nvc, log_get_stream ());
1436     }
1437
1438   /* Check that this is a confirmation response.  */
1439   if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
1440         && !strcmp (value, "confirmation-response")))
1441     {
1442       if (item && value)
1443         log_error ("received unexpected wks message '%s'\n", value);
1444       else
1445         log_error ("received invalid wks message: %s\n", "'type' missing");
1446       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1447       goto leave;
1448     }
1449
1450   /* Get the sender.  */
1451   if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
1452         && is_valid_mailbox (value)))
1453     {
1454       log_error ("received invalid wks message: %s\n",
1455                  "'sender' missing or invalid");
1456       err = gpg_error (GPG_ERR_INV_DATA);
1457       goto leave;
1458     }
1459   sender = value;
1460   (void)sender;
1461   /* FIXME: Do we really need the sender?.  */
1462
1463   /* Get the address.  */
1464   if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
1465         && is_valid_mailbox (value)))
1466     {
1467       log_error ("received invalid wks message: %s\n",
1468                  "'address' missing or invalid");
1469       err = gpg_error (GPG_ERR_INV_DATA);
1470       goto leave;
1471     }
1472   address = value;
1473
1474   /* Get the nonce.  */
1475   if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
1476         && strlen (value) > 16))
1477     {
1478       log_error ("received invalid wks message: %s\n",
1479                  "'nonce' missing or too short");
1480       err = gpg_error (GPG_ERR_INV_DATA);
1481       goto leave;
1482     }
1483   nonce = value;
1484
1485   err = check_and_publish (ctx, address, nonce);
1486
1487
1488  leave:
1489   nvc_release (nvc);
1490   return err;
1491 }
1492
1493
1494 \f
1495 /* Called from the MIME receiver to process the plain text data in MSG .  */
1496 static gpg_error_t
1497 command_receive_cb (void *opaque, const char *mediatype,
1498                     estream_t msg, unsigned int flags)
1499 {
1500   gpg_error_t err;
1501   struct server_ctx_s ctx;
1502
1503   (void)opaque;
1504
1505   memset (&ctx, 0, sizeof ctx);
1506   if ((flags & WKS_RECEIVE_DRAFT2))
1507     ctx.draft_version_2 = 1;
1508
1509   if (!strcmp (mediatype, "application/pgp-keys"))
1510     err = process_new_key (&ctx, msg);
1511   else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
1512     err = process_confirmation_response (&ctx, msg);
1513   else
1514     {
1515       log_info ("ignoring unexpected message of type '%s'\n", mediatype);
1516       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1517     }
1518
1519   xfree (ctx.fpr);
1520   free_strlist (ctx.mboxes);
1521
1522   return err;
1523 }
1524
1525
1526 \f
1527 /* Return a list of all configured domains.  ECh list element is the
1528  * top directory for the domain.  To figure out the actual domain
1529  * name strrchr(name, '/') can be used.  */
1530 static gpg_error_t
1531 get_domain_list (strlist_t *r_list)
1532 {
1533   gpg_error_t err;
1534   DIR *dir = NULL;
1535   char *fname = NULL;
1536   struct dirent *dentry;
1537   struct stat sb;
1538   strlist_t list = NULL;
1539
1540   *r_list = NULL;
1541
1542   dir = opendir (opt.directory);
1543   if (!dir)
1544     {
1545       err = gpg_error_from_syserror ();
1546       goto leave;
1547     }
1548
1549   while ((dentry = readdir (dir)))
1550     {
1551       if (*dentry->d_name == '.')
1552         continue;
1553       if (!strchr (dentry->d_name, '.'))
1554         continue; /* No dot - can't be a domain subdir.  */
1555
1556       xfree (fname);
1557       fname = make_filename_try (opt.directory, dentry->d_name, NULL);
1558       if (!fname)
1559         {
1560           err = gpg_error_from_syserror ();
1561           log_error ("make_filename failed in %s: %s\n",
1562                      __func__, gpg_strerror (err));
1563           goto leave;
1564         }
1565
1566       if (stat (fname, &sb))
1567         {
1568           err = gpg_error_from_syserror ();
1569           log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
1570           continue;
1571         }
1572       if (!S_ISDIR(sb.st_mode))
1573         continue;
1574
1575       if (!add_to_strlist_try (&list, fname))
1576         {
1577           err = gpg_error_from_syserror ();
1578           log_error ("add_to_strlist failed in %s: %s\n",
1579                      __func__, gpg_strerror (err));
1580           goto leave;
1581         }
1582     }
1583   err = 0;
1584   *r_list = list;
1585   list = NULL;
1586
1587  leave:
1588   free_strlist (list);
1589   if (dir)
1590     closedir (dir);
1591   xfree (fname);
1592   return err;
1593 }
1594
1595
1596 \f
1597 static gpg_error_t
1598 expire_one_domain (const char *top_dirname, const char *domain)
1599 {
1600   gpg_error_t err;
1601   char *dirname;
1602   char *fname = NULL;
1603   DIR *dir = NULL;
1604   struct dirent *dentry;
1605   struct stat sb;
1606   time_t now = gnupg_get_time ();
1607
1608   dirname = make_filename_try (top_dirname, "pending", NULL);
1609   if (!dirname)
1610     {
1611       err = gpg_error_from_syserror ();
1612       log_error ("make_filename failed in %s: %s\n",
1613                  __func__, gpg_strerror (err));
1614       goto leave;
1615     }
1616
1617   dir = opendir (dirname);
1618   if (!dir)
1619     {
1620       err = gpg_error_from_syserror ();
1621       log_error (("can't access directory '%s': %s\n"),
1622                  dirname, gpg_strerror (err));
1623       goto leave;
1624     }
1625
1626   while ((dentry = readdir (dir)))
1627     {
1628       if (*dentry->d_name == '.')
1629         continue;
1630       xfree (fname);
1631       fname = make_filename_try (dirname, dentry->d_name, NULL);
1632       if (!fname)
1633         {
1634           err = gpg_error_from_syserror ();
1635           log_error ("make_filename failed in %s: %s\n",
1636                      __func__, gpg_strerror (err));
1637           goto leave;
1638         }
1639       if (strlen (dentry->d_name) != 32)
1640         {
1641           log_info ("garbage file '%s' ignored\n", fname);
1642           continue;
1643         }
1644       if (stat (fname, &sb))
1645         {
1646           err = gpg_error_from_syserror ();
1647           log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
1648           continue;
1649         }
1650       if (S_ISDIR(sb.st_mode))
1651         {
1652           log_info ("garbage directory '%s' ignored\n", fname);
1653           continue;
1654         }
1655       if (sb.st_mtime + PENDING_TTL < now)
1656         {
1657           if (opt.verbose)
1658             log_info ("domain %s: removing pending key '%s'\n",
1659                       domain, dentry->d_name);
1660           if (remove (fname))
1661             {
1662               err = gpg_error_from_syserror ();
1663               /* In case the file has just been renamed or another
1664                * processes is cleaning up, we don't print a diagnostic
1665                * for ENOENT.  */
1666               if (gpg_err_code (err) != GPG_ERR_ENOENT)
1667                 log_error ("error removing '%s': %s\n",
1668                            fname, gpg_strerror (err));
1669             }
1670         }
1671     }
1672   err = 0;
1673
1674  leave:
1675   if (dir)
1676     closedir (dir);
1677   xfree (dirname);
1678   xfree (fname);
1679   return err;
1680
1681 }
1682
1683
1684 /* Scan spool directories and expire too old pending keys.  */
1685 static gpg_error_t
1686 expire_pending_confirmations (strlist_t domaindirs)
1687 {
1688   gpg_error_t err = 0;
1689   strlist_t sl;
1690   const char *domain;
1691
1692   for (sl = domaindirs; sl; sl = sl->next)
1693     {
1694       domain = strrchr (sl->d, '/');
1695       log_assert (domain);
1696       domain++;
1697
1698       expire_one_domain (sl->d, domain);
1699     }
1700
1701   return err;
1702 }
1703
1704
1705 /* List all configured domains.  */
1706 static gpg_error_t
1707 command_list_domains (void)
1708 {
1709   static struct {
1710     const char *name;
1711     const char *perm;
1712   } requireddirs[] = {
1713     { "pending", "-rwx" },
1714     { "hu",      "-rwxr-xr-x" }
1715   };
1716
1717   gpg_error_t err;
1718   strlist_t domaindirs;
1719   strlist_t sl;
1720   const char *domain;
1721   char *fname = NULL;
1722   int i;
1723   estream_t fp;
1724
1725   err = get_domain_list (&domaindirs);
1726   if (err)
1727     {
1728       log_error ("error reading list of domains: %s\n", gpg_strerror (err));
1729       return err;
1730     }
1731
1732   for (sl = domaindirs; sl; sl = sl->next)
1733     {
1734       domain = strrchr (sl->d, '/');
1735       log_assert (domain);
1736       domain++;
1737       es_printf ("%s\n", domain);
1738
1739       /* Check that the required directories are there.  */
1740       for (i=0; i < DIM (requireddirs); i++)
1741         {
1742           xfree (fname);
1743           fname = make_filename_try (sl->d, requireddirs[i].name, NULL);
1744           if (!fname)
1745             {
1746               err = gpg_error_from_syserror ();
1747               goto leave;
1748             }
1749           if (access (fname, W_OK))
1750             {
1751               err = gpg_error_from_syserror ();
1752               if (gpg_err_code (err) == GPG_ERR_ENOENT)
1753                 {
1754                   if (gnupg_mkdir (fname, requireddirs[i].perm))
1755                     {
1756                       err = gpg_error_from_syserror ();
1757                       log_error ("domain %s: error creating subdir '%s': %s\n",
1758                                  domain, requireddirs[i].name,
1759                                  gpg_strerror (err));
1760                     }
1761                   else
1762                     log_info ("domain %s: subdir '%s' created\n",
1763                               domain, requireddirs[i].name);
1764                 }
1765               else if (err)
1766                 log_error ("domain %s: problem with subdir '%s': %s\n",
1767                            domain, requireddirs[i].name, gpg_strerror (err));
1768             }
1769         }
1770
1771       /* Print a warning if the submission address is not configured.  */
1772       xfree (fname);
1773       fname = make_filename_try (sl->d, "submission-address", NULL);
1774       if (!fname)
1775         {
1776           err = gpg_error_from_syserror ();
1777           goto leave;
1778         }
1779       if (access (fname, F_OK))
1780         {
1781           err = gpg_error_from_syserror ();
1782           if (gpg_err_code (err) == GPG_ERR_ENOENT)
1783             log_error ("domain %s: submission address not configured\n",
1784                        domain);
1785           else
1786             log_error ("domain %s: problem with '%s': %s\n",
1787                        domain, fname, gpg_strerror (err));
1788         }
1789
1790       /* Check the syntax of the optional policy file.  */
1791       xfree (fname);
1792       fname = make_filename_try (sl->d, "policy", NULL);
1793       if (!fname)
1794         {
1795           err = gpg_error_from_syserror ();
1796           goto leave;
1797         }
1798       fp = es_fopen (fname, "r");
1799       if (!fp)
1800         {
1801           err = gpg_error_from_syserror ();
1802           if (gpg_err_code (err) != GPG_ERR_ENOENT)
1803             log_error ("domain %s: error in policy file: %s\n",
1804                        domain, gpg_strerror (err));
1805         }
1806       else
1807         {
1808           struct policy_flags_s policy;
1809           err = wks_parse_policy (&policy, fp, 0);
1810           es_fclose (fp);
1811           if (!err)
1812             {
1813               struct policy_flags_s empty_policy;
1814               memset (&empty_policy, 0, sizeof empty_policy);
1815               if (!memcmp (&empty_policy, &policy, sizeof policy))
1816                 log_error ("domain %s: empty policy file\n", domain);
1817             }
1818         }
1819
1820
1821     }
1822   err = 0;
1823
1824  leave:
1825   xfree (fname);
1826   free_strlist (domaindirs);
1827   return err;
1828 }
1829
1830
1831 /* Run regular maintenance jobs.  */
1832 static gpg_error_t
1833 command_cron (void)
1834 {
1835   gpg_error_t err;
1836   strlist_t domaindirs;
1837
1838   err = get_domain_list (&domaindirs);
1839   if (err)
1840     {
1841       log_error ("error reading list of domains: %s\n", gpg_strerror (err));
1842       return err;
1843     }
1844
1845   err = expire_pending_confirmations (domaindirs);
1846
1847   free_strlist (domaindirs);
1848   return err;
1849 }