gpg: Relax printing of STATUS_FAILURE.
[gnupg.git] / g10 / gpg.c
index 5361d6c..aaeddee 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1,7 +1,7 @@
 /* gpg.c - The GnuPG utility (main for gpg)
  * Copyright (C) 1998-2011 Free Software Foundation, Inc.
- * Copyright (C) 1997-2016 Werner Koch
- * Copyright (C) 2015-2016 g10 Code GmbH
+ * Copyright (C) 1997-2017 Werner Koch
+ * Copyright (C) 2015-2017 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
 #include "gpg.h"
 #include <assuan.h>
 #include "../common/iobuf.h"
-#include "util.h"
+#include "../common/util.h"
 #include "packet.h"
-#include "membuf.h"
+#include "../common/membuf.h"
 #include "main.h"
 #include "options.h"
 #include "keydb.h"
 #include "trustdb.h"
 #include "filter.h"
-#include "ttyio.h"
-#include "i18n.h"
-#include "sysutils.h"
-#include "status.h"
+#include "../common/ttyio.h"
+#include "../common/i18n.h"
+#include "../common/sysutils.h"
+#include "../common/status.h"
 #include "keyserver-internal.h"
 #include "exec.h"
-#include "gc-opt-flags.h"
-#include "asshelp.h"
+#include "../common/gc-opt-flags.h"
+#include "../common/asshelp.h"
 #include "call-dirmngr.h"
 #include "tofu.h"
 #include "../common/init.h"
 #include "../common/mbox-util.h"
 #include "../common/shareddefs.h"
+#include "../common/compliance.h"
 
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
 #define MY_O_BINARY  O_BINARY
@@ -73,6 +74,9 @@
 #define MY_O_BINARY  0
 #endif
 
+#ifdef __MINGW32__
+int _dowildcard = -1;
+#endif
 
 enum cmd_and_opt_values
   {
@@ -124,6 +128,7 @@ enum cmd_and_opt_values
     aQuickAddKey,
     aQuickRevUid,
     aQuickSetExpire,
+    aQuickSetPrimaryUid,
     aListConfig,
     aListGcryptConfig,
     aGPGConfList,
@@ -196,6 +201,7 @@ enum cmd_and_opt_values
     oWithWKDHash,
     oWithColons,
     oWithKeyData,
+    oWithKeyOrigin,
     oWithTofuInfo,
     oWithSigList,
     oWithSigCheck,
@@ -368,6 +374,7 @@ enum cmd_and_opt_values
     oPersonalCompressPreferences,
     oAgentProgram,
     oDirmngrProgram,
+    oDisableDirmngr,
     oDisplay,
     oTTYname,
     oTTYtype,
@@ -414,6 +421,9 @@ enum cmd_and_opt_values
     oOnlySignTextIDs,
     oDisableSignerUID,
     oSender,
+    oKeyOrigin,
+    oRequestOrigin,
+    oNoSymkeyCache,
 
     oNoop
   };
@@ -439,23 +449,34 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aListKeys, "list-public-keys", "@" ),
   ARGPARSE_c (aListSigs, "list-signatures", N_("list keys and signatures")),
   ARGPARSE_c (aListSigs, "list-sigs", "@"),
-  ARGPARSE_c (aCheckKeys, "check-sigs",N_("list and check key signatures")),
+  ARGPARSE_c (aCheckKeys, "check-signatures",
+             N_("list and check key signatures")),
+  ARGPARSE_c (aCheckKeys, "check-sigs", "@"),
   ARGPARSE_c (oFingerprint, "fingerprint", N_("list keys and fingerprints")),
   ARGPARSE_c (aListSecretKeys, "list-secret-keys", N_("list secret keys")),
-  ARGPARSE_c (aKeygen,     "gen-key",
+  ARGPARSE_c (aKeygen,     "generate-key",
               N_("generate a new key pair")),
-  ARGPARSE_c (aQuickKeygen, "quick-gen-key" ,
+  ARGPARSE_c (aKeygen,     "gen-key", "@"),
+  ARGPARSE_c (aQuickKeygen, "quick-generate-key" ,
               N_("quickly generate a new key pair")),
-  ARGPARSE_c (aQuickAddUid,  "quick-adduid",
+  ARGPARSE_c (aQuickKeygen, "quick-gen-key", "@"),
+  ARGPARSE_c (aQuickAddUid,  "quick-add-uid",
               N_("quickly add a new user-id")),
+  ARGPARSE_c (aQuickAddUid,  "quick-adduid", "@"),
+  ARGPARSE_c (aQuickAddKey,  "quick-add-key", "@"),
   ARGPARSE_c (aQuickAddKey,  "quick-addkey", "@"),
-  ARGPARSE_c (aQuickRevUid,  "quick-revuid",
+  ARGPARSE_c (aQuickRevUid,  "quick-revoke-uid",
               N_("quickly revoke a user-id")),
+  ARGPARSE_c (aQuickRevUid,  "quick-revuid", "@"),
   ARGPARSE_c (aQuickSetExpire,  "quick-set-expire",
               N_("quickly set a new expiration date")),
-  ARGPARSE_c (aFullKeygen,  "full-gen-key" ,
+  ARGPARSE_c (aQuickSetPrimaryUid,  "quick-set-primary-uid", "@"),
+  ARGPARSE_c (aFullKeygen,  "full-generate-key" ,
               N_("full featured key pair generation")),
-  ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
+  ARGPARSE_c (aFullKeygen,  "full-gen-key", "@"),
+  ARGPARSE_c (aGenRevoke, "generate-revocation",
+             N_("generate a revocation certificate")),
+  ARGPARSE_c (aGenRevoke, "gen-revoke", "@"),
   ARGPARSE_c (aDeleteKeys,"delete-keys",
               N_("remove keys from the public keyring")),
   ARGPARSE_c (aDeleteSecretKeys, "delete-secret-keys",
@@ -468,7 +489,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aLSignKey, "lsign-key"  ,N_("sign a key locally")),
   ARGPARSE_c (aEditKey,  "edit-key"   ,N_("sign or edit a key")),
   ARGPARSE_c (aEditKey,  "key-edit"   ,"@"),
-  ARGPARSE_c (aPasswd,   "passwd",     N_("change a passphrase")),
+  ARGPARSE_c (aPasswd,   "change-passphrase", N_("change a passphrase")),
+  ARGPARSE_c (aPasswd,   "passwd", "@"),
+  ARGPARSE_c (aDesigRevoke, "generate-designated-revocation", "@"),
   ARGPARSE_c (aDesigRevoke, "desig-revoke","@" ),
   ARGPARSE_c (aExport, "export"           , N_("export keys") ),
   ARGPARSE_c (aSendKeys, "send-keys"     , N_("export keys to a keyserver") ),
@@ -487,7 +510,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aFastImport, "fast-import", "@"),
 #ifdef ENABLE_CARD_SUPPORT
   ARGPARSE_c (aCardStatus,  "card-status", N_("print the card status")),
-  ARGPARSE_c (aCardEdit,   "card-edit",  N_("change data on a card")),
+  ARGPARSE_c (aCardEdit,   "edit-card",  N_("change data on a card")),
+  ARGPARSE_c (aCardEdit,   "card-edit", "@"),
   ARGPARSE_c (aChangePIN,  "change-pin", N_("change a card's PIN")),
 #endif
   ARGPARSE_c (aListConfig, "list-config", "@"),
@@ -596,6 +620,7 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
   ARGPARSE_s_s (oKeyServerOptions, "keyserver-options", "@"),
+  ARGPARSE_s_s (oKeyOrigin, "key-origin", "@"),
   ARGPARSE_s_s (oImportOptions, "import-options", "@"),
   ARGPARSE_s_s (oImportFilter,  "import-filter", "@"),
   ARGPARSE_s_s (oExportOptions, "export-options", "@"),
@@ -685,6 +710,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oPassphraseFile,  "passphrase-file", "@"),
   ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
   ARGPARSE_s_s (oPinentryMode,    "pinentry-mode", "@"),
+  ARGPARSE_s_s (oRequestOrigin,   "request-origin", "@"),
   ARGPARSE_s_i (oCommandFD, "command-fd", "@"),
   ARGPARSE_s_s (oCommandFile, "command-file", "@"),
   ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
@@ -715,9 +741,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oWithKeyData,"with-key-data", "@"),
   ARGPARSE_s_n (oWithSigList,"with-sig-list", "@"),
   ARGPARSE_s_n (oWithSigCheck,"with-sig-check", "@"),
-  ARGPARSE_s_n (aListKeys, "list-key", "@"),   /* alias */
-  ARGPARSE_s_n (aListSigs, "list-sig", "@"),   /* alias */
-  ARGPARSE_s_n (aCheckKeys, "check-sig", "@"), /* alias */
+  ARGPARSE_c (aListKeys, "list-key", "@"),   /* alias */
+  ARGPARSE_c (aListSigs, "list-sig", "@"),   /* alias */
+  ARGPARSE_c (aCheckKeys, "check-sig", "@"), /* alias */
   ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"),
   ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"),
   ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
