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