wks: Add --cron command to gpg-wks-server.
[gnupg.git] / tools / gpg-wks-server.c
1 /* gpg-wks-server.c - A server for the Web Key Service protocols.
2  * Copyright (C) 2016 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* The Web Key Service I-D defines an update protocol to stpre a
21  * public key in the Web Key Directory.  The current specification is
22  * draft-koch-openpgp-webkey-service-01.txt.
23  */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
33
34 #include "util.h"
35 #include "init.h"
36 #include "sysutils.h"
37 #include "ccparray.h"
38 #include "exectool.h"
39 #include "zb32.h"
40 #include "mbox-util.h"
41 #include "name-value.h"
42 #include "mime-maker.h"
43 #include "send-mail.h"
44 #include "gpg-wks.h"
45
46
47 /* The time we wait for a confirmation response.  */
48 #define PENDING_TTL (86400 * 3)  /* 3 days.  */
49
50
51 /* Constants to identify the commands and options. */
52 enum cmd_and_opt_values
53   {
54     aNull = 0,
55
56     oQuiet      = 'q',
57     oVerbose    = 'v',
58     oOutput     = 'o',
59
60     oDebug      = 500,
61
62     aReceive,
63     aCron,
64
65     oGpgProgram,
66     oSend,
67     oFrom,
68     oHeader,
69
70     oDummy
71   };
72
73
74 /* The list of commands and options. */
75 static ARGPARSE_OPTS opts[] = {
76   ARGPARSE_group (300, ("@Commands:\n ")),
77
78   ARGPARSE_c (aReceive,   "receive",
79               ("receive a submission or confirmation")),
80   ARGPARSE_c (aCron,      "cron",
81               ("run regular jobs")),
82
83   ARGPARSE_group (301, ("@\nOptions:\n ")),
84
85   ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
86   ARGPARSE_s_n (oQuiet, "quiet",  ("be somewhat more quiet")),
87   ARGPARSE_s_s (oDebug, "debug", "@"),
88   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
89   ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
90   ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
91   ARGPARSE_s_s (oFrom, "from", "|ADDR|use ADDR as the default sender"),
92   ARGPARSE_s_s (oHeader, "header" ,
93                 "|NAME=VALUE|add \"NAME: VALUE\" as header to all mails"),
94
95   ARGPARSE_end ()
96 };
97
98
99 /* The list of supported debug flags.  */
100 static struct debug_flags_s debug_flags [] =
101   {
102     { DBG_CRYPTO_VALUE , "crypto"  },
103     { DBG_MEMORY_VALUE , "memory"  },
104     { DBG_MEMSTAT_VALUE, "memstat" },
105     { DBG_IPC_VALUE    , "ipc"     },
106     { DBG_EXTPROG_VALUE, "extprog" },
107     { 0, NULL }
108   };
109
110
111 /* State for processing a message.  */
112 struct server_ctx_s
113 {
114   char *fpr;
115   strlist_t mboxes;  /* List of addr-specs taken from the UIDs.  */
116 };
117 typedef struct server_ctx_s *server_ctx_t;
118
119
120
121 static gpg_error_t command_receive_cb (void *opaque,
122                                        const char *mediatype, estream_t fp);
123 static gpg_error_t command_cron (void);
124
125
126 \f
127 /* Print usage information and and provide strings for help. */
128 static const char *
129 my_strusage( int level )
130 {
131   const char *p;
132
133   switch (level)
134     {
135     case 11: p = "gpg-wks-server (@GNUPG@)";
136       break;
137     case 13: p = VERSION; break;
138     case 17: p = PRINTABLE_OS_NAME; break;
139     case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
140
141     case 1:
142     case 40:
143       p = ("Usage: gpg-wks-server command [options] (-h for help)");
144       break;
145     case 41:
146       p = ("Syntax: gpg-wks-server command [options]\n"
147            "Server for the Web Key Service protocol\n");
148       break;
149
150     default: p = NULL; break;
151     }
152   return p;
153 }
154
155
156 static void
157 wrong_args (const char *text)
158 {
159   es_fprintf (es_stderr, "usage: %s [options] %s\n", strusage (11), text);
160   exit (2);
161 }
162
163
164 \f
165 /* Command line parsing.  */
166 static enum cmd_and_opt_values
167 parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
168 {
169   enum cmd_and_opt_values cmd = 0;
170   int no_more_options = 0;
171
172   while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
173     {
174       switch (pargs->r_opt)
175         {
176         case oQuiet:     opt.quiet = 1; break;
177         case oVerbose:   opt.verbose++; break;
178         case oDebug:
179           if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
180             {
181               pargs->r_opt = ARGPARSE_INVALID_ARG;
182               pargs->err = ARGPARSE_PRINT_ERROR;
183             }
184           break;
185
186         case oGpgProgram:
187           opt.gpg_program = pargs->r.ret_str;
188           break;
189         case oFrom:
190           opt.default_from = pargs->r.ret_str;
191           break;
192         case oHeader:
193           append_to_strlist (&opt.extra_headers, pargs->r.ret_str);
194           break;
195         case oSend:
196           opt.use_sendmail = 1;
197           break;
198         case oOutput:
199           opt.output = pargs->r.ret_str;
200           break;
201
202         case aReceive:
203         case aCron:
204           cmd = pargs->r_opt;
205           break;
206
207         default: pargs->err = 2; break;
208         }
209     }
210
211   return cmd;
212 }
213
214
215 \f
216 /* gpg-wks-server main. */
217 int
218 main (int argc, char **argv)
219 {
220   gpg_error_t err;
221   ARGPARSE_ARGS pargs;
222   enum cmd_and_opt_values cmd;
223
224   gnupg_reopen_std ("gpg-wks-server");
225   set_strusage (my_strusage);
226   log_set_prefix ("gpg-wks-server", GPGRT_LOG_WITH_PREFIX);
227
228   /* Make sure that our subsystems are ready.  */
229   init_common_subsystems (&argc, &argv);
230
231   /* Parse the command line. */
232   pargs.argc  = &argc;
233   pargs.argv  = &argv;
234   pargs.flags = ARGPARSE_FLAG_KEEP;
235   cmd = parse_arguments (&pargs, opts);
236
237   if (log_get_errorcount (0))
238     exit (2);
239
240   /* Print a warning if an argument looks like an option.  */
241   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
242     {
243       int i;
244
245       for (i=0; i < argc; i++)
246         if (argv[i][0] == '-' && argv[i][1] == '-')
247           log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
248     }
249
250   /* Set defaults for non given options.  */
251   if (!opt.gpg_program)
252     opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
253
254   if (!opt.directory)
255     opt.directory = "/var/lib/gnupg/wks";
256
257   /* Check for syntax errors in the --header option to avoid later
258    * error messages with a not easy to find cause */
259   if (opt.extra_headers)
260     {
261       strlist_t sl;
262
263       for (sl = opt.extra_headers; sl; sl = sl->next)
264         {
265           err = mime_maker_add_header (NULL, sl->d, NULL);
266           if (err)
267             log_error ("syntax error in \"--header %s\": %s\n",
268                        sl->d, gpg_strerror (err));
269         }
270     }
271
272   if (log_get_errorcount (0))
273     exit (2);
274
275
276   /* Check that we have a working directory.  */
277 #if defined(HAVE_STAT)
278   {
279     struct stat sb;
280
281     if (stat (opt.directory, &sb))
282       {
283         err = gpg_error_from_syserror ();
284         log_error ("error accessing directory '%s': %s\n",
285                    opt.directory, gpg_strerror (err));
286         exit (2);
287       }
288     if (!S_ISDIR(sb.st_mode))
289       {
290         log_error ("error accessing directory '%s': %s\n",
291                    opt.directory, "not a directory");
292         exit (2);
293       }
294     if (sb.st_uid != getuid())
295       {
296         log_error ("directory '%s' not owned by user\n", opt.directory);
297         exit (2);
298       }
299     if ((sb.st_mode & S_IRWXO))
300       {
301         log_error ("directory '%s' has too relaxed permissions\n",
302                    opt.directory);
303         exit (2);
304       }
305   }
306 #else /*!HAVE_STAT*/
307   log_fatal ("program build w/o stat() call\n");
308 #endif /*!HAVE_STAT*/
309
310   /* Run the selected command.  */
311   switch (cmd)
312     {
313     case aReceive:
314       if (argc)
315         wrong_args ("--receive");
316       err = wks_receive (es_stdin, command_receive_cb, NULL);
317       if (err)
318         log_error ("processing mail failed: %s\n", gpg_strerror (err));
319       break;
320
321     case aCron:
322       if (argc)
323         wrong_args ("--cron");
324       err = command_cron ();
325       if (err)
326         log_error ("running --cron failed: %s\n", gpg_strerror (err));
327       break;
328
329     default:
330       usage (1);
331       break;
332     }
333
334   return log_get_errorcount (0)? 1:0;
335 }
336
337
338 \f
339 static void
340 list_key_status_cb (void *opaque, const char *keyword, char *args)
341 {
342   server_ctx_t ctx = opaque;
343   (void)ctx;
344   if (opt.debug)
345     log_debug ("%s: %s\n", keyword, args);
346 }
347
348
349 static gpg_error_t
350 list_key (server_ctx_t ctx, estream_t key)
351 {
352   gpg_error_t err;
353   ccparray_t ccp;
354   const char **argv;
355   estream_t listing;
356   char *line = NULL;
357   size_t length_of_line = 0;
358   size_t  maxlen;
359   ssize_t len;
360   char **fields = NULL;
361   int nfields;
362   int lnr;
363   char *mbox = NULL;
364
365   /* We store our results in the context - clear it first.  */
366   xfree (ctx->fpr);
367   ctx->fpr = NULL;
368   free_strlist (ctx->mboxes);
369   ctx->mboxes = NULL;
370
371   /* Open a memory stream.  */
372   listing = es_fopenmem (0, "w+b");
373   if (!listing)
374     {
375       err = gpg_error_from_syserror ();
376       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
377       return err;
378     }
379
380   ccparray_init (&ccp, 0);
381
382   ccparray_put (&ccp, "--no-options");
383   if (!opt.verbose)
384     ccparray_put (&ccp, "--quiet");
385   else if (opt.verbose > 1)
386     ccparray_put (&ccp, "--verbose");
387   ccparray_put (&ccp, "--batch");
388   ccparray_put (&ccp, "--status-fd=2");
389   ccparray_put (&ccp, "--always-trust");
390   ccparray_put (&ccp, "--with-colons");
391   ccparray_put (&ccp, "--dry-run");
392   ccparray_put (&ccp, "--import-options=import-minimal,import-show");
393   ccparray_put (&ccp, "--import");
394
395   ccparray_put (&ccp, NULL);
396   argv = ccparray_get (&ccp, NULL);
397   if (!argv)
398     {
399       err = gpg_error_from_syserror ();
400       goto leave;
401     }
402   err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
403                                 NULL, listing,
404                                 list_key_status_cb, ctx);
405   if (err)
406     {
407       log_error ("import failed: %s\n", gpg_strerror (err));
408       goto leave;
409     }
410
411   es_rewind (listing);
412   lnr = 0;
413   maxlen = 2048; /* Set limit.  */
414   while ((len = es_read_line (listing, &line, &length_of_line, &maxlen)) > 0)
415     {
416       lnr++;
417       if (!maxlen)
418         {
419           log_error ("received line too long\n");
420           err = gpg_error (GPG_ERR_LINE_TOO_LONG);
421           goto leave;
422         }
423       /* Strip newline and carriage return, if present.  */
424       while (len > 0
425              && (line[len - 1] == '\n' || line[len - 1] == '\r'))
426         line[--len] = '\0';
427       /* log_debug ("line '%s'\n", line); */
428
429       xfree (fields);
430       fields = strtokenize (line, ":");
431       if (!fields)
432         {
433           err = gpg_error_from_syserror ();
434           log_error ("strtokenize failed: %s\n", gpg_strerror (err));
435           goto leave;
436         }
437       for (nfields = 0; fields[nfields]; nfields++)
438         ;
439       if (!nfields)
440         {
441           err = gpg_error (GPG_ERR_INV_ENGINE);
442           goto leave;
443         }
444       if (!strcmp (fields[0], "sec"))
445         {
446           /* gpg may return "sec" as the first record - but we do not
447            * accept secret keys.  */
448           err = gpg_error (GPG_ERR_NO_PUBKEY);
449           goto leave;
450         }
451       if (lnr == 1 && strcmp (fields[0], "pub"))
452         {
453           /* First record is not a public key.  */
454           err = gpg_error (GPG_ERR_INV_ENGINE);
455           goto leave;
456         }
457       if (lnr > 1 && !strcmp (fields[0], "pub"))
458         {
459           /* More than one public key.  */
460           err = gpg_error (GPG_ERR_TOO_MANY);
461           goto leave;
462         }
463       if (!strcmp (fields[0], "sub") || !strcmp (fields[0], "ssb"))
464         break; /* We can stop parsing here.  */
465
466       if (!strcmp (fields[0], "fpr") && nfields > 9 && !ctx->fpr)
467         {
468           ctx->fpr = xtrystrdup (fields[9]);
469           if (!ctx->fpr)
470             {
471               err = gpg_error_from_syserror ();
472               goto leave;
473             }
474         }
475       else if (!strcmp (fields[0], "uid") && nfields > 9)
476         {
477           /* Fixme: Unescape fields[9] */
478           xfree (mbox);
479           mbox = mailbox_from_userid (fields[9]);
480           if (mbox && !append_to_strlist_try (&ctx->mboxes, mbox))
481             {
482               err = gpg_error_from_syserror ();
483               goto leave;
484             }
485         }
486     }
487   if (len < 0 || es_ferror (listing))
488     log_error ("error reading memory stream\n");
489
490  leave:
491   xfree (mbox);
492   xfree (fields);
493   es_free (line);
494   xfree (argv);
495   es_fclose (listing);
496   return err;
497 }
498
499
500 /* Take the key in KEYFILE and write it to DANEFILE using the DANE
501  * output format. */
502 static gpg_error_t
503 copy_key_as_dane (const char *keyfile, const char *danefile)
504 {
505   gpg_error_t err;
506   ccparray_t ccp;
507   const char **argv;
508
509   ccparray_init (&ccp, 0);
510
511   ccparray_put (&ccp, "--no-options");
512   if (!opt.verbose)
513     ccparray_put (&ccp, "--quiet");
514   else if (opt.verbose > 1)
515     ccparray_put (&ccp, "--verbose");
516   ccparray_put (&ccp, "--batch");
517   ccparray_put (&ccp, "--yes");
518   ccparray_put (&ccp, "--always-trust");
519   ccparray_put (&ccp, "--no-keyring");
520   ccparray_put (&ccp, "--output");
521   ccparray_put (&ccp, danefile);
522   ccparray_put (&ccp, "--export-options=export-dane");
523   ccparray_put (&ccp, "--import-options=import-export");
524   ccparray_put (&ccp, "--import");
525   ccparray_put (&ccp, "--");
526   ccparray_put (&ccp, keyfile);
527
528   ccparray_put (&ccp, NULL);
529   argv = ccparray_get (&ccp, NULL);
530   if (!argv)
531     {
532       err = gpg_error_from_syserror ();
533       goto leave;
534     }
535   err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
536                                 NULL, NULL, NULL, NULL);
537   if (err)
538     {
539       log_error ("%s failed: %s\n", __func__, gpg_strerror (err));
540       goto leave;
541     }
542
543  leave:
544   xfree (argv);
545   return err;
546 }
547
548
549 static void
550 encrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
551 {
552   (void)opaque;
553
554   if (opt.debug)
555     log_debug ("%s: %s\n", keyword, args);
556 }
557
558
559 /* Encrypt the INPUT stream to a new stream which is stored at success
560  * at R_OUTPUT.  Encryption is done for the key in file KEYFIL.  */
561 static gpg_error_t
562 encrypt_stream (estream_t *r_output, estream_t input, const char *keyfile)
563 {
564   gpg_error_t err;
565   ccparray_t ccp;
566   const char **argv;
567   estream_t output;
568
569   *r_output = NULL;
570
571   output = es_fopenmem (0, "w+b");
572   if (!output)
573     {
574       err = gpg_error_from_syserror ();
575       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
576       return err;
577     }
578
579   ccparray_init (&ccp, 0);
580
581   ccparray_put (&ccp, "--no-options");
582   if (!opt.verbose)
583     ccparray_put (&ccp, "--quiet");
584   else if (opt.verbose > 1)
585     ccparray_put (&ccp, "--verbose");
586   ccparray_put (&ccp, "--batch");
587   ccparray_put (&ccp, "--status-fd=2");
588   ccparray_put (&ccp, "--always-trust");
589   ccparray_put (&ccp, "--no-keyring");
590   ccparray_put (&ccp, "--armor");
591   ccparray_put (&ccp, "--recipient-file");
592   ccparray_put (&ccp, keyfile);
593   ccparray_put (&ccp, "--encrypt");
594   ccparray_put (&ccp, "--");
595
596   ccparray_put (&ccp, NULL);
597   argv = ccparray_get (&ccp, NULL);
598   if (!argv)
599     {
600       err = gpg_error_from_syserror ();
601       goto leave;
602     }
603   err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
604                                 NULL, output,
605                                 encrypt_stream_status_cb, NULL);
606   if (err)
607     {
608       log_error ("encryption failed: %s\n", gpg_strerror (err));
609       goto leave;
610     }
611
612   es_rewind (output);
613   *r_output = output;
614   output = NULL;
615
616  leave:
617   es_fclose (output);
618   xfree (argv);
619   return err;
620 }
621
622
623 /* Get the submission address for address MBOX.  Caller must free the
624  * value.  If no address can be found NULL is returned.  */
625 static char *
626 get_submission_address (const char *mbox)
627 {
628   gpg_error_t err;
629   const char *domain;
630   char *fname, *line, *p;
631   size_t n;
632   estream_t fp;
633
634   domain = strchr (mbox, '@');
635   if (!domain)
636     return NULL;
637   domain++;
638
639   fname = make_filename_try (opt.directory, domain, "submission-address", NULL);
640   if (!fname)
641     {
642       err = gpg_error_from_syserror ();
643       log_error ("make_filename failed in %s: %s\n",
644                  __func__, gpg_strerror (err));
645       return NULL;
646     }
647
648   fp = es_fopen (fname, "r");
649   if (!fp)
650     {
651       err = gpg_error_from_syserror ();
652       if (gpg_err_code (err) == GPG_ERR_ENOENT)
653         log_info ("Note: no specific submission address configured"
654                   " for domain '%s'\n", domain);
655       else
656         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
657       xfree (fname);
658       return NULL;
659     }
660
661   line = NULL;
662   n = 0;
663   if (es_getline (&line, &n, fp) < 0)
664     {
665       err = gpg_error_from_syserror ();
666       log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
667       xfree (line);
668       es_fclose (fp);
669       xfree (fname);
670       return NULL;
671     }
672   es_fclose (fp);
673   xfree (fname);
674
675   p = strchr (line, '\n');
676   if (p)
677     *p = 0;
678   trim_spaces (line);
679   if (!is_valid_mailbox (line))
680     {
681       log_error ("invalid submission address for domain '%s' detected\n",
682                  domain);
683       xfree (line);
684       return NULL;
685     }
686
687   return line;
688 }
689
690
691 /* We store the key under the name of the nonce we will then send to
692  * the user.  On success the nonce is stored at R_NONCE and the file
693  * name at R_FNAME.  */
694 static gpg_error_t
695 store_key_as_pending (const char *dir, estream_t key,
696                       char **r_nonce, char **r_fname)
697 {
698   gpg_error_t err;
699   char *dname = NULL;
700   char *fname = NULL;
701   char *nonce = NULL;
702   estream_t outfp = NULL;
703   char buffer[1024];
704   size_t nbytes, nwritten;
705
706   *r_nonce = NULL;
707   *r_fname = NULL;
708
709   dname = make_filename_try (dir, "pending", NULL);
710   if (!dname)
711     {
712       err = gpg_error_from_syserror ();
713       goto leave;
714     }
715
716   if (!gnupg_mkdir (dname, "-rwx"))
717     log_info ("directory '%s' created\n", dname);
718
719   /* Create the nonce.  We use 20 bytes so that we don't waste a
720    * character in our zBase-32 encoding.  Using the gcrypt's nonce
721    * function is faster than using the strong random function; this is
722    * Good Enough for our purpose.  */
723   log_assert (sizeof buffer > 20);
724   gcry_create_nonce (buffer, 20);
725   nonce = zb32_encode (buffer, 8 * 20);
726   memset (buffer, 0, 20);  /* Not actually needed but it does not harm. */
727   if (!nonce)
728     {
729       err = gpg_error_from_syserror ();
730       goto leave;
731     }
732
733   fname = strconcat (dname, "/", nonce, NULL);
734   if (!fname)
735     {
736       err = gpg_error_from_syserror ();
737       goto leave;
738     }
739
740   /* With 128 bits of random we can expect that no other file exists
741    * under this name.  We use "x" to detect internal errors.  */
742   outfp = es_fopen (fname, "wbx,mode=-rw");
743   if (!outfp)
744     {
745       err = gpg_error_from_syserror ();
746       log_error ("error creating '%s': %s\n", fname, gpg_strerror (err));
747       goto leave;
748     }
749   es_rewind (key);
750   for (;;)
751     {
752       if (es_read (key, buffer, sizeof buffer, &nbytes))
753         {
754           err = gpg_error_from_syserror ();
755           log_error ("error reading '%s': %s\n",
756                      es_fname_get (key), gpg_strerror (err));
757           break;
758         }
759
760       if (!nbytes)
761         {
762           err = 0;
763           goto leave; /* Ready.  */
764         }
765       if (es_write (outfp, buffer, nbytes, &nwritten))
766         {
767           err = gpg_error_from_syserror ();
768           log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
769           goto leave;
770         }
771       else if (nwritten != nbytes)
772         {
773           err = gpg_error (GPG_ERR_EIO);
774           log_error ("error writing '%s': %s\n", fname, "short write");
775           goto leave;
776         }
777     }
778
779  leave:
780   if (err)
781     {
782       es_fclose (outfp);
783       gnupg_remove (fname);
784     }
785   else if (es_fclose (outfp))
786     {
787       err = gpg_error_from_syserror ();
788       log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
789     }
790
791   if (!err)
792     {
793       *r_nonce = nonce;
794       *r_fname = fname;
795     }
796   else
797     {
798       xfree (nonce);
799       xfree (fname);
800     }
801   xfree (dname);
802   return err;
803 }
804
805
806 /* Send a confirmation rewqyest.  DIR is the directory used for the
807  * address MBOX.  NONCE is the nonce we want to see in the response to
808  * this mail.  FNAME the name of the file with the key.  */
809 static gpg_error_t
810 send_confirmation_request (server_ctx_t ctx,
811                            const char *mbox, const char *nonce,
812                            const char *keyfile)
813 {
814   gpg_error_t err;
815   estream_t body = NULL;
816   estream_t bodyenc = NULL;
817   mime_maker_t mime = NULL;
818   char *from_buffer = NULL;
819   const char *from;
820   strlist_t sl;
821
822   from = from_buffer = get_submission_address (mbox);
823   if (!from)
824     {
825       from = opt.default_from;
826       if (!from)
827         {
828           log_error ("no sender address found for '%s'\n", mbox);
829           err = gpg_error (GPG_ERR_CONFIGURATION);
830           goto leave;
831         }
832       log_info ("Note: using default sender address '%s'\n", from);
833     }
834
835   body = es_fopenmem (0, "w+b");
836   if (!body)
837     {
838       err = gpg_error_from_syserror ();
839       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
840       goto leave;
841     }
842   /* It is fine to use 8 bit encoding because that is encrypted and
843    * only our client will see it.  */
844   es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
845             "Content-Transfer-Encoding: 8bit\n"
846             "\n",
847             body);
848
849   es_fprintf (body, ("type: confirmation-request\n"
850                      "sender: %s\n"
851                      "address: %s\n"
852                      "fingerprint: %s\n"
853                      "nonce: %s\n"),
854               from,
855               mbox,
856               ctx->fpr,
857               nonce);
858
859   es_rewind (body);
860   err = encrypt_stream (&bodyenc, body, keyfile);
861   if (err)
862     goto leave;
863   es_fclose (body);
864   body = NULL;
865
866
867   err = mime_maker_new (&mime, NULL);
868   if (err)
869     goto leave;
870   err = mime_maker_add_header (mime, "From", from);
871   if (err)
872     goto leave;
873   err = mime_maker_add_header (mime, "To", mbox);
874   if (err)
875     goto leave;
876   err = mime_maker_add_header (mime, "Subject", "Confirm your key publication");
877   if (err)
878     goto leave;
879   for (sl = opt.extra_headers; sl; sl = sl->next)
880     {
881       err = mime_maker_add_header (mime, sl->d, NULL);
882       if (err)
883         goto leave;
884     }
885
886   err = mime_maker_add_header (mime, "Content-Type",
887                                "multipart/encrypted; "
888                                "protocol=\"application/pgp-encrypted\"");
889   if (err)
890     goto leave;
891   err = mime_maker_add_container (mime, "multipart/encrypted");
892   if (err)
893     goto leave;
894
895   err = mime_maker_add_header (mime, "Content-Type",
896                                "application/pgp-encrypted");
897   if (err)
898     goto leave;
899   err = mime_maker_add_body (mime, "Version: 1\n");
900   if (err)
901     goto leave;
902   err = mime_maker_add_header (mime, "Content-Type",
903                                "application/octet-stream");
904   if (err)
905     goto leave;
906
907   err = mime_maker_add_stream (mime, &bodyenc);
908   if (err)
909     goto leave;
910
911   err = wks_send_mime (mime);
912
913  leave:
914   mime_maker_release (mime);
915   es_fclose (bodyenc);
916   es_fclose (body);
917   xfree (from_buffer);
918   return err;
919 }
920
921
922 /* Store the key given by KEY into the pending directory and send a
923  * confirmation requests.  */
924 static gpg_error_t
925 process_new_key (server_ctx_t ctx, estream_t key)
926 {
927   gpg_error_t err;
928   strlist_t sl;
929   const char *s;
930   char *dname = NULL;
931   char *nonce = NULL;
932   char *fname = NULL;
933
934   /* First figure out the user id from the key.  */
935   err = list_key (ctx, key);
936   if (err)
937     goto leave;
938   if (!ctx->fpr)
939     {
940       log_error ("error parsing key (no fingerprint)\n");
941       err = gpg_error (GPG_ERR_NO_PUBKEY);
942       goto leave;
943     }
944   log_info ("fingerprint: %s\n", ctx->fpr);
945   for (sl = ctx->mboxes; sl; sl = sl->next)
946     {
947       log_info ("  addr-spec: %s\n", sl->d);
948     }
949
950   /* Walk over all user ids and send confirmation requests for those
951    * we support.  */
952   for (sl = ctx->mboxes; sl; sl = sl->next)
953     {
954       s = strchr (sl->d, '@');
955       log_assert (s && s[1]);
956       xfree (dname);
957       dname = make_filename_try (opt.directory, s+1, NULL);
958       if (!dname)
959         {
960           err = gpg_error_from_syserror ();
961           goto leave;
962         }
963       /* Fixme: check for proper directory permissions.  */
964       if (access (dname, W_OK))
965         {
966           log_info ("skipping address '%s': Domain not configured\n", sl->d);
967           continue;
968         }
969       log_info ("storing address '%s'\n", sl->d);
970
971       xfree (nonce);
972       xfree (fname);
973       err = store_key_as_pending (dname, key, &nonce, &fname);
974       if (err)
975         goto leave;
976
977       err = send_confirmation_request (ctx, sl->d, nonce, fname);
978       if (err)
979         goto leave;
980     }
981
982  leave:
983   if (nonce)
984     wipememory (nonce, strlen (nonce));
985   xfree (nonce);
986   xfree (fname);
987   xfree (dname);
988   return err;
989 }
990
991
992 \f
993 /* Check that we have send a request with NONCE and publish the key.  */
994 static gpg_error_t
995 check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
996 {
997   gpg_error_t err;
998   char *fname = NULL;
999   char *fnewname = NULL;
1000   estream_t key = NULL;
1001   char *hash = NULL;
1002   const char *domain;
1003   const char *s;
1004   strlist_t sl;
1005   char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
1006
1007   /* FIXME: There is a bug in name-value.c which adds white space for
1008    * the last pair and thus we strip the nonce here until this has
1009    * been fixed.  */
1010   char *nonce2 = xstrdup (nonce);
1011   trim_trailing_spaces (nonce2);
1012   nonce = nonce2;
1013
1014
1015   domain = strchr (address, '@');
1016   log_assert (domain && domain[1]);
1017   domain++;
1018   fname = make_filename_try (opt.directory, domain, "pending", nonce, NULL);
1019   if (!fname)
1020     {
1021       err = gpg_error_from_syserror ();
1022       goto leave;
1023     }
1024
1025   /* Try to open the file with the key.  */
1026   key = es_fopen (fname, "rb");
1027   if (!key)
1028     {
1029       err = gpg_error_from_syserror ();
1030       if (gpg_err_code (err) == GPG_ERR_ENOENT)
1031         {
1032           log_info ("no pending request for '%s'\n", address);
1033           err = gpg_error (GPG_ERR_NOT_FOUND);
1034         }
1035       else
1036         log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
1037       goto leave;
1038     }
1039
1040   /* We need to get the fingerprint from the key.  */
1041   err = list_key (ctx, key);
1042   if (err)
1043     goto leave;
1044   if (!ctx->fpr)
1045     {
1046       log_error ("error parsing key (no fingerprint)\n");
1047       err = gpg_error (GPG_ERR_NO_PUBKEY);
1048       goto leave;
1049     }
1050   log_info ("fingerprint: %s\n", ctx->fpr);
1051   for (sl = ctx->mboxes; sl; sl = sl->next)
1052     log_info ("  addr-spec: %s\n", sl->d);
1053
1054   /* Check that the key has 'address' as a user id.  We use
1055    * case-insensitive matching because the client is expected to
1056    * return the address verbatim.  */
1057   for (sl = ctx->mboxes; sl; sl = sl->next)
1058     if (!strcmp (sl->d, address))
1059       break;
1060   if (!sl)
1061     {
1062       log_error ("error publishing key: '%s' is not a user ID of %s\n",
1063                  address, ctx->fpr);
1064       err = gpg_error (GPG_ERR_NO_PUBKEY);
1065       goto leave;
1066     }
1067
1068
1069   /* Hash user ID and create filename.  */
1070   s = strchr (address, '@');
1071   log_assert (s);
1072   gcry_md_hash_buffer (GCRY_MD_SHA1, shaxbuf, address, s - address);
1073   hash = zb32_encode (shaxbuf, 8*20);
1074   if (!hash)
1075     {
1076       err = gpg_error_from_syserror ();
1077       goto leave;
1078     }
1079
1080   {
1081     /*FIXME: This is a hack to make installation easier.  It is better
1082      * to let --cron create the required directories.  */
1083     fnewname = make_filename_try (opt.directory, domain, "hu", NULL);
1084     if (!fnewname)
1085       {
1086         err = gpg_error_from_syserror ();
1087         goto leave;
1088     }
1089     if (!gnupg_mkdir (fnewname, "-rwxr-xr-x"))
1090       log_info ("directory '%s' created\n", fnewname);
1091     xfree (fnewname);
1092   }
1093   fnewname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
1094   if (!fnewname)
1095     {
1096       err = gpg_error_from_syserror ();
1097       goto leave;
1098     }
1099
1100   /* Publish.  */
1101   if (rename (fname, fnewname))
1102     {
1103       err = gpg_error_from_syserror ();
1104       log_error ("renaming '%s' to '%s' failed: %s\n",
1105                  fname, fnewname, gpg_strerror (err));
1106       goto leave;
1107     }
1108
1109   log_info ("key %s published for '%s'\n", ctx->fpr, address);
1110
1111
1112   /* Try to publish as DANE record if the DANE directory exists.  */
1113   xfree (fname);
1114   fname = fnewname;
1115   fnewname = make_filename_try (opt.directory, domain, "dane", NULL);
1116   if (!fnewname)
1117     {
1118       err = gpg_error_from_syserror ();
1119       goto leave;
1120     }
1121   if (!access (fnewname, W_OK))
1122     {
1123       /* Yes, we have a dane directory.  */
1124       s = strchr (address, '@');
1125       log_assert (s);
1126       gcry_md_hash_buffer (GCRY_MD_SHA256, shaxbuf, address, s - address);
1127       xfree (hash);
1128       hash = bin2hex (shaxbuf, 28, NULL);
1129       if (!hash)
1130         {
1131           err = gpg_error_from_syserror ();
1132           goto leave;
1133         }
1134       xfree (fnewname);
1135       fnewname = make_filename_try (opt.directory, domain, "dane", hash, NULL);
1136       if (!fnewname)
1137         {
1138           err = gpg_error_from_syserror ();
1139           goto leave;
1140         }
1141       err = copy_key_as_dane (fname, fnewname);
1142       if (err)
1143         goto leave;
1144       log_info ("key %s published for '%s' (DANE record)\n", ctx->fpr, address);
1145     }
1146
1147
1148  leave:
1149   es_fclose (key);
1150   xfree (hash);
1151   xfree (fnewname);
1152   xfree (fname);
1153   xfree (nonce2);
1154   return err;
1155 }
1156
1157
1158 /* Process a confirmation response in MSG.  */
1159 static gpg_error_t
1160 process_confirmation_response (server_ctx_t ctx, estream_t msg)
1161 {
1162   gpg_error_t err;
1163   nvc_t nvc;
1164   nve_t item;
1165   const char *value, *sender, *address, *nonce;
1166
1167   err = nvc_parse (&nvc, NULL, msg);
1168   if (err)
1169     {
1170       log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
1171       goto leave;
1172     }
1173
1174   if (opt.debug)
1175     {
1176       log_debug ("response follows:\n");
1177       nvc_write (nvc, log_get_stream ());
1178     }
1179
1180   /* Check that this is a confirmation response.  */
1181   if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
1182         && !strcmp (value, "confirmation-response")))
1183     {
1184       if (item && value)
1185         log_error ("received unexpected wks message '%s'\n", value);
1186       else
1187         log_error ("received invalid wks message: %s\n", "'type' missing");
1188       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1189       goto leave;
1190     }
1191
1192   /* Get the sender.  */
1193   if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
1194         && is_valid_mailbox (value)))
1195     {
1196       log_error ("received invalid wks message: %s\n",
1197                  "'sender' missing or invalid");
1198       err = gpg_error (GPG_ERR_INV_DATA);
1199       goto leave;
1200     }
1201   sender = value;
1202   (void)sender;
1203   /* FIXME: Do we really need the sender?.  */
1204
1205   /* Get the address.  */
1206   if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
1207         && is_valid_mailbox (value)))
1208     {
1209       log_error ("received invalid wks message: %s\n",
1210                  "'address' missing or invalid");
1211       err = gpg_error (GPG_ERR_INV_DATA);
1212       goto leave;
1213     }
1214   address = value;
1215
1216   /* Get the nonce.  */
1217   if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
1218         && strlen (value) > 16))
1219     {
1220       log_error ("received invalid wks message: %s\n",
1221                  "'nonce' missing or too short");
1222       err = gpg_error (GPG_ERR_INV_DATA);
1223       goto leave;
1224     }
1225   nonce = value;
1226
1227   err = check_and_publish (ctx, address, nonce);
1228
1229
1230  leave:
1231   nvc_release (nvc);
1232   return err;
1233 }
1234
1235
1236 \f
1237 /* Called from the MIME receiver to process the plain text data in MSG .  */
1238 static gpg_error_t
1239 command_receive_cb (void *opaque, const char *mediatype, estream_t msg)
1240 {
1241   gpg_error_t err;
1242   struct server_ctx_s ctx;
1243
1244   memset (&ctx, 0, sizeof ctx);
1245
1246   (void)opaque;
1247
1248   if (!strcmp (mediatype, "application/pgp-keys"))
1249     err = process_new_key (&ctx, msg);
1250   else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
1251     err = process_confirmation_response (&ctx, msg);
1252   else
1253     {
1254       log_info ("ignoring unexpected message of type '%s'\n", mediatype);
1255       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1256     }
1257
1258   xfree (ctx.fpr);
1259   free_strlist (ctx.mboxes);
1260
1261   return err;
1262 }
1263
1264
1265 \f
1266 static gpg_error_t
1267 expire_one_domain (const char *top_dirname, const char *domain)
1268 {
1269   gpg_error_t err;
1270   char *dirname;
1271   char *fname = NULL;
1272   DIR *dir = NULL;
1273   struct dirent *dentry;
1274   struct stat sb;
1275   time_t now = gnupg_get_time ();
1276
1277   dirname = make_filename_try (top_dirname, "pending", NULL);
1278   if (!dirname)
1279     {
1280       err = gpg_error_from_syserror ();
1281       log_error ("make_filename failed in %s: %s\n",
1282                  __func__, gpg_strerror (err));
1283       goto leave;
1284     }
1285
1286   dir = opendir (dirname);
1287   if (!dir)
1288     {
1289       err = gpg_error_from_syserror ();
1290       log_error (("can't access directory '%s': %s\n"),
1291                  dirname, gpg_strerror (err));
1292       goto leave;
1293     }
1294
1295   while ((dentry = readdir (dir)))
1296     {
1297       if (*dentry->d_name == '.')
1298         continue;
1299       xfree (fname);
1300       fname = make_filename_try (dirname, dentry->d_name, NULL);
1301       if (!fname)
1302         {
1303           err = gpg_error_from_syserror ();
1304           log_error ("make_filename failed in %s: %s\n",
1305                      __func__, gpg_strerror (err));
1306           goto leave;
1307         }
1308       if (strlen (dentry->d_name) != 32)
1309         {
1310           log_info ("garbage file '%s' ignored\n", fname);
1311           continue;
1312         }
1313       if (stat (fname, &sb))
1314         {
1315           err = gpg_error_from_syserror ();
1316           log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
1317           continue;
1318         }
1319       if (S_ISDIR(sb.st_mode))
1320         {
1321           log_info ("garbage directory '%s' ignored\n", fname);
1322           continue;
1323         }
1324       if (sb.st_mtime + PENDING_TTL < now)
1325         {
1326           if (opt.verbose)
1327             log_info ("domain %s: removing pending key '%s'\n",
1328                       domain, dentry->d_name);
1329           if (remove (fname))
1330             {
1331               err = gpg_error_from_syserror ();
1332               /* In case the file has just been renamed or another
1333                * processes is cleaning up, we don't print a diagnostic
1334                * for ENOENT.  */
1335               if (gpg_err_code (err) != GPG_ERR_ENOENT)
1336                 log_error ("error removing '%s': %s\n",
1337                            fname, gpg_strerror (err));
1338             }
1339         }
1340     }
1341   err = 0;
1342
1343  leave:
1344   if (dir)
1345     closedir (dir);
1346   xfree (dirname);
1347   xfree (fname);
1348   return err;
1349
1350 }
1351
1352
1353 /* Scan spool directories and expire too old pending keys.  */
1354 static gpg_error_t
1355 expire_pending_confirmations (void)
1356 {
1357   gpg_error_t err;
1358   DIR *dir = NULL;
1359   char *fname = NULL;
1360   struct dirent *dentry;
1361   struct stat sb;
1362
1363   dir = opendir (opt.directory);
1364   if (!dir)
1365     {
1366       err = gpg_error_from_syserror ();
1367       goto leave;
1368     }
1369
1370   while ((dentry = readdir (dir)))
1371     {
1372       if (*dentry->d_name == '.')
1373         continue;
1374       if (!strchr (dentry->d_name, '.'))
1375         continue; /* No dot - can't be a domain subdir.  */
1376
1377       xfree (fname);
1378       fname = make_filename_try (opt.directory, dentry->d_name, NULL);
1379       if (!fname)
1380         {
1381           err = gpg_error_from_syserror ();
1382           log_error ("make_filename failed in %s: %s\n",
1383                      __func__, gpg_strerror (err));
1384           goto leave;
1385         }
1386
1387       if (stat (fname, &sb))
1388         {
1389           err = gpg_error_from_syserror ();
1390           log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
1391           continue;
1392         }
1393       if (!S_ISDIR(sb.st_mode))
1394         continue;
1395
1396       expire_one_domain (fname, dentry->d_name);
1397     }
1398   err = 0;
1399
1400  leave:
1401   if (dir)
1402     closedir (dir);
1403   xfree (fname);
1404   return err;
1405 }
1406
1407
1408 /* Run regular maintenance jobs.  */
1409 static gpg_error_t
1410 command_cron (void)
1411 {
1412   return expire_pending_confirmations ();
1413 }