@@ -764,6 +790,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
   ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
   ARGPARSE_s_n (oWithWKDHash,     "with-wkd-hash", "@"),
+  ARGPARSE_s_n (oWithKeyOrigin,   "with-key-origin", "@"),
   ARGPARSE_s_s (oDisableCipherAlgo,  "disable-cipher-algo", "@"),
   ARGPARSE_s_s (oDisablePubkeyAlgo,  "disable-pubkey-algo", "@"),
   ARGPARSE_s_n (oAllowNonSelfsignedUID,      "allow-non-selfsigned-uid", "@"),
@@ -814,6 +841,7 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
   ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
+  ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", "@"),
   ARGPARSE_s_s (oDisplay,    "display",    "@"),
   ARGPARSE_s_s (oTTYname,    "ttyname",    "@"),
   ARGPARSE_s_s (oTTYtype,    "ttytype",    "@"),
@@ -861,6 +889,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oAutoKeyLocate, "auto-key-locate", "@"),
   ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"),
   ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
+  ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
 
   /* Dummy options with warnings.  */
   ARGPARSE_s_n (oUseAgent,      "use-agent", "@"),
@@ -900,7 +929,6 @@ static struct debug_flags_s debug_flags [] =
     { DBG_MEMSTAT_VALUE, "memstat" },
     { DBG_TRUST_VALUE  , "trust"   },
     { DBG_HASHING_VALUE, "hashing" },
-    { DBG_CARD_IO_VALUE, "cardio"  },
     { DBG_IPC_VALUE    , "ipc"     },
     { DBG_CLOCK_VALUE  , "clock"   },
     { DBG_LOOKUP_VALUE , "lookup"  },
@@ -1140,6 +1168,7 @@ static void
 wrong_args( const char *text)
 {
   es_fprintf (es_stderr, _("usage: %s [options] %s\n"), GPG_NAME, text);
+  log_inc_errorcount ();
   g10_exit(2);
 }
 
