Fix usage of ARGPARSE_OPTS.
[gnupg.git] / dirmngr / dirmngr-client.c
index 1e38840..53b405e 100644 (file)
@@ -15,7 +15,7 @@
  * 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/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <assert.h>
 
 #include <gpg-error.h>
-#include <assuan.h> 
+#include <assuan.h>
 
-#define JNLIB_NEED_LOG_LOGV
 #include "../common/logging.h"
 #include "../common/argparse.h"
 #include "../common/stringhelp.h"
 #include "../common/mischelp.h"
 #include "../common/strlist.h"
+#include "../common/asshelp.h"
 
-#include "i18n.h"
-#include "util.h"
+#include "../common/i18n.h"
+#include "../common/util.h"
+#include "../common/init.h"
 
 
 /* Constants for the options.  */
-enum 
+enum
   {
     oQuiet       = 'q',
     oVerbose     = 'v',
@@ -76,12 +77,12 @@ static ARGPARSE_OPTS opts[] = {
   { oUrl,      "url",       0, N_("expect an URL for --lookup")},
   { oLoadCRL,  "load-crl",  0, N_("load a CRL into the dirmngr")},
   { oSquidMode,"squid-mode",0, N_("special mode for use by Squid")},
-  { oPEM,      "pem",       0, N_("certificates are expected in PEM format")},
+  { oPEM,      "pem",       0, N_("expect certificates in PEM format")},
   { oForceDefaultResponder, "force-default-responder", 0,
     N_("force the use of the default OCSP responder")},
-  { 0, NULL, 0, NULL }
+  ARGPARSE_end ()
 };
+
 
 /* The usual structure for the program flags.  */
 static struct
@@ -89,7 +90,6 @@ static struct
   int quiet;
   int verbose;
   const char *dirmngr_program;
-  int force_pipe_server;
   int force_default_responder;
   int pem;
   int escaped_pem; /* PEM is additional percent encoded.  */
@@ -116,8 +116,26 @@ static unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 static unsigned char asctobin[256]; /* runtime initialized */
 
 
+/* Build the helptable for radix64 to bin conversion. */
+static void
+init_asctobin (void)
+{
+  static int initialized;
+  int i;
+  unsigned char *s;
+
+  if (initialized)
+    return;
+  initialized = 1;
+
+  for (i=0; i < 256; i++ )
+    asctobin[i] = 255; /* Used to detect invalid characters. */
+  for (s=bintoasc, i=0; *s; s++, i++)
+    asctobin[*s] = i;
+}
+
+
 /* Prototypes.  */
-static assuan_context_t start_dirmngr (int only_daemon);
 static gpg_error_t read_certificate (const char *fname,
                                      unsigned char **rbuf, size_t *rbuflen);
 static gpg_error_t do_check (assuan_context_t ctx,
@@ -137,10 +155,10 @@ static const char *
 my_strusage (int level)
 {
   const char *p;
-    
+
   switch(level)
     {
-    case 11: p = "dirmngr-client (GnuPG)";
+    case 11: p = "dirmngr-client (@GNUPG@)";
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
@@ -164,21 +182,6 @@ my_strusage (int level)
 }
 
 
-static void
-my_i18n_init (void)
-{
-#warning Better use common init functions
-#ifdef USE_SIMPLE_GETTEXT
-  set_gettext_file (PACKAGE);
-#else
-# ifdef ENABLE_NLS
-  setlocale (LC_ALL, "" );
-  bindtextdomain (PACKAGE, LOCALEDIR);
-  textdomain (PACKAGE);
-# endif
-#endif
-}
-
 
 int
 main (int argc, char **argv )
@@ -195,26 +198,27 @@ main (int argc, char **argv )
   int cmd_loadcrl = 0;
   int cmd_squid_mode = 0;
 
+  early_system_init ();
   set_strusage (my_strusage);
   log_set_prefix ("dirmngr-client",
-                  JNLIB_LOG_WITH_PREFIX); 
+                  GPGRT_LOG_WITH_PREFIX);
 
-  /* For W32 we need to initialize the socket subsystem.  Becuase we
+  /* For W32 we need to initialize the socket subsystem.  Because we
      don't use Pth we need to do this explicit. */
-#ifdef HAVE_W32_SYSTEM  
+#ifdef HAVE_W32_SYSTEM
  {
    WSADATA wsadat;
 
    WSAStartup (0x202, &wsadat);
  }
 #endif /*HAVE_W32_SYSTEM*/
-  
+
   /* Init Assuan.  */
   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
 
   /* Setup I18N. */
-  my_i18n_init();
+  i18n_init();
 
   /* Parse the command line.  */
   pargs.argc = &argc;
@@ -226,7 +230,7 @@ main (int argc, char **argv )
         {
         case oVerbose: opt.verbose++; break;
         case oQuiet: opt.quiet++; break;
-          
+
         case oOCSP: opt.use_ocsp++; break;
         case oPing: cmd_ping = 1; break;
         case oCacheCert: cmd_cache_cert = 1; break;
@@ -236,7 +240,7 @@ main (int argc, char **argv )
         case oLocal: opt.local = 1; break;
         case oLoadCRL: cmd_loadcrl = 1; break;
         case oPEM: opt.pem = 1; break;
-        case oSquidMode: 
+        case oSquidMode:
           opt.pem = 1;
           opt.escaped_pem = 1;
           cmd_squid_mode = 1;
@@ -249,19 +253,6 @@ main (int argc, char **argv )
   if (log_get_errorcount (0))
     exit (2);
 
-  /* Build the helptable for radix64 to bin conversion. */
-  if (opt.pem) 
-    {
-      int i;
-      unsigned char *s;
-      
-      for (i=0; i < 256; i++ )
-        asctobin[i] = 255; /* Used to detect invalid characters. */
-      for (s=bintoasc, i=0; *s; s++, i++)
-        asctobin[*s] = i;
-    }
-
-
   if (cmd_ping)
     err = 0;
   else if (cmd_lookup || cmd_loadcrl)
@@ -287,7 +278,7 @@ main (int argc, char **argv )
     {
       err = read_certificate (*argv, &certbuf, &certbuflen);
       if (err)
-        log_error (_("error reading certificate from `%s': %s\n"),
+        log_error (_("error reading certificate from '%s': %s\n"),
                    *argv, gpg_strerror (err));
     }
   else
@@ -305,9 +296,20 @@ main (int argc, char **argv )
       exit (2);
     }
 
-  ctx = start_dirmngr (1);
-  if (!ctx)
-    exit (2);
+  err = start_new_dirmngr (&ctx,
+                           GPG_ERR_SOURCE_DEFAULT,
+                           opt.dirmngr_program
+                             ? opt.dirmngr_program
+                             : gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR),
+                           ! cmd_ping,
+                           opt.verbose,
+                           0,
+                           NULL, NULL);
+  if (err)
+    {
+      log_error (_("can't connect to the dirmngr: %s\n"), gpg_strerror (err));
+      exit (2);
+    }
 
   if (cmd_ping)
     ;
@@ -342,7 +344,7 @@ main (int argc, char **argv )
           err = do_loadcrl (ctx, *argv);
           if (err)
             {
-              log_error (_("loading CRL `%s' failed: %s\n"),
+              log_error (_("loading CRL '%s' failed: %s\n"),
                          *argv, gpg_strerror (err));
               last_err = err;
             }
@@ -423,7 +425,7 @@ status_cb (void *opaque, const char *line)
   (void)opaque;
 
   if (opt.verbose > 2)
-    log_info (_("got status: `%s'\n"), line);
+    log_info (_("got status: '%s'\n"), line);
   return 0;
 }
 
@@ -443,127 +445,6 @@ data_cb (void *opaque, const void *buffer, size_t length)
     }
   return 0;
 }
