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