@@ -1828,9 +1857,17 @@ gpgconf_list (const char *configfile)
   es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("try-secret-key:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("auto-key-locate:%lu:\n", GC_OPT_FLAG_NONE);
+  es_printf ("auto-key-retrieve:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
   es_printf ("group:%lu:\n", GC_OPT_FLAG_NONE);
+  es_printf ("compliance:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "gnupg");
+  es_printf ("default-new-key-algo:%lu:\n", GC_OPT_FLAG_NONE);
+  es_printf ("trust-model:%lu:\n", GC_OPT_FLAG_NONE);
+  es_printf ("disable-dirmngr:%lu:\n", GC_OPT_FLAG_NONE);
+  es_printf ("max-cert-depth:%lu:\n", GC_OPT_FLAG_NONE);
+  es_printf ("completes-needed:%lu:\n", GC_OPT_FLAG_NONE);
+  es_printf ("marginals-needed:%lu:\n", GC_OPT_FLAG_NONE);
 
   /* The next one is an info only item and should match the macros at
      the top of keygen.c  */
@@ -2052,11 +2089,8 @@ parse_tofu_policy (const char *policystr)
 }
 
 
-/* Parse the value of --compliance.  */
-static int
-parse_compliance_option (const char *string)
-{
-  struct { const char *keyword; enum cmd_and_opt_values option; } list[] = {
+static struct gnupg_compliance_option compliance_options[] =
+  {
     { "gnupg",      oGnuPG },
     { "openpgp",    oOpenPGP },
     { "rfc4880bis", oRFC4880bis },
@@ -2067,29 +2101,9 @@ parse_compliance_option (const char *string)
     { "pgp8",       oPGP8 },
     { "de-vs",      oDE_VS }
   };
-  int i;
 
-  if (!ascii_strcasecmp (string, "help"))
-    {
-      log_info (_("valid values for option '%s':\n"), "--compliance");
-      for (i=0; i < DIM (list); i++)
-        log_info ("  %s\n", list[i].keyword);
-      g10_exit (1);
-    }
 
-  for (i=0; i < DIM (list); i++)
-    if (!ascii_strcasecmp (string, list[i].keyword))
-      return list[i].option;
-
-  log_error (_("invalid value for option '%s'\n"), "--compliance");
-  if (!opt.quiet)
-    log_info (_("(use \"help\" to list choices)\n"));
-  g10_exit (1);
-}
-
-
-
-/* Helper to set compliance related options.  This is a separte
+/* Helper to set compliance related options.  This is a separate
  * function so that it can also be used by the --compliance option
  * parser.  */
 static void
@@ -2145,6 +2159,7 @@ set_compliance_option (enum cmd_and_opt_values option)
     case oDE_VS:
       set_compliance_option (oOpenPGP);
       opt.compliance = CO_DE_VS;
+      opt.force_mdc = 1;
       /* Fixme: Change other options.  */
       break;
 
@@ -2164,7 +2179,7 @@ set_compliance_option (enum cmd_and_opt_values option)
 static void
 gpg_init_default_ctrl (ctrl_t ctrl)
 {
-  (void)ctrl;
+  ctrl->magic = SERVER_CONTROL_MAGIC;
 }
 
 
@@ -2177,6 +2192,8 @@ gpg_deinit_default_ctrl (ctrl_t ctrl)
   tofu_closedbs (ctrl);
 #endif
   gpg_dirmngr_deinit_session_data (ctrl);
+
+  keydb_release (ctrl->cached_getkey_kdb);
 }
 
 
@@ -2286,6 +2303,7 @@ main (int argc, char **argv)
     int ovrseskeyfd = -1;
     int fpr_maybe_cmd = 0; /* --fingerprint maybe a command.  */
     int any_explicit_recipient = 0;
+    int default_akl = 1;
     int require_secmem = 0;
     int got_secmem = 0;
     struct assuan_malloc_hooks malloc_hooks;
@@ -2326,6 +2344,9 @@ main (int argc, char **argv)
 
     dotlock_create (NULL, 0); /* Register lock file cleanup. */
 
+    /* Tell the compliance module who we are.  */
+    gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPG);
+
     opt.autostart = 1;
     opt.session_env = session_env_new ();
     if (!opt.session_env)
@@ -2348,9 +2369,10 @@ main (int argc, char **argv)
     opt.max_cert_depth = 5;
     opt.escape_from = 1;
     opt.flags.require_cross_cert = 1;
-    opt.import_options = 0;
+    opt.import_options = IMPORT_REPAIR_KEYS;
     opt.export_options = EXPORT_ATTRIBUTES;
-    opt.keyserver_options.import_options = IMPORT_REPAIR_PKS_SUBKEY_BUG;
+    opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS
+                                           | IMPORT_REPAIR_PKS_SUBKEY_BUG);
     opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
     opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD;
     opt.verify_options = (LIST_SHOW_UID_VALIDITY
@@ -2375,7 +2397,6 @@ main (int argc, char **argv)
     opt.passphrase_repeat = 1;
     opt.emit_version = 0;
     opt.weak_digests = NULL;
-    additional_weak_digest("MD5");
 
     /* Check whether we have a config file on the command line.  */
     orig_argc = argc;
@@ -2451,6 +2472,10 @@ main (int argc, char **argv)
     assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
     setup_libassuan_logging (&opt.debug, NULL);
 
+    /* Set default options which require that malloc stuff is ready.  */
+    additional_weak_digest ("MD5");
+    parse_auto_key_locate ("local,wkd");
+
     /* Try for a version specific config file first */
     default_configname = get_default_configname ();
     if (default_config)
@@ -2565,6 +2590,7 @@ main (int argc, char **argv)
          case aQuickAddKey:
          case aQuickRevUid:
          case aQuickSetExpire:
+         case aQuickSetPrimaryUid:
          case aExportOwnerTrust:
          case aImportOwnerTrust:
           case aRebuildKeydbCaches:
@@ -2724,6 +2750,10 @@ main (int argc, char **argv)
             opt.with_wkd_hash = 1;
             break;
 
+         case oWithKeyOrigin:
+            opt.with_key_origin = 1;
+            break;
+
          case oSecretKeyring:
             /* Ignore this old option.  */
             break;
@@ -2837,7 +2867,15 @@ main (int argc, char **argv)
            break;
 
           case oCompliance:
-            set_compliance_option (parse_compliance_option (pargs.r.ret_str));
+           {
+             int compliance = gnupg_parse_compliance_option
+                (pargs.r.ret_str,
+                 compliance_options, DIM (compliance_options),
+                 opt.quiet);
+             if (compliance < 0)
+               g10_exit (1);
+             set_compliance_option (compliance);
+           }
             break;
           case oOpenPGP:
           case oRFC2440:
@@ -3063,8 +3101,16 @@ main (int argc, char **argv)
               log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
            break;
 
+          case oRequestOrigin:
+           opt.request_origin = parse_request_origin (pargs.r.ret_str);
+           if (opt.request_origin == -1)
+              log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
+           break;
+
          case oCommandFD:
             opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
+           if (! gnupg_fd_valid (opt.command_fd))
+             log_error ("command-fd is invalid: %s\n", strerror (errno));
             break;
          case oCommandFile:
             opt.command_fd = open_info_file (pargs.r.ret_str, 0, 1);
@@ -3301,13 +3347,14 @@ main (int argc, char **argv)
          case oIgnoreCrcError: opt.ignore_crc_error = 1; break;
          case oIgnoreMDCError: opt.ignore_mdc_error = 1; break;
          case oNoRandomSeedFile: use_random_seed = 0; break;
+
          case oAutoKeyRetrieve:
+            opt.keyserver_options.options |= KEYSERVER_AUTO_KEY_RETRIEVE;
+            break;
          case oNoAutoKeyRetrieve:
-               if(pargs.r_opt==oAutoKeyRetrieve)
-                 opt.keyserver_options.options|=KEYSERVER_AUTO_KEY_RETRIEVE;
-               else
-                 opt.keyserver_options.options&=~KEYSERVER_AUTO_KEY_RETRIEVE;
-               break;
+            opt.keyserver_options.options &= ~KEYSERVER_AUTO_KEY_RETRIEVE;
+            break;
+
          case oShowSessionKey: opt.show_session_key = 1; break;
          case oOverrideSessionKey:
                opt.override_session_key = pargs.r.ret_str;
@@ -3358,6 +3405,7 @@ main (int argc, char **argv)
            break;
           case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
           case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
+         case oDisableDirmngr: opt.disable_dirmngr = 1;  break;
           case oWeakDigest:
            additional_weak_digest(pargs.r.ret_str);
            break;
@@ -3432,6 +3480,13 @@ main (int argc, char **argv)
          case oNoRequireCrossCert: opt.flags.require_cross_cert=0; break;
 
          case oAutoKeyLocate:
+            if (default_akl)
+              {
+                /* This is the first time --aito-key-locate is seen.
+                 * We need to reset the default akl.  */
+                default_akl = 0;
+                release_akl();
+              }
            if(!parse_auto_key_locate(pargs.r.ret_str))
              {
                if(configname)
@@ -3445,6 +3500,12 @@ main (int argc, char **argv)
            release_akl();
            break;
 
+         case oKeyOrigin:
+           if(!parse_key_origin (pargs.r.ret_str))
+              log_error (_("invalid argument for option \"%.50s\"\n"),
+                         "--key-origin");
+           break;
+
          case oEnableLargeRSA:
 #if SECMEM_BUFFER_SIZE >= 65536
             opt.flags.large_rsa=1;
@@ -3479,14 +3540,25 @@ main (int argc, char **argv)
 
           case oFakedSystemTime:
             {
-              time_t faked_time = isotime2epoch (pargs.r.ret_str);
+              size_t len = strlen (pargs.r.ret_str);
+              int freeze = 0;
+              time_t faked_time;
+
+              if (len > 0 && pargs.r.ret_str[len-1] == '!')
+                {
+                  freeze = 1;
+                  pargs.r.ret_str[len-1] = '\0';
+                }
+
+              faked_time = isotime2epoch (pargs.r.ret_str);
               if (faked_time == (time_t)(-1))
                 faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
-              gnupg_set_time (faked_time, 0);
+              gnupg_set_time (faked_time, freeze);
             }
             break;
 
           case oNoAutostart: opt.autostart = 0; break;
+          case oNoSymkeyCache: opt.no_symkey_cache = 1; break;
 
          case oDefaultNewKeyAlgo:
             opt.def_new_key_algo = pargs.r.ret_str;
@@ -3495,7 +3567,16 @@ main (int argc, char **argv)
          case oNoop: break;
 
          default:
-            pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
+            if (configfp)
+              pargs.err = ARGPARSE_PRINT_WARNING;
+            else
+              {
+                pargs.err = ARGPARSE_PRINT_ERROR;
+                /* The argparse fucntion calls a plain exit and thus
+                 * we need to print a status here.  */
+                write_status_failure ("option-parser",
+                                      gpg_error(GPG_ERR_GENERAL));
+              }
             break;
          }
       }