-  
-
-/* Try to connect to the dirmngr via socket or fork it off and work by
-   pipes.  Handle the server's initial greeting */
-static assuan_context_t
-start_dirmngr (int only_daemon)
-{
-  int rc;
-  char *infostr, *p;
-  assuan_context_t ctx;
-  int try_default = 0;
-
-  infostr = opt.force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
-  if (only_daemon && (!infostr || !*infostr))
-    {
-      infostr = xstrdup (dirmngr_socket_name ());
-      try_default = 1;
-    }
-
-  rc = assuan_new (&ctx);
-  if (rc)
-    {
-      log_error (_("failed to allocate assuan context: %s\n"),
-                 gpg_strerror (rc));
-      return NULL;
-    }
-
-  if (!infostr || !*infostr)
-    {
-      const char *pgmname;
-      const char *argv[3];
-      int no_close_list[3];
-      int i;
-
-      if (only_daemon)
-        {
-          log_error (_("apparently no running dirmngr\n"));
-          return NULL;
-        }
-
-      if (opt.verbose)
-        log_info (_("no running dirmngr - starting one\n"));
-      
-      if (!opt.dirmngr_program || !*opt.dirmngr_program)
-        opt.dirmngr_program = "./dirmngr";
-      if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
-        pgmname = opt.dirmngr_program;
-      else
-        pgmname++;
-
-      argv[0] = pgmname;
-      argv[1] = "--server";
-      argv[2] = NULL;
-
-      i=0;
-      if (log_get_fd () != -1)
-        no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
-      no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
-      no_close_list[i] = -1;
-
-      /* Connect to the agent and perform initial handshaking.  */
-      rc = assuan_pipe_connect (ctx, opt.dirmngr_program, argv,
-                                no_close_list, NULL, NULL, 0);
-    }
-  else /* Connect to a daemon.  */
-    {
-      int prot;
-      int pid;
-
-      infostr = xstrdup (infostr);
-      if (!try_default && *infostr)
-        {
-          if ( !(p = strchr (infostr, ':')) || p == infostr)
-            {
-              log_error (_("malformed DIRMNGR_INFO environment variable\n"));
-              xfree (infostr);
-              if (only_daemon)
-                return NULL;
-              /* Try again by starting a new instance.  */
-              opt.force_pipe_server = 1;
-              return start_dirmngr (0);
-            }
-          *p++ = 0;
-          pid = atoi (p);
-          while (*p && *p != ':')
-            p++;
-          prot = *p? atoi (p+1) : 0;
-          if (prot != 1)
-            {
-              log_error (_("dirmngr protocol version %d is not supported\n"),
-                         prot);
-              xfree (infostr);
-              if (only_daemon)
-                return NULL;
-              opt.force_pipe_server = 1;
-              return start_dirmngr (0);
-            }
-        }
-      else
-        pid = -1;
-
-      rc = assuan_socket_connect (ctx, infostr, pid, 0);
-      xfree (infostr);
-      if (gpg_err_code(rc) == GPG_ERR_ASS_CONNECT_FAILED && !only_daemon)
-        {
-          log_error (_("can't connect to the dirmngr - trying fall back\n"));
-          opt.force_pipe_server = 1;
-          return start_dirmngr (0);
-        }
-    }
-
-  if (rc)
-    {
-      assuan_release (ctx);
-      log_error (_("can't connect to the dirmngr: %s\n"),
-                 gpg_strerror (rc));
-      return NULL;
-    }
-
-  return ctx;
-}
 
 
 /* Read the first PEM certificate from the file FNAME.  If fname is
@@ -585,6 +466,8 @@ read_pem_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
     s_waitend
   } state = s_init;
 
+  init_asctobin ();
+
   fp = fname? fopen (fname, "r") : stdin;
   if (!fp)
     return gpg_error_from_errno (errno);
@@ -634,7 +517,7 @@ read_pem_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
             }
           break;
         case s_init:
-          state = s_lfseen;
+          state = s_lfseen; /* fall through */
         case s_lfseen:
           if (c != "-----BEGIN "[pos])
             state = s_idle;
