sm/
[gnupg.git] / sm / gpgsm.c
index 0d6da95..50ffb84 100644 (file)
@@ -1,6 +1,6 @@
 /* gpgsm.c - GnuPG for S/MIME 
  * Copyright (C) 2001, 2002, 2003, 2004, 2005,
- *               2006, 2007  Free Software Foundation, Inc.
+ *               2006, 2007, 2008  Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -108,6 +108,7 @@ enum cmd_and_opt_values {
   oFixedPassphrase,
   oLogFile,
   oNoLogFile,
+  oAuditLog,
 
   oEnableSpecialFilenames,
 
@@ -117,9 +118,11 @@ enum cmd_and_opt_values {
   oTTYtype,
   oLCctype,
   oLCmessages,
+  oXauthority,
 
   oPreferSystemDirmngr,
   oDirmngrProgram,
+  oDisableDirmngr,
   oProtectToolProgram,
   oFakedSystemTime,
 
@@ -147,7 +150,6 @@ enum cmd_and_opt_values {
   oEnablePolicyChecks,
   oAutoIssuerKeyRetrieve,
   
-
   oTextmode,
   oFingerprint,
   oWithFingerprint,
@@ -172,6 +174,7 @@ enum cmd_and_opt_values {
   oOpenPGP,
   oCipherAlgo,
   oDigestAlgo,
+  oExtraDigestAlgo,
   oCompressAlgo,
   oCommandFD,
   oNoVerbose,
@@ -228,6 +231,7 @@ enum cmd_and_opt_values {
   oIgnoreTimeConflict,
   oNoRandomSeedFile,
   oNoAutoKeyRetrieve,
+  oNoCommonCertsImport,
   oUseAgent,
   oMergeOnly,
   oTryAllSecrets,
@@ -336,12 +340,13 @@ static ARGPARSE_OPTS opts[] = {
     { oTextmode, "textmode",  0, N_("use canonical text mode")},
 #endif
 
-    { oOutput, "output",    2, N_("use as output file")},
+    { oOutput, "output",    2, N_("|FILE|write output to FILE")},
     { oVerbose, "verbose",   0, N_("verbose") },
     { oQuiet,  "quiet",   0, N_("be somewhat more quiet") },
     { oNoTTY, "no-tty", 0, N_("don't use the terminal at all") },
-    { oLogFile, "log-file"   ,2, N_("use a log file for the server")},
+    { oLogFile, "log-file"   ,2, N_("|FILE|write a server mode log to FILE")},
     { oNoLogFile, "no-log-file" ,0, "@"},
+    { oAuditLog, "audit-log", 2, N_("|FILE|write an audit log to FILE")},
 #if 0
     { oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") },
     { oForceMDC, "force-mdc", 0, N_("always use a MDC for encryption") },
@@ -356,7 +361,7 @@ static ARGPARSE_OPTS opts[] = {
     { oKeyring, "keyring"   ,2, N_("add this keyring to the list of keyrings")},
     { oSecretKeyring, "secret-keyring" ,2, N_("add this secret keyring to the list")},
     { oDefaultKey, "default-key" ,2, N_("|NAME|use NAME as default secret key")},
-    { oKeyServer, "keyserver",2, N_("|HOST|use this keyserver to lookup keys")},
+    { oKeyServer, "keyserver",2, N_("|SPEC|use this keyserver to lookup keys")},
     { oCharset, "charset"   , 2, N_("|NAME|set terminal charset to NAME") },
     { oOptions, "options"   , 2, N_("read options from file")},
 
@@ -385,6 +390,7 @@ static ARGPARSE_OPTS opts[] = {
     { oCipherAlgo, "cipher-algo", 2 , N_("|NAME|use cipher algorithm NAME")},
     { oDigestAlgo, "digest-algo", 2 ,
       N_("|NAME|use message digest algorithm NAME")},
+    { oExtraDigestAlgo, "extra-digest-algo", 2 , "@" },
 #if 0
     { oCompressAlgo, "compress-algo", 1 , N_("|N|use compress algorithm N")},
 #endif
@@ -424,11 +430,12 @@ static ARGPARSE_OPTS opts[] = {
     { oTTYtype,    "ttytype",     2, "@" },
     { oLCctype,    "lc-ctype",    2, "@" },
     { oLCmessages, "lc-messages", 2, "@" },
+    { oXauthority, "xauthority", 2, "@" },
     { oDirmngrProgram, "dirmngr-program", 2 , "@" },
+    { oDisableDirmngr, "disable-dirmngr", 0 , "@" },
     { oProtectToolProgram, "protect-tool-program", 2 , "@" },
     { oFakedSystemTime, "faked-system-time", 2, "@" }, /* (epoch time) */
 