@@ -3514,7 +3595,10 @@ main (int argc, char **argv)
       }
     xfree(configname); configname = NULL;
     if (log_get_errorcount (0))
-      g10_exit(2);
+      {
+        write_status_failure ("option-parser", gpg_error(GPG_ERR_GENERAL));
+        g10_exit(2);
+      }
 
     /* The command --gpgconf-list is pretty simple and may be called
        directly after the option parsing. */
@@ -3535,7 +3619,10 @@ main (int argc, char **argv)
                  "--print-pks-records",
                  "--export-options export-pka");
     if (log_get_errorcount (0))
-      g10_exit(2);
+      {
+        write_status_failure ("option-checking", gpg_error(GPG_ERR_GENERAL));
+        g10_exit(2);
+      }
 
 
     if( nogreeting )
@@ -3636,6 +3723,7 @@ main (int argc, char **argv)
       {
        log_info(_("will not run with insecure memory due to %s\n"),
                 "--require-secmem");
+        write_status_failure ("option-checking", gpg_error(GPG_ERR_GENERAL));
        g10_exit(2);
       }
 
@@ -3776,7 +3864,11 @@ main (int argc, char **argv)
       }
 
     if( log_get_errorcount(0) )
-       g10_exit(2);
+      {
+        write_status_failure ("option-postprocessing",
+                              gpg_error(GPG_ERR_GENERAL));
+       g10_exit (2);
+      }
 
     if(opt.compress_level==0)
       opt.compress_algo=COMPRESS_ALGO_NONE;
