tools: Call sendmail directly from the wks tools.
authorWerner Koch <wk@gnupg.org>
Sat, 2 Jul 2016 22:41:30 +0000 (00:41 +0200)
committerWerner Koch <wk@gnupg.org>
Sat, 2 Jul 2016 22:41:30 +0000 (00:41 +0200)
* tools/send-mail.c, tools/send-mail.h: New.
* tools/wks-util.c: New.
* tools/Makefile.am (gpg_wks_server_SOURCES): Add them.
(gpg_wks_client_SOURCES): Ditto.
* tools/gpg-wks.h (opt): Add fields use_sendmail and output.
* tools/gpg-wks-client.c: Add options --send and --output.  Rename
command --send to --create.
(command_send, send_confirmation_response): Output via wks_send_mime.
* tools/gpg-wks-server.c:  Add options --send and --output.
(send_confirmation_request): Output via wks_send_mime.
(check_and_publish): Add hack for name-value bug.
--

With this code, a dedicated user on the server along with a procmail
script, it was possible to run a basic test.

Signed-off-by: Werner Koch <wk@gnupg.org>
tools/Makefile.am
tools/gpg-wks-client.c
tools/gpg-wks-server.c
tools/gpg-wks.h
tools/send-mail.c [new file with mode: 0644]
tools/send-mail.h [new file with mode: 0644]
tools/wks-util.c [new file with mode: 0644]

index 362ee1f..7bc1456 100644 (file)
@@ -147,21 +147,25 @@ gpgtar_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
 gpg_wks_server_SOURCES = \
        gpg-wks-server.c \
        gpg-wks.h \
+       wks-util.c \
        wks-receive.c \
        rfc822parse.c rfc822parse.h \
        mime-parser.c mime-parser.h \
-       mime-maker.h  mime-maker.c
+       mime-maker.c  mime-maker.h  \
+       send-mail.c   send-mail.h
 
 gpg_wks_server_CFLAGS = $(GPG_ERROR_CFLAGS)
 gpg_wks_server_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS)
 
 gpg_wks_client_SOURCES = \
        gpg-wks-client.c \
-       gpg-wks.h \
+       gpg-wks.h  \
+       wks-util.c \
        wks-receive.c \
        rfc822parse.c rfc822parse.h \
        mime-parser.c mime-parser.h \
-       mime-maker.h  mime-maker.c \
+       mime-maker.h  mime-maker.c  \
+       send-mail.c   send-mail.h   \
        call-dirmngr.c call-dirmngr.h
 
 gpg_wks_client_CFLAGS = $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
index c7cb8fb..25ee43f 100644 (file)
@@ -34,6 +34,7 @@
 #include "name-value.h"
 #include "call-dirmngr.h"
 #include "mime-maker.h"
+#include "send-mail.h"
 #include "gpg-wks.h"
 
 
@@ -44,13 +45,15 @@ enum cmd_and_opt_values
 
     oQuiet      = 'q',
     oVerbose   = 'v',
+    oOutput     = 'o',
 
     oDebug      = 500,
 
-    aSend,
+    aCreate,
     aReceive,
 
     oGpgProgram,
+    oSend,
 
     oDummy
   };
@@ -60,8 +63,8 @@ enum cmd_and_opt_values
 static ARGPARSE_OPTS opts[] = {
   ARGPARSE_group (300, ("@Commands:\n ")),
 
-  ARGPARSE_c (aSend,   "send",
-              ("send a publication request")),
+  ARGPARSE_c (aCreate,   "create",
+              ("create a publication request")),
   ARGPARSE_c (aReceive,   "receive",
               ("receive a confirmation request")),
 
@@ -71,6 +74,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oQuiet,        "quiet",  ("be somewhat more quiet")),
   ARGPARSE_s_s (oDebug, "debug", "@"),
   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
+  ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
+  ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
 
 
   ARGPARSE_end ()
@@ -112,10 +117,10 @@ my_strusage( int level )
 
     case 1:
     case 40:
-      p = ("Usage: gpg-wks-client --send|--receive [args] (-h for help)");
+      p = ("Usage: gpg-wks-client [command] [options] [args] (-h for help)");
       break;
     case 41:
-      p = ("Syntax: gpg-wks-client --send|--receive [args]\n"
+      p = ("Syntax: gpg-wks-client [command] [options] [args]\n"
            "Client for the Web Key Service\n");
       break;
 
@@ -158,8 +163,14 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
         case oGpgProgram:
           opt.gpg_program = pargs->r.ret_str;
           break;
+        case oSend:
+          opt.use_sendmail = 1;
+          break;
+        case oOutput:
+          opt.output = pargs->r.ret_str;
+          break;
 
-       case aSend:
+       case aCreate:
        case aReceive:
           cmd = pargs->r_opt;
           break;
@@ -221,12 +232,12 @@ main (int argc, char **argv)
   /* Run the selected command.  */
   switch (cmd)
     {
-    case aSend:
+    case aCreate:
       if (argc != 2)
-        wrong_args ("--send FINGERPRINT USER-ID");
+        wrong_args ("--create FINGERPRINT USER-ID");
       err = command_send (argv[0], argv[1]);
       if (err)
-        log_error ("sending key failed: %s\n", gpg_strerror (err));
+        log_error ("creating request failed: %s\n", gpg_strerror (err));
       break;
 
     case aReceive:
@@ -234,7 +245,7 @@ main (int argc, char **argv)
         wrong_args ("--receive");
       err = wks_receive (es_stdin, command_receive_cb, NULL);
       if (err)
-        log_error ("reading mail failed: %s\n", gpg_strerror (err));
+        log_error ("processing mail failed: %s\n", gpg_strerror (err));
       break;
 
     default:
@@ -407,7 +418,7 @@ command_send (const char *fingerprint, char *userid)
   if (err)
     goto leave;
 
-  err = mime_maker_make (mime, es_stdout);
+  err = wks_send_mime (mime);
 
  leave:
   mime_maker_release (mime);
@@ -502,7 +513,7 @@ send_confirmation_response (const char *sender, const char *address,
   if (err)
     goto leave;
 
-  err = mime_maker_make (mime, es_stdout);
+  err = wks_send_mime (mime);
 
  leave:
   mime_maker_release (mime);
index 1106934..305b454 100644 (file)
@@ -40,6 +40,7 @@
 #include "mbox-util.h"
 #include "name-value.h"
 #include "mime-maker.h"
+#include "send-mail.h"
 #include "gpg-wks.h"
 
 
@@ -50,6 +51,7 @@ enum cmd_and_opt_values
 
     oQuiet      = 'q',
     oVerbose   = 'v',
+    oOutput     = 'o',
 
     oDebug      = 500,
 
@@ -57,6 +59,7 @@ enum cmd_and_opt_values
     aCron,
 
     oGpgProgram,
+    oSend,
     oFrom,
     oHeader,
 
@@ -79,7 +82,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oQuiet,        "quiet",  ("be somewhat more quiet")),
   ARGPARSE_s_s (oDebug, "debug", "@"),
   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
-  ARGPARSE_s_s (oFrom, "from" , "|ADDR|use ADDR as the default sender"),
+  ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
+  ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
+  ARGPARSE_s_s (oFrom, "from", "|ADDR|use ADDR as the default sender"),
   ARGPARSE_s_s (oHeader, "header" ,
                 "|NAME=VALUE|add \"NAME: VALUE\" as header to all mails"),
 
@@ -182,6 +187,12 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
         case oHeader:
           append_to_strlist (&opt.extra_headers, pargs->r.ret_str);
           break;
+        case oSend:
+          opt.use_sendmail = 1;
+          break;
+        case oOutput:
+          opt.output = pargs->r.ret_str;
+          break;
 
        case aReceive:
         case aCron:
@@ -831,7 +842,7 @@ send_confirmation_request (server_ctx_t ctx,
   if (err)
     goto leave;
 
-  err = mime_maker_make (mime, es_stdout);
+  err = wks_send_mime (mime);
 
  leave:
   mime_maker_release (mime);
@@ -923,6 +934,14 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
   const char *s;
   strlist_t sl;
 
+  /* FIXME: There is a bug in name-value.c which adds white space for
+   * the last pair and thus we strip the nonce here until this has
+   * been fixed.  */
+  char *nonce2 = xstrdup (nonce);
+  trim_trailing_spaces (nonce2);
+  nonce = nonce2;
+
+
   domain = strchr (address, '@');
   log_assert (domain && domain[1]);
   domain++;
@@ -1027,6 +1046,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
   xfree (hash);
   xfree (fnewname);
   xfree (fname);
+  xfree (nonce2);
   return err;
 }
 
index 873925c..be85eec 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "../common/util.h"
 #include "../common/strlist.h"
+#include "mime-maker.h"
 
 /* We keep all global options in the structure OPT.  */
 struct
@@ -29,6 +30,8 @@ struct
   int verbose;
   unsigned int debug;
   int quiet;
+  int use_sendmail;
+  const char *output;
   const char *gpg_program;
   const char *directory;
   const char *default_from;
@@ -43,6 +46,9 @@ struct
 #define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
 
 
+/*-- wks-util.c --*/
+gpg_error_t wks_send_mime (mime_maker_t mime);
+
 /*-- wks-receive.c --*/
 gpg_error_t wks_receive (estream_t fp,
                          gpg_error_t (*result_cb)(void *opaque,
diff --git a/tools/send-mail.c b/tools/send-mail.c
new file mode 100644 (file)
index 0000000..2266521
--- /dev/null
@@ -0,0 +1,129 @@
+/* send-mail.c - Invoke sendmail or other delivery tool.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "exectool.h"
+#include "sysutils.h"
+#include "send-mail.h"
+
+
+static gpg_error_t
+run_sendmail (estream_t data)
+{
+  gpg_error_t err;
+  const char pgmname[] = "/usr/lib/sendmail";
+  const char *argv[3];
+
+  argv[0] = "-oi";
+  argv[1] = "-t";
+  argv[2] = NULL;
+
+  err = gnupg_exec_tool_stream (pgmname, argv, data, NULL, NULL, NULL, NULL);
+  if (err)
+    log_error ("running '%s' failed: %s\n", pgmname, gpg_strerror (err));
+  return err;
+}
+
+
+/* Send the data in FP as mail.  */
+gpg_error_t
+send_mail (estream_t fp)
+{
+  return run_sendmail (fp);
+}
+
+
+/* Convenience function to write a mail to a named file. */
+gpg_error_t
+send_mail_to_file (estream_t fp, const char *fname)
+{
+  gpg_error_t err;
+  estream_t outfp = NULL;
+  char *buffer = NULL;
+  size_t buffersize = 32 * 1024;
+  size_t nbytes, nwritten;
+
+  if (!fname)
+    fname = "-";
+
+  buffer = xtrymalloc (buffersize);
+  if (!buffer)
+    return gpg_error_from_syserror ();
+
+  outfp = !strcmp (fname,"-")? es_stdout : es_fopen (fname, "wb");
+  if (!outfp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error creating '%s': %s\n", fname, gpg_strerror (err));
+      goto leave;
+    }
+  for (;;)
+    {
+      if (es_read (fp, buffer, sizeof buffer, &nbytes))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error reading '%s': %s\n",
+                     es_fname_get (fp), gpg_strerror (err));
+          goto leave;
+        }
+
+      if (!nbytes)
+        {
+          err = 0;
+          break; /* Ready.  */
+        }
+
+      if (es_write (outfp, buffer, nbytes, &nwritten))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
+          goto leave;
+        }
+      else if (nwritten != nbytes)
+        {
+          err = gpg_error (GPG_ERR_EIO);
+          log_error ("error writing '%s': %s\n", fname, "short write");
+          goto leave;
+        }
+    }
+
+
+ leave:
+  if (err)
+    {
+      if (outfp && outfp != es_stdout)
+        {
+          es_fclose (outfp);
+          gnupg_remove (fname);
+        }
+    }
+  else if (outfp && outfp != es_stdout && es_fclose (outfp))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
+    }
+
+  xfree (buffer);
+  return err;
+}
diff --git a/tools/send-mail.h b/tools/send-mail.h
new file mode 100644 (file)
index 0000000..5f57854
--- /dev/null
@@ -0,0 +1,27 @@
+/* send-mail.h - Invoke sendmail or other delivery tool.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_SEND_MAIL_H
+#define GNUPG_SEND_MAIL_H
+
+gpg_error_t send_mail (estream_t fp);
+gpg_error_t send_mail_to_file (estream_t fp, const char *fname);
+
+
+#endif /*GNUPG_SEND_MAIL_H*/
diff --git a/tools/wks-util.c b/tools/wks-util.c
new file mode 100644 (file)
index 0000000..8d9f92b
--- /dev/null
@@ -0,0 +1,65 @@
+/* wks-utils.c - Common helper fucntions for wks tools
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "mime-maker.h"
+#include "send-mail.h"
+#include "gpg-wks.h"
+
+
+/* Helper to write mail to the output(s).  */
+gpg_error_t
+wks_send_mime (mime_maker_t mime)
+{
+  gpg_error_t err;
+  estream_t mail;
+
+  /* Without any option we take a short path.  */
+  if (!opt.use_sendmail && !opt.output)
+    return mime_maker_make (mime, es_stdout);
+
+  mail = es_fopenmem (0, "w+b");
+  if (!mail)
+    {
+      err = gpg_error_from_syserror ();
+      return err;
+    }
+
+  err = mime_maker_make (mime, mail);
+
+  if (!err && opt.output)
+    {
+      es_rewind (mail);
+      err = send_mail_to_file (mail, opt.output);
+    }
+
+  if (!err && opt.use_sendmail)
+    {
+      es_rewind (mail);
+      err = send_mail (mail);
+    }
+
+  es_fclose (mail);
+  return err;
+}