@@ -696,8 +579,8 @@ read_pem_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
              real LF and not a trailing percent escaped one. */
           if (c== '\n' && !escaped_c)
             goto ready;
-          break; 
-        default: 
+          break;
+        default:
           BUG();
         }
     }
@@ -736,6 +619,15 @@ read_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
 
   if (opt.pem)
     return read_pem_certificate (fname, rbuf, rbuflen);
+  else if (fname)
+    {
+      /* A filename has been given.  Let's just assume it is in PEM
+         format and decode it, and fall back to interpreting it as
+         binary certificate if that fails.  */
+      err = read_pem_certificate (fname, rbuf, rbuflen);
+      if (! err)
+        return 0;
+    }
 
   fp = fname? fopen (fname, "rb") : stdin;
   if (!fp)
@@ -744,7 +636,7 @@ read_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
   buf = NULL;
   bufsize = buflen = 0;
 #define NCHUNK 8192
-  do 
+  do
     {
       bufsize += NCHUNK;
       if (!buf)
@@ -806,7 +698,7 @@ inq_cert (void *opaque, const char *line)
     }
   else
     {
-      log_info (_("unsupported inquiry `%s'\n"), line);
+      log_info (_("unsupported inquiry '%s'\n"), line);
       err = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
       /* Note that this error will let assuan_transact terminate
          immediately instead of return the error to the caller.  It is
@@ -831,10 +723,10 @@ do_check (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
   parm.cert = cert;
   parm.certlen = certlen;
 
-  err = assuan_transact (ctx, 
+  err = assuan_transact (ctx,
                          (opt.use_ocsp && opt.force_default_responder
-                          ? "CHECKOCSP --force-default-responder" 
-                          : opt.use_ocsp? "CHECKOCSP" : "CHECKCRL"), 
+                          ? "CHECKOCSP --force-default-responder"
+                          : opt.use_ocsp? "CHECKOCSP" : "CHECKCRL"),
                          NULL, NULL, inq_cert, &parm, status_cb, NULL);
   if (opt.verbose > 1)
     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
@@ -899,10 +791,10 @@ do_loadcrl (assuan_context_t ctx, const char *filename)
       fname = canonicalize_file_name (filename);
       if (!fname)
         {
-          log_error ("error canonicalizing `%s': %s\n",
+          log_error ("error canonicalizing '%s': %s\n",
                      filename, strerror (errno));
           return gpg_error (GPG_ERR_GENERAL);
-        }      
+        }
 #else
       fname = xstrdup (filename);
 #endif
@@ -912,7 +804,7 @@ do_loadcrl (assuan_context_t ctx, const char *filename)
           return gpg_error (GPG_ERR_GENERAL);
         }
     }
-  
+
   line = xmalloc (8 + 6 + strlen (fname) * 3 + 1);
   p = stpcpy (line, "LOADCRL ");
   if (opt.url)
@@ -953,7 +845,7 @@ do_lookup (assuan_context_t ctx, const char *pattern)
   struct b64state state;
 
   if (opt.verbose)
-    log_info (_("looking up `%s'\n"), pattern);
+    log_info (_("looking up '%s'\n"), pattern);
 
   err = b64enc_start (&state, stdout, NULL);
   if (err)
@@ -1003,7 +895,7 @@ squid_loop_body (assuan_context_t ctx)
   gpg_error_t err;
   unsigned char *certbuf;
   size_t certbuflen = 0;
-  
+
   err = read_pem_certificate (NULL, &certbuf, &certbuflen);
   if (gpg_err_code (err) == GPG_ERR_EOF)
     return err;
@@ -1023,7 +915,7 @@ squid_loop_body (assuan_context_t ctx)
         log_info (_("certificate is valid\n"));
       puts ("OK");
     }
-  else 
+  else
     {
       if (!opt.quiet)
         {
@@ -1035,7 +927,7 @@ squid_loop_body (assuan_context_t ctx)
         }
       puts ("ERROR");
     }
-  
+
   fflush (stdout);
 
   return 0;