-
     { oNoBatch, "no-batch", 0, "@" },
     { oWithColons, "with-colons", 0, "@"},
     { oWithKeyData,"with-key-data", 0, "@"},
@@ -456,6 +463,7 @@ static ARGPARSE_OPTS opts[] = {
     { oListOnly, "list-only", 0, "@"},
     { oIgnoreTimeConflict, "ignore-time-conflict", 0, "@" },
     { oNoRandomSeedFile,  "no-random-seed-file", 0, "@" },
+    { oNoCommonCertsImport, "no-common-certs-import", 0, "@" },
 {0} };
 
 
@@ -811,6 +819,99 @@ parse_validation_model (const char *model)
 }
 
 
+/* Release the list of SERVERS.  As usual it is okay to call this
+   function with SERVERS passed as NULL.  */
+void
+keyserver_list_free (struct keyserver_spec *servers)
+{
+  while (servers)
+    {
+      struct keyserver_spec *tmp = servers->next;
+      xfree (servers->host);
+      xfree (servers->user);
+      if (servers->pass)
+        memset (servers->pass, 0, strlen (servers->pass));
+      xfree (servers->pass);
+      xfree (servers->base);
+      xfree (servers);
+      servers = tmp;
+    }
+}
+
+/* See also dirmngr ldapserver_parse_one().  */
+struct keyserver_spec *
+parse_keyserver_line (char *line,
+                     const char *filename, unsigned int lineno)
+{
+  char *p;
+  char *endp;
+  struct keyserver_spec *server;
+  int fieldno;
+  int fail = 0;
+
+  /* Parse the colon separated fields.  */
+  server = xcalloc (1, sizeof *server);
+  for (fieldno = 1, p = line; p; p = endp, fieldno++ )
+    {
+      endp = strchr (p, ':');
+      if (endp)
+       *endp++ = '\0';
+      trim_spaces (p);
+      switch (fieldno)
+       {
+       case 1:
+         if (*p)
+           server->host = xstrdup (p);
+         else
+           {
+             log_error (_("%s:%u: no hostname given\n"),
+                        filename, lineno);
+             fail = 1;
+           }
+         break;
+          
+       case 2:
+         if (*p)
+           server->port = atoi (p);
+         break;
+         
+       case 3:
+         if (*p)
+           server->user = xstrdup (p);
+         break;
+         
+       case 4:
+         if (*p && !server->user)
+           {
+             log_error (_("%s:%u: password given without user\n"), 
+                        filename, lineno);
+             fail = 1;
+           }
+         else if (*p)
+           server->pass = xstrdup (p);
+         break;
+         
+       case 5:
+         if (*p)
+           server->base = xstrdup (p);
+         break;
+         
+       default:
+         /* (We silently ignore extra fields.) */
+         break;
+       }
+    }
+  
+  if (fail)
+    {
+      log_info (_("%s:%u: skipping this line\n"), filename, lineno);
+      keyserver_list_free (server);
+    }
+
+  return server;
+}
+
+
 int
 main ( int argc, char **argv)
 {
@@ -831,21 +932,26 @@ main ( int argc, char **argv)
   int default_config =1;
   int default_keyring = 1;
   char *logfile = NULL;
+  char *auditlog = NULL;
   int greeting = 0;
   int nogreeting = 0;
   int debug_wait = 0;
   int use_random_seed = 1;
+  int no_common_certs_import = 0;
   int with_fpr = 0;
   char *def_digest_string = NULL;
+  char *extra_digest_algo = NULL;
   enum cmd_and_opt_values cmd = 0;
   struct server_control_s ctrl;
   certlist_t recplist = NULL;
   certlist_t signerlist = NULL;
   int do_not_setup_keys = 0;
   int recp_required = 0;
+  estream_t auditfp = NULL;
 
   /*mtrace();*/
 
+  gnupg_reopen_std ("gpgsm");
   /* trap_unaligned ();*/
   gnupg_rl_initialize ();
   set_strusage (my_strusage);
@@ -1151,6 +1257,8 @@ main ( int argc, char **argv)
         case oLogFile: logfile = pargs.r.ret_str; break;
         case oNoLogFile: logfile = NULL; break;          
 
+        case oAuditLog: auditlog = pargs.r.ret_str; break;
+
         case oBatch: 
           opt.batch = 1;
           greeting = 0;
@@ -1201,7 +1309,9 @@ main ( int argc, char **argv)
         case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break;
         case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break;
         case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break;
+        case oXauthority: opt.xauthority = xstrdup (pargs.r.ret_str); break;
         case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str;  break;
+        case oDisableDirmngr: opt.disable_dirmngr = 1;  break;
         case oPreferSystemDirmngr: opt.prefer_system_dirmngr = 1; break;
         case oProtectToolProgram:
           opt.protect_tool_program = pargs.r.ret_str; 
@@ -1288,13 +1398,36 @@ main ( int argc, char **argv)
           }
           break;
 