@@ -3819,19 +3911,22 @@ main (int argc, char **argv)
            switch(badtype)
              {
              case PREFTYPE_SYM:
-               log_info(_("you may not use cipher algorithm '%s'"
-                          " while in %s mode\n"),
-                        badalg,compliance_option_string());
+               log_info (_("cipher algorithm '%s'"
+                            " may not be used in %s mode\n"),
+                        badalg,
+                          gnupg_compliance_option_string (opt.compliance));
                break;
              case PREFTYPE_HASH:
-               log_info(_("you may not use digest algorithm '%s'"
-                          " while in %s mode\n"),
-                        badalg,compliance_option_string());
+               log_info (_("digest algorithm '%s'"
+                            " may not be used in %s mode\n"),
+                          badalg,
+                          gnupg_compliance_option_string (opt.compliance));
                break;
              case PREFTYPE_ZIP:
-               log_info(_("you may not use compression algorithm '%s'"
-                          " while in %s mode\n"),
-                        badalg,compliance_option_string());
+               log_info (_("compression algorithm '%s'"
+                            " may not be used in %s mode\n"),
+                          badalg,
+                          gnupg_compliance_option_string (opt.compliance));
                break;
              default:
                BUG();
@@ -3841,6 +3936,44 @@ main (int argc, char **argv)
          }
       }
 
+    /* Check our chosen algorithms against the list of allowed
+     * algorithms in the current compliance mode, and fail hard if it
+     * is not.  This is us being nice to the user informing her early
+     * that the chosen algorithms are not available.  We also check
+     * and enforce this right before the actual operation.  */
+    if (opt.def_cipher_algo
+       && ! gnupg_cipher_is_allowed (opt.compliance,
+                                     cmd == aEncr
+                                     || cmd == aSignEncr
+                                     || cmd == aEncrSym
+                                     || cmd == aSym
+                                     || cmd == aSignSym
+                                     || cmd == aSignEncrSym,
+                                     opt.def_cipher_algo,
+                                     GCRY_CIPHER_MODE_NONE))
+      log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
+                openpgp_cipher_algo_name (opt.def_cipher_algo),
+                gnupg_compliance_option_string (opt.compliance));
+
+    if (opt.def_digest_algo
+       && ! gnupg_digest_is_allowed (opt.compliance,
+                                     cmd == aSign
+                                     || cmd == aSignEncr
+                                     || cmd == aSignEncrSym
+                                     || cmd == aSignSym
+                                     || cmd == aClearsign,
+                                     opt.def_digest_algo))
+      log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
+                gcry_md_algo_name (opt.def_digest_algo),
+                gnupg_compliance_option_string (opt.compliance));
+
+    /* Fail hard.  */
+    if (log_get_errorcount (0))
+      {
+        write_status_failure ("option-checking", gpg_error(GPG_ERR_GENERAL));
+       g10_exit (2);
+      }
+
     /* Set the random seed file. */
     if( use_random_seed ) {
       char *p = make_filename (gnupg_homedir (), "random_seed", NULL );
@@ -3921,6 +4054,11 @@ main (int argc, char **argv)
       case aListTrustDB:
         rc = setup_trustdb (argc? 1:0, trustdb_name);
         break;
+      case aKeygen:
+      case aFullKeygen:
+      case aQuickKeygen:
+        rc = setup_trustdb (1, trustdb_name);
+        break;
       default:
         /* If we are using TM_ALWAYS, we do not need to create the
            trustdb.  */
@@ -3969,6 +4107,7 @@ main (int argc, char **argv)
       case aQuickAddUid:
       case aQuickAddKey:
       case aQuickRevUid:
+      case aQuickSetPrimaryUid:
       case aFullKeygen:
       case aKeygen:
       case aImport:
@@ -3997,7 +4136,7 @@ main (int argc, char **argv)
 
       case aStore: /* only store the file */
        if( argc > 1 )
-           wrong_args(_("--store [filename]"));
+           wrong_args("--store [filename]");
        if( (rc = encrypt_store(fname)) )
           {
             write_status_failure ("store", rc);
@@ -4007,7 +4146,7 @@ main (int argc, char **argv)
        break;
       case aSym: /* encrypt the given file only with the symmetric cipher */
        if( argc > 1 )
-           wrong_args(_("--symmetric [filename]"));
+           wrong_args("--symmetric [filename]");
        if( (rc = encrypt_symmetric(fname)) )
           {
             write_status_failure ("symencrypt", rc);
@@ -4022,7 +4161,7 @@ main (int argc, char **argv)
        else
          {
            if( argc > 1 )
-             wrong_args(_("--encrypt [filename]"));
+             wrong_args("--encrypt [filename]");
            if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 0, NULL, -1)) )
               {
                 write_status_failure ("encrypt", rc);
@@ -4038,13 +4177,14 @@ main (int argc, char **argv)
           might work with 7, but alas, I don't have a copy to test
           with right now. */
        if( argc > 1 )
-         wrong_args(_("--symmetric --encrypt [filename]"));
+         wrong_args("--symmetric --encrypt [filename]");
        else if(opt.s2k_mode==0)
          log_error(_("you cannot use --symmetric --encrypt"
                      " with --s2k-mode 0\n"));
        else if(PGP6 || PGP7)
          log_error(_("you cannot use --symmetric --encrypt"
-                     " while in %s mode\n"),compliance_option_string());
+                     " in %s mode\n"),
+                   gnupg_compliance_option_string (opt.compliance));
        else
          {
            if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 1, NULL, -1)) )