+        case oExtraDigestAlgo: 
+          extra_digest_algo = pargs.r.ret_str;
+          break;
+
         case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
         case oNoRandomSeedFile: use_random_seed = 0; break;
+        case oNoCommonCertsImport: no_common_certs_import = 1; break;
 
         case oEnableSpecialFilenames: allow_special_filenames =1; break;
 
         case oValidationModel: parse_validation_model (pargs.r.ret_str); break;
 
+       case oKeyServer:
+         {
+           struct keyserver_spec *keyserver;
+           keyserver = parse_keyserver_line (pargs.r.ret_str,
+                                             configname, configlineno);
+           if (! keyserver)
+             log_error (_("could not parse keyserver\n"));
+           else
+             {
+               /* FIXME: Keep last next pointer.  */
+               struct keyserver_spec **next_p = &opt.keyserver;
+               while (*next_p)
+                 next_p = &(*next_p)->next;
+               *next_p = keyserver;
+             }
+         }
+         break;
+
         case aDummy:
           break;
         default: 
@@ -1343,6 +1476,11 @@ main ( int argc, char **argv)
     }
 #  endif
 
+  if (auditlog)
+    log_info ("NOTE: The audit log feature (--audit-log) is "
+              "WORK IN PRORESS and not ready for use!\n");
+
+
   if (may_coredump && !opt.quiet)
     log_info (_("WARNING: program may create a core file!\n"));
 
@@ -1426,6 +1564,12 @@ main ( int argc, char **argv)
           if (our_md_test_algo(opt.def_digest_algo) )
             log_error (_("selected digest algorithm is invalid\n"));
         }
+      if (extra_digest_algo)
+        {
+          opt.extra_digest_algo = gcry_md_map_name (extra_digest_algo);
+          if (our_md_test_algo (opt.extra_digest_algo) )
+            log_error (_("selected digest algorithm is invalid\n"));
+        }
     }
 
   if (log_get_errorcount(0))
@@ -1448,7 +1592,7 @@ main ( int argc, char **argv)
       int created;
 
       keydb_add_resource ("pubring.kbx", 0, 0, &created);