@@ -4064,7 +4204,7 @@ main (int argc, char **argv)
        }
        else {
            if( argc > 1 )
-               wrong_args(_("--sign [filename]"));
+               wrong_args("--sign [filename]");
            if( argc ) {
                sl = xmalloc_clear( sizeof *sl + strlen(fname));
                strcpy(sl->d, fname);
@@ -4080,7 +4220,7 @@ main (int argc, char **argv)
 
       case aSignEncr: /* sign and encrypt the given file */
        if( argc > 1 )
-           wrong_args(_("--sign --encrypt [filename]"));
+           wrong_args("--sign --encrypt [filename]");
        if( argc ) {
            sl = xmalloc_clear( sizeof *sl + strlen(fname));
            strcpy(sl->d, fname);
@@ -4098,13 +4238,14 @@ main (int argc, char **argv)
 
       case aSignEncrSym: /* sign and encrypt the given file */
        if( argc > 1 )
-           wrong_args(_("--symmetric --sign --encrypt [filename]"));
+           wrong_args("--symmetric --sign --encrypt [filename]");
        else if(opt.s2k_mode==0)
          log_error(_("you cannot use --symmetric --sign --encrypt"
                      " with --s2k-mode 0\n"));
        else if(PGP6 || PGP7)
          log_error(_("you cannot use --symmetric --sign --encrypt"
-                     " while in %s mode\n"),compliance_option_string());
+                     " in %s mode\n"),
+                   gnupg_compliance_option_string (opt.compliance));
        else
          {
            if( argc )
@@ -4127,7 +4268,7 @@ main (int argc, char **argv)
 
       case aSignSym: /* sign and conventionally encrypt the given file */
        if (argc > 1)
-           wrong_args(_("--sign --symmetric [filename]"));
+           wrong_args("--sign --symmetric [filename]");
        rc = sign_symencrypt_file (ctrl, fname, locusr);
         if (rc)
           {
@@ -4139,7 +4280,7 @@ main (int argc, char **argv)
 
       case aClearsign: /* make a clearsig */
        if( argc > 1 )
-           wrong_args(_("--clear-sign [filename]"));
+           wrong_args("--clear-sign [filename]");
        if( (rc = clearsign_file (ctrl, fname, locusr, NULL)) )
           {
             write_status_failure ("sign", rc);
@@ -4169,7 +4310,7 @@ main (int argc, char **argv)
        else
          {
            if( argc > 1 )
-             wrong_args(_("--decrypt [filename]"));
+             wrong_args("--decrypt [filename]");
            if( (rc = decrypt_message (ctrl, fname) ))
               {
                 write_status_failure ("decrypt", rc);
@@ -4196,11 +4337,11 @@ main (int argc, char **argv)
 
       case aSignKey:
        if( argc != 1 )
-         wrong_args(_("--sign-key user-id"));
+         wrong_args("--sign-key user-id");
        /* fall through */
       case aLSignKey:
        if( argc != 1 )
-         wrong_args(_("--lsign-key user-id"));
+         wrong_args("--lsign-key user-id");
        /* fall through */
 
        sl=NULL;
@@ -4221,7 +4362,7 @@ main (int argc, char **argv)
 
       case aEditKey: /* Edit a key signature */
        if( !argc )
-           wrong_args(_("--edit-key user-id [commands]"));
+           wrong_args("--edit-key user-id [commands]");
        username = make_username( fname );
        if( argc > 1 ) {
            sl = NULL;
@@ -4237,7 +4378,7 @@ main (int argc, char **argv)
 
       case aPasswd:
         if (argc != 1)
-          wrong_args (_("--passwd <user-id>"));
+          wrong_args("--change-passphrase <user-id>");
         else
           {
             username = make_username (fname);
@@ -4255,14 +4396,15 @@ main (int argc, char **argv)
            proper order :) */
        for( ; argc; argc-- )
          add_to_strlist2( &sl, argv[argc-1], utf8_strings );
-       delete_keys(sl,cmd==aDeleteSecretKeys,cmd==aDeleteSecretAndPublicKeys);
+       delete_keys (ctrl, sl,
+                     cmd==aDeleteSecretKeys, cmd==aDeleteSecretAndPublicKeys);
        free_strlist(sl);
        break;
 
       case aCheckKeys:
-       opt.check_sigs = 1;
+       opt.check_sigs = 1; /* fall through */
       case aListSigs:
-       opt.list_sigs = 1;
+       opt.list_sigs = 1; /* fall through */
       case aListKeys:
        sl = NULL;
        for( ; argc; argc--, argv++ )
@@ -4290,7 +4432,7 @@ main (int argc, char **argv)
           const char *x_algo, *x_usage, *x_expire;
 
           if (argc < 1 || argc > 4)
-            wrong_args("--quick-gen-key USER-ID [ALGO [USAGE [EXPIRE]]]");
+            wrong_args("--quick-generate-key USER-ID [ALGO [USAGE [EXPIRE]]]");
           username = make_username (fname);
           argv++, argc--;
           x_algo = "";
@@ -4316,20 +4458,20 @@ main (int argc, char **argv)
       case aKeygen: /* generate a key */
        if( opt.batch ) {
            if( argc > 1 )
-               wrong_args("--gen-key [parameterfile]");
+               wrong_args("--generate-key [parameterfile]");
            generate_keypair (ctrl, 0, argc? *argv : NULL, NULL, 0);
        }
        else {
             if (opt.command_fd != -1 && argc)
               {
                 if( argc > 1 )
-                  wrong_args("--gen-key [parameterfile]");
+                  wrong_args("--generate-key [parameterfile]");
 
                 opt.batch = 1;
                 generate_keypair (ctrl, 0, argc? *argv : NULL, NULL, 0);
               }
             else if (argc)
-              wrong_args ("--gen-key");
+              wrong_args ("--generate-key");
             else
               generate_keypair (ctrl, 0, NULL, NULL, 0);
        }
@@ -4339,13 +4481,13 @@ main (int argc, char **argv)
        if (opt.batch)
           {
            if (argc > 1)
-              wrong_args ("--full-gen-key [parameterfile]");
+              wrong_args ("--full-generate-key [parameterfile]");
            generate_keypair (ctrl, 1, argc? *argv : NULL, NULL, 0);
           }
        else
           {
            if (argc)
-              wrong_args("--full-gen-key");
+              wrong_args("--full-generate-key");
            generate_keypair (ctrl, 1, NULL, NULL, 0);
        }
        break;
@@ -4355,7 +4497,7 @@ main (int argc, char **argv)
           const char *uid, *newuid;
 
           if (argc != 2)
-            wrong_args ("--quick-adduid USER-ID NEW-USER-ID");
+            wrong_args ("--quick-add-uid USER-ID NEW-USER-ID");
           uid = *argv++; argc--;
           newuid = *argv++; argc--;
           keyedit_quick_adduid (ctrl, uid, newuid);
@@ -4367,7 +4509,7 @@ main (int argc, char **argv)
           const char *x_fpr, *x_algo, *x_usage, *x_expire;
 
           if (argc < 1 || argc > 4)
-            wrong_args ("--quick-addkey FINGERPRINT [ALGO [USAGE [EXPIRE]]]");
+            wrong_args ("--quick-add-key FINGERPRINT [ALGO [USAGE [EXPIRE]]]");
           x_fpr = *argv++; argc--;
           x_algo = "";
           x_usage = "";
@@ -4393,7 +4535,7 @@ main (int argc, char **argv)
           const char *uid, *uidtorev;
 
           if (argc != 2)
-            wrong_args ("--quick-revuid USER-ID USER-ID-TO-REVOKE");
+            wrong_args ("--quick-revoke-uid USER-ID USER-ID-TO-REVOKE");
           uid = *argv++; argc--;
           uidtorev = *argv++; argc--;
           keyedit_quick_revuid (ctrl, uid, uidtorev);
@@ -4404,18 +4546,31 @@ main (int argc, char **argv)
         {
           const char *x_fpr, *x_expire;
 
-          if (argc != 2)
-            wrong_args ("--quick-set-exipre FINGERPRINT EXPIRE");
+          if (argc < 2)
+            wrong_args ("--quick-set-exipre FINGERPRINT EXPIRE [SUBKEY-FPRS]");
           x_fpr = *argv++; argc--;
           x_expire = *argv++; argc--;
-          keyedit_quick_set_expire (ctrl, x_fpr, x_expire);
+          keyedit_quick_set_expire (ctrl, x_fpr, x_expire, argv);
+        }
+       break;
+
+      case aQuickSetPrimaryUid:
+        {
+          const char *uid, *primaryuid;
+
+          if (argc != 2)
+            wrong_args ("--quick-set-primary-uid USER-ID PRIMARY-USER-ID");
+          uid = *argv++; argc--;
+          primaryuid = *argv++; argc--;
+          keyedit_quick_set_primary (ctrl, uid, primaryuid);
         }
        break;
 
       case aFastImport:
-        opt.import_options |= IMPORT_FAST;
+        opt.import_options |= IMPORT_FAST; /* fall through */
       case aImport:
-       import_keys (ctrl, argc? argv:NULL, argc, NULL, opt.import_options);
+       import_keys (ctrl, argc? argv:NULL, argc, NULL,
+                     opt.import_options, opt.key_origin, opt.key_origin_url);
        break;
 
        /* TODO: There are a number of command that use this same
@@ -4503,7 +4658,7 @@ main (int argc, char **argv)
        sl = NULL;
        for( ; argc; argc--, argv++ )
            append_to_strlist2( &sl, *argv, utf8_strings );
-       rc = keyserver_fetch (ctrl, sl);
+       rc = keyserver_fetch (ctrl, sl, opt.key_origin);
        if(rc)
           {
             write_status_failure ("fetch-keys", rc);
@@ -4518,7 +4673,7 @@ main (int argc, char **argv)
            add_to_strlist2( &sl, *argv, utf8_strings );
         {
           export_stats_t stats = export_new_stats ();
-          export_seckeys (ctrl, sl, stats);
+          export_seckeys (ctrl, sl, opt.export_options, stats);
           export_print_stats (stats);
           export_release_stats (stats);
         }
@@ -4531,7 +4686,7 @@ main (int argc, char **argv)
            add_to_strlist2( &sl, *argv, utf8_strings );
         {
           export_stats_t stats = export_new_stats ();
-          export_secsubkeys (ctrl, sl, stats);
+          export_secsubkeys (ctrl, sl, opt.export_options, stats);
           export_print_stats (stats);
           export_release_stats (stats);
         }
@@ -4540,15 +4695,15 @@ main (int argc, char **argv)
 
       case aGenRevoke:
        if( argc != 1 )
-           wrong_args("--gen-revoke user-id");
+           wrong_args("--generate-revocation user-id");
        username =  make_username(*argv);
-       gen_revoke( username );
+       gen_revoke (ctrl, username );
        xfree( username );
        break;
 
       case aDesigRevoke:
        if (argc != 1)
-           wrong_args ("--desig-revoke user-id");
+           wrong_args ("--generate-designated-revocation user-id");
        username = make_username (*argv);
        gen_desig_revoke (ctrl, username, locusr);
        xfree (username);
@@ -4689,10 +4844,10 @@ main (int argc, char **argv)
 #ifndef NO_TRUST_MODELS
       case aListTrustDB:
        if( !argc )
-          list_trustdb (es_stdout, NULL);
+          list_trustdb (ctrl, es_stdout, NULL);
        else {
            for( ; argc; argc--, argv++ )
-              list_trustdb (es_stdout, *argv );
+              list_trustdb (ctrl, es_stdout, *argv );
        }
        break;
 
@@ -4724,27 +4879,30 @@ main (int argc, char **argv)
       case aExportOwnerTrust:
        if( argc )
            wrong_args("--export-ownertrust");
-       export_ownertrust();
+       export_ownertrust (ctrl);
        break;
 
       case aImportOwnerTrust:
        if( argc > 1 )
            wrong_args("--import-ownertrust [file]");
-       import_ownertrust( argc? *argv:NULL );
+       import_ownertrust (ctrl, argc? *argv:NULL );
        break;
 #endif /*!NO_TRUST_MODELS*/
 
       case aRebuildKeydbCaches:
         if (argc)
             wrong_args ("--rebuild-keydb-caches");
-        keydb_rebuild_caches (1);
+        keydb_rebuild_caches (ctrl, 1);
         break;
 
 #ifdef ENABLE_CARD_SUPPORT
       case aCardStatus:
-        if (argc)
-            wrong_args ("--card-status");
-        card_status (es_stdout, NULL, 0);
+        if (argc == 0)
+            card_status (ctrl, es_stdout, NULL);
+        else if (argc == 1)
+            card_status (ctrl, es_stdout, *argv);
+        else
+            wrong_args ("--card-status [serialno]");
         break;
 
       case aCardEdit:
@@ -4798,7 +4956,10 @@ main (int argc, char **argv)
 
          hd = keydb_new ();
          if (! hd)
-            g10_exit (1);
+            {
+              write_status_failure ("tofu-driver", gpg_error(GPG_ERR_GENERAL));
+              g10_exit (1);
+            }
 
           tofu_begin_batch_update (ctrl);
 
@@ -4812,6 +4973,7 @@ main (int argc, char **argv)
                {
                  log_error (_("error parsing key specification '%s': %s\n"),
                              argv[i], gpg_strerror (rc));
+                  write_status_failure ("tofu-driver", rc);
                  g10_exit (1);
                }
 
@@ -4825,6 +4987,8 @@ main (int argc, char **argv)
                  log_error (_("'%s' does not appear to be a valid"
                               " key ID, fingerprint or keygrip\n"),
                             argv[i]);
+                  write_status_failure ("tofu-driver",
+                                        gpg_error(GPG_ERR_GENERAL));
                  g10_exit (1);
                }
 
@@ -4835,6 +4999,7 @@ main (int argc, char **argv)
                      the string.  */
                   log_error ("keydb_search_reset failed: %s\n",
                              gpg_strerror (rc));
+                  write_status_failure ("tofu-driver", rc);
                  g10_exit (1);
                }
 
@@ -4843,6 +5008,7 @@ main (int argc, char **argv)
                {
                  log_error (_("key \"%s\" not found: %s\n"), argv[i],
                              gpg_strerror (rc));
+                  write_status_failure ("tofu-driver", rc);
                  g10_exit (1);
                }
 
@@ -4851,12 +5017,16 @@ main (int argc, char **argv)
                {
                  log_error (_("error reading keyblock: %s\n"),
                              gpg_strerror (rc));
+                  write_status_failure ("tofu-driver", rc);
                  g10_exit (1);
                }
 
-             merge_keys_and_selfsig (kb);
+             merge_keys_and_selfsig (ctrl, kb);
              if (tofu_set_policy (ctrl, kb, policy))
-               g10_exit (1);
+                {
+                  write_status_failure ("tofu-driver", rc);
+                  g10_exit (1);
+                }
 
               release_kbnode (kb);
            }
@@ -4868,10 +5038,14 @@ main (int argc, char **argv)
 #endif /*USE_TOFU*/
        break;
 
-      case aListPackets:
       default:
+        if (!opt.quiet)
+          log_info (_("WARNING: no command supplied."
+                      "  Trying to guess what you mean ...\n"));
+        /*FALLTHRU*/
+      case aListPackets:
        if( argc > 1 )
-           wrong_args(_("[filename]"));
+           wrong_args("[filename]");
        /* Issue some output for the unix newbie */
        if (!fname && !opt.outfile
             && gnupg_isatty (fileno (stdin))
@@ -4934,6 +5108,12 @@ emergency_cleanup (void)
 void
 g10_exit( int rc )
 {
+  /* If we had an error but not printed an error message, do it now.
+   * Note that write_status_failure will never print a second failure
+   * status line. */
+  if (rc)
+    write_status_failure ("gpg-exit", gpg_error (GPG_ERR_GENERAL));
+
   gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
   if (DBG_CLOCK)
     log_clock ("stop");
@@ -4941,6 +5121,7 @@ g10_exit( int rc )
   if ( (opt.debug & DBG_MEMSTAT_VALUE) )
     {
       keydb_dump_stats ();
+      sig_check_dump_stats ();
       gcry_control (GCRYCTL_DUMP_MEMORY_STATS);
       gcry_control (GCRYCTL_DUMP_RANDOM_STATS);
     }
@@ -5269,6 +5450,9 @@ read_sessionkey_from_fd (int fd)
   int i, len;
   char *line;
 
+  if (! gnupg_fd_valid (fd))
+    log_fatal ("override-session-key-fd is invalid: %s\n", strerror (errno));
+
   for (line = NULL, i = len = 100; ; i++ )
     {
       if (i >= len-1 )