-      if (created)
+      if (created && !no_common_certs_import)
         {
           /* Import the standard certificates for a new default keybox. */
           char *filelist[2];
@@ -1468,6 +1612,26 @@ main ( int argc, char **argv)
     keydb_add_resource (sl->d, 0, 0, NULL);
   FREE_STRLIST(nrings);
 
+
+  /* Prepare the audit log feature for certain commands.  */
+  if (auditlog)
+    {
+      switch (cmd)
+        {
+        case aEncr: 
+        case aSign:
+        case aDecrypt:
+        case aVerify:
+          audit_release (ctrl.audit);
+          ctrl.audit = audit_new ();
+          auditfp = open_es_fwrite (auditlog);
+          break;
+        default:
+          break;
+        }
+    }
+
+
   if (!do_not_setup_keys)
     {
       for (sl = locusr; sl ; sl = sl->next)
@@ -1514,6 +1678,7 @@ main ( int argc, char **argv)
   
   fname = argc? *argv : NULL;
   
+  /* Dispatch command.  */
   switch (cmd)
     {
     case aGPGConfList: 
@@ -1524,38 +1689,25 @@ main ( int argc, char **argv)
                 GC_OPT_FLAG_DEFAULT, config_filename_esc);
         xfree (config_filename_esc);
 
-        printf ("verbose:%lu:\n"
-                "quiet:%lu:\n"
-                "debug-level:%lu:\"none:\n"
-                "log-file:%lu:\n",
-                GC_OPT_FLAG_NONE,
-                GC_OPT_FLAG_NONE,
-                GC_OPT_FLAG_DEFAULT,
-                GC_OPT_FLAG_NONE );
-        printf ("disable-crl-checks:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("disable-trusted-cert-crl-check:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("enable-ocsp:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("include-certs:%lu:1:\n",
-                GC_OPT_FLAG_DEFAULT );
-        printf ("disable-policy-checks:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("auto-issuer-key-retrieve:%lu:\n",
-                GC_OPT_FLAG_NONE );
+        printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE);
+       printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE);
+       printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
+       printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
+        printf ("disable-crl-checks:%lu:\n", GC_OPT_FLAG_NONE);
+        printf ("disable-trusted-cert-crl-check:%lu:\n", GC_OPT_FLAG_NONE);
+        printf ("enable-ocsp:%lu:\n", GC_OPT_FLAG_NONE);
+        printf ("include-certs:%lu:1:\n", GC_OPT_FLAG_DEFAULT);
+        printf ("disable-policy-checks:%lu:\n", GC_OPT_FLAG_NONE);
+        printf ("auto-issuer-key-retrieve:%lu:\n", GC_OPT_FLAG_NONE);
+        printf ("disable-dirmngr:%lu:\n", GC_OPT_FLAG_NONE);
 #ifndef HAVE_W32_SYSTEM
-        printf ("prefer-system-dirmngr:%lu:\n",
-                GC_OPT_FLAG_NONE );
+        printf ("prefer-system-dirmngr:%lu:\n", GC_OPT_FLAG_NONE);
 #endif
-        printf ("cipher-algo:%lu:\"3DES:\n",
-                GC_OPT_FLAG_DEFAULT );
-        printf ("p12-charset:%lu:\n",
-                GC_OPT_FLAG_DEFAULT );
-        printf ("default-key:%lu:\n",
-                GC_OPT_FLAG_DEFAULT );
-        printf ("encrypt-to:%lu:\n",
-                GC_OPT_FLAG_DEFAULT );
+        printf ("cipher-algo:%lu:\"3DES:\n", GC_OPT_FLAG_DEFAULT);
+        printf ("p12-charset:%lu:\n", GC_OPT_FLAG_DEFAULT);
+        printf ("default-key:%lu:\n", GC_OPT_FLAG_DEFAULT);
+        printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_DEFAULT);
+       printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE);
 
       }
       break;
@@ -1752,7 +1904,7 @@ main ( int argc, char **argv)
         FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
 
         if (argc == 1)
-          gpgsm_p12_export (&ctrl, *argv, stdout);
+          gpgsm_p12_export (&ctrl, *argv, fp);
         else
           wrong_args ("--export-secret-key-p12 KEY-ID");
         if (fp != stdout)
@@ -1813,11 +1965,22 @@ main ( int argc, char **argv)
 
 
     default:
-        log_error ("invalid command (there is no implicit command)\n");
+        log_error (_("invalid command (there is no implicit command)\n"));
        break;
     }
+
+  /* Print the audit result if needed.  */
+  if (auditlog && auditfp)
+    {
+      audit_print_result (ctrl.audit, auditfp, 0);
+      audit_release (ctrl.audit);
+      ctrl.audit = NULL;
+      es_fclose (auditfp);
+    }
   
   /* cleanup */
+  keyserver_list_free (opt.keyserver);
+  opt.keyserver = NULL;
   gpgsm_release_certlist (recplist);
   gpgsm_release_certlist (signerlist);
   FREE_STRLIST (remusr);