sm: Do not expect X.509 keyids to be unique
[gnupg.git] / sm / gpgsm.c
index 8a8c017..0feda90 100644 (file)
@@ -1,6 +1,6 @@
-/* gpgsm.c - GnuPG for S/MIME 
- * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- *               2010  Free Software Foundation, Inc.
+/* gpgsm.c - GnuPG for S/MIME
+ * Copyright (C) 2001-2008, 2010  Free Software Foundation, Inc.
+ * Copyright (C) 2001-2008, 2010  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -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 <gcrypt.h>
 #include <assuan.h> /* malloc hooks */
 
+#include "passphrase.h"
+#include "../common/shareddefs.h"
 #include "../kbx/keybox.h" /* malloc hooks */
-#include "i18n.h"
+#include "../common/i18n.h"
 #include "keydb.h"
-#include "sysutils.h"
-#include "gc-opt-flags.h"
+#include "../common/sysutils.h"
+#include "../common/gc-opt-flags.h"
+#include "../common/asshelp.h"
+#include "../common/init.h"
+#include "../common/compliance.h"
 
 
 #ifndef O_BINARY
@@ -72,7 +77,9 @@ enum cmd_and_opt_values {
   aRecvKeys,
   aExport,
   aExportSecretKeyP12,
-  aServer,                        
+  aExportSecretKeyP8,
+  aExportSecretKeyRaw,
+  aServer,
   aLearnCard,
   aCallDirmngr,
   aCallProtectTool,
@@ -95,7 +102,6 @@ enum cmd_and_opt_values {
   oDebugAllowCoreDump,
   oDebugNoChainValidation,
   oDebugIgnoreExpiration,
-  oFixedPassphrase,
   oLogFile,
   oNoLogFile,
   oAuditLog,
@@ -117,6 +123,8 @@ enum cmd_and_opt_values {
   oProtectToolProgram,
   oFakedSystemTime,
 
+  oPassphraseFD,
+  oPinentryMode,
 
   oAssumeArmor,
   oAssumeBase64,
@@ -126,6 +134,8 @@ enum cmd_and_opt_values {
   oNoArmor,
   oP12Charset,
 
+  oCompliance,
+
   oDisableCRLChecks,
   oEnableCRLChecks,
   oDisableTrustedCertCRLCheck,
@@ -140,9 +150,11 @@ enum cmd_and_opt_values {
   oDisablePolicyChecks,
   oEnablePolicyChecks,
   oAutoIssuerKeyRetrieve,
-  
+
   oWithFingerprint,
   oWithMD5Fingerprint,
+  oWithKeygrip,
+  oWithSecret,
   oAnswerYes,
   oAnswerNo,
   oKeyring,
@@ -177,7 +189,8 @@ enum cmd_and_opt_values {
   oIgnoreTimeConflict,
   oNoRandomSeedFile,
   oNoCommonCertsImport,
-  oIgnoreCertExtension
+  oIgnoreCertExtension,
+  oNoAutostart
  };
 
 
@@ -186,33 +199,41 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_group (300, N_("@Commands:\n ")),
 
   ARGPARSE_c (aSign, "sign", N_("make a signature")),
-  ARGPARSE_c (aClearsign, "clearsign", N_("make a clear text signature") ),
+/*ARGPARSE_c (aClearsign, "clearsign", N_("make a clear text signature") ),*/
   ARGPARSE_c (aDetachedSign, "detach-sign", N_("make a detached signature")),
   ARGPARSE_c (aEncr, "encrypt", N_("encrypt data")),
-  ARGPARSE_c (aSym, "symmetric", N_("encryption only with symmetric cipher")),
+/*ARGPARSE_c (aSym, "symmetric", N_("encryption only with symmetric cipher")),*/
   ARGPARSE_c (aDecrypt, "decrypt", N_("decrypt data (default)")),
   ARGPARSE_c (aVerify, "verify",  N_("verify a signature")),
   ARGPARSE_c (aListKeys, "list-keys", N_("list keys")),
-  ARGPARSE_c (aListExternalKeys, "list-external-keys", 
+  ARGPARSE_c (aListExternalKeys, "list-external-keys",
               N_("list external keys")),
   ARGPARSE_c (aListSecretKeys, "list-secret-keys", N_("list secret keys")),
-  ARGPARSE_c (aListChain,   "list-chain",  N_("list certificate chain")), 
+  ARGPARSE_c (aListChain,   "list-chain",  N_("list certificate chain")),
   ARGPARSE_c (aFingerprint, "fingerprint", N_("list keys and fingerprints")),
-  ARGPARSE_c (aKeygen, "gen-key", N_("generate a new key pair")),
-  ARGPARSE_c (aDeleteKey, "delete-keys", 
+  ARGPARSE_c (aKeygen, "generate-key", N_("generate a new key pair")),
+  ARGPARSE_c (aKeygen, "gen-key", "@"),
+  ARGPARSE_c (aDeleteKey, "delete-keys",
               N_("remove keys from the public keyring")),
-  ARGPARSE_c (aSendKeys, "send-keys", N_("export keys to a key server")),
-  ARGPARSE_c (aRecvKeys, "recv-keys", N_("import keys from a key server")),
+/*ARGPARSE_c (aSendKeys, "send-keys", N_("export keys to a keyserver")),*/
+/*ARGPARSE_c (aRecvKeys, "recv-keys", N_("import keys from a keyserver")),*/
   ARGPARSE_c (aImport, "import", N_("import certificates")),
   ARGPARSE_c (aExport, "export", N_("export certificates")),
-  ARGPARSE_c (aExportSecretKeyP12, "export-secret-key-p12", "@"), 
+
+  /* We use -raw and not -p1 for pkcs#1 secret key export so that it
+     won't accidentally be used in case -p12 was intended.  */
+  ARGPARSE_c (aExportSecretKeyP12, "export-secret-key-p12", "@"),
+  ARGPARSE_c (aExportSecretKeyP8,  "export-secret-key-p8", "@"),
+  ARGPARSE_c (aExportSecretKeyRaw, "export-secret-key-raw", "@"),
+
   ARGPARSE_c (aLearnCard, "learn-card", N_("register a smartcard")),
   ARGPARSE_c (aServer, "server", N_("run in server mode")),
-  ARGPARSE_c (aCallDirmngr, "call-dirmngr", 
+  ARGPARSE_c (aCallDirmngr, "call-dirmngr",
               N_("pass a command to the dirmngr")),
   ARGPARSE_c (aCallProtectTool, "call-protect-tool",
               N_("invoke gpg-protect-tool")),
-  ARGPARSE_c (aPasswd, "passwd", N_("change a passphrase")),
+  ARGPARSE_c (aPasswd, "change-passphrase", N_("change a passphrase")),
+  ARGPARSE_c (aPasswd, "passwd", "@"),
   ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
   ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
 
@@ -231,24 +252,26 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oP12Charset, "p12-charset", "@"),
 
-  ARGPARSE_s_n (oAssumeArmor, "assume-armor", 
+  ARGPARSE_s_i (oPassphraseFD,    "passphrase-fd", "@"),
+  ARGPARSE_s_s (oPinentryMode,    "pinentry-mode", "@"),
+
+  ARGPARSE_s_n (oAssumeArmor, "assume-armor",
                 N_("assume input is in PEM format")),
   ARGPARSE_s_n (oAssumeBase64, "assume-base64",
                 N_("assume input is in base-64 format")),
-  ARGPARSE_s_n (oAssumeBinary, "assume-binary", 
+  ARGPARSE_s_n (oAssumeBinary, "assume-binary",
                 N_("assume input is in binary format")),
 
   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
 
-  ARGPARSE_s_n (oPreferSystemDirmngr,"prefer-system-dirmngr",
-                N_("use system's dirmngr if available")),
+  ARGPARSE_s_n (oPreferSystemDirmngr,"prefer-system-dirmngr", "@"),
 
-  ARGPARSE_s_n (oDisableCRLChecks, "disable-crl-checks", 
+  ARGPARSE_s_n (oDisableCRLChecks, "disable-crl-checks",
                 N_("never consult a CRL")),
   ARGPARSE_s_n (oEnableCRLChecks, "enable-crl-checks", "@"),
   ARGPARSE_s_n (oDisableTrustedCertCRLCheck,
                 "disable-trusted-cert-crl-check", "@"),
-  ARGPARSE_s_n (oEnableTrustedCertCRLCheck, 
+  ARGPARSE_s_n (oEnableTrustedCertCRLCheck,
                 "enable-trusted-cert-crl-check", "@"),
 
   ARGPARSE_s_n (oForceCRLRefresh, "force-crl-refresh", "@"),
@@ -258,7 +281,7 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oValidationModel, "validation-model", "@"),
 
-  ARGPARSE_s_i (oIncludeCerts, "include-certs", 
+  ARGPARSE_s_i (oIncludeCerts, "include-certs",
                 N_("|N|number of certificates to include") ),
 
   ARGPARSE_s_s (oPolicyFile, "policy-file",
@@ -286,9 +309,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
   ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
 
-  ARGPARSE_s_s (oAuditLog, "audit-log", 
+  ARGPARSE_s_s (oAuditLog, "audit-log",
                 N_("|FILE|write an audit log to FILE")),
-  ARGPARSE_s_s (oHtmlAuditLog, "html-audit-log", ""),
+  ARGPARSE_s_s (oHtmlAuditLog, "html-audit-log", "@"),
   ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
   ARGPARSE_s_n (oBatch, "batch", N_("batch mode: never ask")),
   ARGPARSE_s_n (oAnswerYes, "yes", N_("assume yes on most questions")),
@@ -311,7 +334,7 @@ static ARGPARSE_OPTS opts[] = {
                 N_("|SPEC|use this keyserver to lookup keys")),
   ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
 
-  ARGPARSE_p_u (oDebug, "debug", "@"),
+  ARGPARSE_s_s (oDebug, "debug", "@"),
   ARGPARSE_s_s (oDebugLevel, "debug-level",
                 N_("|LEVEL|set the debugging level to LEVEL")),
   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
@@ -320,39 +343,33 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
   ARGPARSE_s_n (oDebugNoChainValidation, "debug-no-chain-validation", "@"),
   ARGPARSE_s_n (oDebugIgnoreExpiration,  "debug-ignore-expiration", "@"),
-  ARGPARSE_s_s (oFixedPassphrase, "fixed-passphrase", "@"),
 
   ARGPARSE_s_i (oStatusFD, "status-fd",
                 N_("|FD|write status info to this FD")),
 
-  ARGPARSE_s_s (oCipherAlgo, "cipher-algo", 
+  ARGPARSE_s_s (oCipherAlgo, "cipher-algo",
                 N_("|NAME|use cipher algorithm NAME")),
   ARGPARSE_s_s (oDigestAlgo, "digest-algo",
                 N_("|NAME|use message digest algorithm NAME")),
   ARGPARSE_s_s (oExtraDigestAlgo, "extra-digest-algo", "@"),
-    
+
 
   ARGPARSE_group (302, N_(
   "@\n(See the man page for a complete listing of all commands and options)\n"
   )),
 
-  ARGPARSE_group (303, N_("@\nExamples:\n\n"
-    " -se -r Bob [file]          sign and encrypt for user Bob\n"
-    " --clearsign [file]         make a clear text signature\n"
-    " --detach-sign [file]       make a detached signature\n"
-    " --list-keys [names]        show keys\n"
-    " --fingerprint [names]      show fingerprints\n"  )),
 
   /* Hidden options. */
+  ARGPARSE_s_s (oCompliance, "compliance",   "@"),
   ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
   ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"),
-  ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"), 
+  ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"),
   ARGPARSE_s_n (oNoArmor, "no-armor", "@"),
   ARGPARSE_s_n (oNoArmor, "no-armour", "@"),
   ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"),
   ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
   ARGPARSE_s_n (oNoOptions, "no-options", "@"),
-  ARGPARSE_s_s (oHomedir, "homedir", "@"),   
+  ARGPARSE_s_s (oHomedir, "homedir", "@"),
   ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
   ARGPARSE_s_s (oDisplay,    "display", "@"),
   ARGPARSE_s_s (oTTYname,    "ttyname", "@"),
@@ -372,25 +389,41 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oWithEphemeralKeys,  "with-ephemeral-keys", "@"),
   ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"),
   ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
+  ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
+  ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
   ARGPARSE_s_s (oDisableCipherAlgo,  "disable-cipher-algo", "@"),
   ARGPARSE_s_s (oDisablePubkeyAlgo,  "disable-pubkey-algo", "@"),
   ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
   ARGPARSE_s_n (oNoRandomSeedFile,  "no-random-seed-file", "@"),
   ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"),
   ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"),
+  ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
 
   /* Command aliases.  */
-  ARGPARSE_c (aListKeys, "list-key", "@"),  
-  ARGPARSE_c (aListChain, "list-sig", "@"), 
-  ARGPARSE_c (aListChain, "list-sigs", "@"), 
-  ARGPARSE_c (aListChain, "check-sig", "@"), 
-  ARGPARSE_c (aListChain, "check-sigs", "@"), 
+  ARGPARSE_c (aListKeys, "list-key", "@"),
+  ARGPARSE_c (aListChain, "list-signatures", "@"),
+  ARGPARSE_c (aListChain, "list-sigs", "@"),
+  ARGPARSE_c (aListChain, "check-signatures", "@"),
+  ARGPARSE_c (aListChain, "check-sigs", "@"),
   ARGPARSE_c (aDeleteKey, "delete-key", "@"),
 
   ARGPARSE_end ()
 };
 
 
+/* The list of supported debug flags.  */
+static struct debug_flags_s debug_flags [] =
+  {
+    { DBG_X509_VALUE   , "x509"    },
+    { DBG_MPI_VALUE    , "mpi"     },
+    { DBG_CRYPTO_VALUE , "crypto"  },
+    { DBG_MEMORY_VALUE , "memory"  },
+    { DBG_CACHE_VALUE  , "cache"   },
+    { DBG_MEMSTAT_VALUE, "memstat" },
+    { DBG_HASHING_VALUE, "hashing" },
+    { DBG_IPC_VALUE    , "ipc"     },
+    { 0, NULL }
+  };
 
 
 /* Global variable to keep an error count. */
@@ -403,12 +436,9 @@ static int maybe_setuid = 1;
 static const char *debug_level;
 static unsigned int debug_value;
 
-/* Option --enable-special-filenames */
-static int allow_special_filenames;
-
 /* Default value for include-certs.  We need an extra macro for
    gpgconf-list because the variable will be changed by the command
-   line option.  
+   line option.
 
    It is often cumbersome to locate intermediate certificates, thus by
    default we include all certificates in the chain.  However we leave
@@ -417,13 +447,13 @@ static int allow_special_filenames;
    should be installed only after due checks and thus it won't help to
    send it along with each message.  */
 #define DEFAULT_INCLUDE_CERTS -2 /* Include all certs but root. */
-static int default_include_certs = DEFAULT_INCLUDE_CERTS; 
+static int default_include_certs = DEFAULT_INCLUDE_CERTS;
 
 /* Whether the chain mode shall be used for validation.  */
 static int default_validation_model;
 
 /* The default cipher algo.  */
-#define DEFAULT_CIPHER_ALGO "3DES"  /*des-EDE3-CBC*/
+#define DEFAULT_CIPHER_ALGO "AES"
 
 
 static char *build_list (const char *text,
@@ -432,10 +462,8 @@ static void set_cmd (enum cmd_and_opt_values *ret_cmd,
                      enum cmd_and_opt_values new_cmd );
 
 static void emergency_cleanup (void);
-static int check_special_filename (const char *fname, int for_write);
 static int open_read (const char *filename);
-static estream_t open_es_fread (const char *filename);
-static FILE *open_fwrite (const char *filename);
+static estream_t open_es_fread (const char *filename, const char *mode);
 static estream_t open_es_fwrite (const char *filename);
 static void run_protect_tool (int argc, char **argv);
 
@@ -500,7 +528,7 @@ make_libversion (const char *libname, const char *(*getfnc)(const char*))
 {
   const char *s;
   char *result;
-  
+
   if (maybe_setuid)
     {
       gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* Drop setuid. */
@@ -522,19 +550,19 @@ my_strusage( int level )
 
   switch (level)
     {
-    case 11: p = "gpgsm (GnuPG)";
+    case 11: p = "@GPGSM@ (@GNUPG@)";
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
 
     case 1:
-    case 40: p = _("Usage: gpgsm [options] [files] (-h for help)");
+    case 40: p = _("Usage: @GPGSM@ [options] [files] (-h for help)");
       break;
     case 41:
-      p = _("Syntax: gpgsm [options] [files]\n"
-            "sign, check, encrypt or decrypt using the S/MIME protocol\n"
-            "default operation depends on the input data\n");
+      p = _("Syntax: @GPGSM@ [options] [files]\n"
+            "Sign, check, encrypt or decrypt using the S/MIME protocol\n"
+            "Default operation depends on the input data\n");
       break;
 
     case 20:
@@ -549,11 +577,11 @@ my_strusage( int level )
       break;
 
     case 31: p = "\nHome: "; break;
-    case 32: p = opt.homedir; break;
+    case 32: p = gnupg_homedir (); break;
     case 33: p = _("\nSupported algorithms:\n"); break;
     case 34:
       if (!ciphers)
-        ciphers = build_list ("Cipher: ", gcry_cipher_algo_name,
+        ciphers = build_list ("Cipher: ", gnupg_cipher_algo_name,
                               our_cipher_test_algo );
       p = ciphers;
       break;
@@ -568,7 +596,7 @@ my_strusage( int level )
         digests = build_list("Hash: ", gcry_md_algo_name, our_md_test_algo );
       p = digests;
       break;
-     
+
     default: p = NULL; break;
     }
   return p;
@@ -581,7 +609,7 @@ build_list (const char *text, const char * (*mapf)(int), int (*chkf)(int))
   int i;
   size_t n=strlen(text)+2;
   char *list, *p;
-  
+
   if (maybe_setuid) {
     gcry_control (GCRYCTL_DROP_PRIVS); /* drop setuid */
   }
@@ -603,7 +631,7 @@ build_list (const char *text, const char * (*mapf)(int), int (*chkf)(int))
        }
     }
   if (p)
-    p = stpcpy(p, "\n" );
+    strcpy (p, "\n" );
   return list;
 }
 
@@ -624,9 +652,7 @@ set_binary (FILE *fp)
 static void
 wrong_args (const char *text)
 {
-  fputs (_("usage: gpgsm [options] "), stderr);
-  fputs (text, stderr);
-  putc ('\n', stderr);
+  fprintf (stderr, _("usage: %s [options] %s\n"), GPGSM_NAME, text);
   gpgsm_exit (2);
 }
 
@@ -635,7 +661,7 @@ static void
 set_opt_session_env (const char *name, const char *value)
 {
   gpg_error_t err;
-  
+
   err = session_env_setenv (opt.session_env, name, value);
   if (err)
     log_fatal ("error setting session environment: %s\n",
@@ -658,11 +684,11 @@ set_debug (void)
   else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
     opt.debug = 0;
   else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
-    opt.debug = DBG_ASSUAN_VALUE;
+    opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
-    opt.debug = DBG_ASSUAN_VALUE|DBG_X509_VALUE;
+    opt.debug = DBG_IPC_VALUE|DBG_X509_VALUE;
   else if (!strcmp (debug_level, "expert")  || (numok && numlvl <= 8))
-    opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE
+    opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE
                  |DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
   else if (!strcmp (debug_level, "guru") || numok)
     {
@@ -670,13 +696,13 @@ set_debug (void)
       /* Unless the "guru" string has been used we don't want to allow
          hashing debugging.  The rationale is that people tend to
          select the highest debug value and would then clutter their
-         disk with debug files which may reveal confidential data.  */ 
+         disk with debug files which may reveal confidential data.  */
       if (numok)
         opt.debug &= ~(DBG_HASHING_VALUE);
     }
   else
     {
-      log_error (_("invalid debug-level `%s' given\n"), debug_level);
+      log_error (_("invalid debug-level '%s' given\n"), debug_level);
       gpgsm_exit (2);
     }
 
@@ -694,17 +720,9 @@ set_debug (void)
   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
 
   if (opt.debug)
-    log_info ("enabled debug flags:%s%s%s%s%s%s%s%s\n",
-              (opt.debug & DBG_X509_VALUE   )? " x509":"",    
-              (opt.debug & DBG_MPI_VALUE    )? " mpi":"",    
-              (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"", 
-              (opt.debug & DBG_MEMORY_VALUE )? " memory":"", 
-              (opt.debug & DBG_CACHE_VALUE  )? " cache":"", 
-              (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"", 
-              (opt.debug & DBG_HASHING_VALUE)? " hashing":"", 
-              (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"" );
+    parse_debug_flag (NULL, &opt.debug, debug_flags);
 }
+
 
 
 static void
@@ -721,7 +739,7 @@ set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
   else if ( (cmd == aSign && new_cmd == aClearsign)
             || (cmd == aClearsign && new_cmd == aSign) )
     cmd = aClearsign;
-  else 
+  else
     {
       log_error(_("conflicting commands\n"));
       gpgsm_exit(2);
@@ -741,12 +759,12 @@ do_add_recipient (ctrl_t ctrl, const char *name,
     {
       if (recp_required)
         {
-          log_error ("can't encrypt to `%s': %s\n", name, gpg_strerror (rc));
+          log_error ("can't encrypt to '%s': %s\n", name, gpg_strerror (rc));
           gpgsm_status2 (ctrl, STATUS_INV_RECP,
                          get_inv_recpsgnr_code (rc), name, NULL);
         }
       else
-        log_info (_("NOTE: won't be able to encrypt to `%s': %s\n"),
+        log_info (_("Note: won't be able to encrypt to '%s': %s\n"),
                   name, gpg_strerror (rc));
     }
 }
@@ -757,7 +775,7 @@ parse_validation_model (const char *model)
 {
   int i = gpgsm_parse_validation_model (model);
   if (i == -1)
-    log_error (_("unknown validation model `%s'\n"), model);
+    log_error (_("unknown validation model '%s'\n"), model);
   else
     default_validation_model = i;
 }
@@ -813,43 +831,44 @@ parse_keyserver_line (char *line,
              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"), 
+             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);
+      server = NULL;
     }
 
   return server;
@@ -862,7 +881,6 @@ main ( int argc, char **argv)
   ARGPARSE_ARGS pargs;
   int orig_argc;
   char **orig_argv;
-  const char *fname;
   /*  char *username;*/
   int may_coredump;
   strlist_t sl, remusr= NULL, locusr=NULL;
@@ -895,10 +913,11 @@ main ( int argc, char **argv)
   estream_t auditfp = NULL;
   estream_t htmlauditfp = NULL;
   struct assuan_malloc_hooks malloc_hooks;
-
+  int pwfd = -1;
   /*mtrace();*/
 
-  gnupg_reopen_std ("gpgsm");
+  early_system_init ();
+  gnupg_reopen_std (GPGSM_NAME);
   /* trap_unaligned ();*/
   gnupg_rl_initialize ();
   set_strusage (my_strusage);
@@ -907,17 +926,14 @@ main ( int argc, char **argv)
   /* Please note that we may running SUID(ROOT), so be very CAREFUL
      when adding any stuff between here and the call to secmem_init()
      somewhere after the option parsing */
-  log_set_prefix ("gpgsm", 1);
+  log_set_prefix (GPGSM_NAME, GPGRT_LOG_WITH_PREFIX);
 
   /* Make sure that our subsystems are ready.  */
-  i18n_init();
-  init_common_subsystems ();
+  i18n_init ();
+  init_common_subsystems (&argc, &argv);
 
   /* Check that the libraries are suitable.  Do it here because the
      option parse may need services of the library */
-  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
-    log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt", 
-               NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
   if (!ksba_check_version (NEED_KSBA_VERSION) )
     log_fatal (_("%s is too old (need %s, have %s)\n"), "libksba",
                NEED_KSBA_VERSION, ksba_check_version (NULL) );
@@ -926,11 +942,15 @@ main ( int argc, char **argv)
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
 
   may_coredump = disable_core_dumps ();
-  
+
   gnupg_init_signals (0, emergency_cleanup);
-  
-  create_dotlock (NULL); /* register locking cleanup */
 
+  dotlock_create (NULL, 0); /* Register lockfile cleanup.  */
+
+  /* Tell the compliance module who we are.  */
+  gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPGSM);
+
+  opt.autostart = 1;
   opt.session_env = session_env_new ();
   if (!opt.session_env)
     log_fatal ("error allocating session environment block: %s\n",
@@ -938,9 +958,8 @@ main ( int argc, char **argv)
 
   /* Note: If you change this default cipher algorithm , please
      remember to update the Gpgconflist entry as well.  */
-  opt.def_cipher_algoid = DEFAULT_CIPHER_ALGO; 
+  opt.def_cipher_algoid = DEFAULT_CIPHER_ALGO;
 
-  opt.homedir = default_homedir ();
 
   /* First check whether we have a config file on the commandline */
   orig_argc = argc;
@@ -959,21 +978,24 @@ main ( int argc, char **argv)
           default_config = 0;
        }
       else if (pargs.r_opt == oNoOptions)
-        default_config = 0; /* --no-options */
+        {
+          default_config = 0; /* --no-options */
+          opt.no_homedir_creation = 1;
+        }
       else if (pargs.r_opt == oHomedir)
-        opt.homedir = pargs.r.ret_str;
+        gnupg_set_homedir (pargs.r.ret_str);
       else if (pargs.r_opt == aCallProtectTool)
         break; /* This break makes sure that --version and --help are
                   passed to the protect-tool. */
     }
-  
-  
+
+
   /* Initialize the secure memory. */
   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
   maybe_setuid = 0;
 
-  /* 
-     Now we are now working under our real uid 
+  /*
+     Now we are now working under our real uid
   */
 
   ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
@@ -982,8 +1004,8 @@ main ( int argc, char **argv)
   malloc_hooks.realloc = gcry_realloc;
   malloc_hooks.free = gcry_free;
   assuan_set_malloc_hooks (&malloc_hooks);
-  assuan_set_assuan_log_prefix (log_get_prefix (NULL));
   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+  setup_libassuan_logging (&opt.debug, NULL);
 
   keybox_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
 
@@ -996,10 +1018,11 @@ main ( int argc, char **argv)
 
   /* Set the default option file */
   if (default_config )
-    configname = make_filename (opt.homedir, "gpgsm.conf", NULL);
+    configname = make_filename (gnupg_homedir (),
+                                GPGSM_NAME EXTSEP_S "conf", NULL);
   /* Set the default policy file */
-  opt.policy_file = make_filename (opt.homedir, "policies.txt", NULL);
-  
+  opt.policy_file = make_filename (gnupg_homedir (), "policies.txt", NULL);
+
   argc        = orig_argc;
   argv        = orig_argv;
   pargs.argc  = &argc;
@@ -1015,34 +1038,34 @@ main ( int argc, char **argv)
         if (default_config)
           {
             if (parse_debug)
-              log_info (_("NOTE: no default option file `%s'\n"), configname);
+              log_info (_("Note: no default option file '%s'\n"), configname);
           }
-        else 
+        else
           {
-            log_error (_("option file `%s': %s\n"), configname, strerror(errno));
+            log_error (_("option file '%s': %s\n"), configname, strerror(errno));
             gpgsm_exit(2);
           }
         xfree(configname);
         configname = NULL;
       }
     if (parse_debug && configname)
-      log_info (_("reading options from `%s'\n"), configname);
+      log_info (_("reading options from '%s'\n"), configname);
     default_config = 0;
   }
 
-  while (!no_more_options 
+  while (!no_more_options
          && optfile_parse (configfp, configname, &configlineno, &pargs, opts))
     {
       switch (pargs.r_opt)
         {
-       case aGPGConfList: 
-       case aGPGConfTest: 
+       case aGPGConfList:
+       case aGPGConfTest:
           set_cmd (&cmd, pargs.r_opt);
           do_not_setup_keys = 1;
           nogreeting = 1;
           break;
 
-        case aServer: 
+        case aServer:
           opt.batch = 1;
           set_cmd (&cmd, aServer);
           break;
@@ -1059,7 +1082,7 @@ main ( int argc, char **argv)
           no_more_options = 1; /* Stop parsing. */
           do_not_setup_keys = 1;
           break;
-        
+
         case aDeleteKey:
           set_cmd (&cmd, aDeleteKey);
           /*greeting=1;*/
@@ -1068,45 +1091,47 @@ main ( int argc, char **argv)
 
         case aDetachedSign:
           detached_sig = 1;
-          set_cmd (&cmd, aSign ); 
+          set_cmd (&cmd, aSign );
           break;
 
         case aKeygen:
           set_cmd (&cmd, aKeygen);
-          greeting=1; 
+          greeting=1;
           do_not_setup_keys = 1;
           break;
 
-        case aImport: 
-        case aSendKeys: 
-        case aRecvKeys: 
-        case aExport: 
-        case aExportSecretKeyP12: 
+        case aImport:
+        case aSendKeys:
+        case aRecvKeys:
+        case aExport:
+        case aExportSecretKeyP12:
+        case aExportSecretKeyP8:
+        case aExportSecretKeyRaw:
         case aDumpKeys:
         case aDumpChain:
-        case aDumpExternalKeys: 
-        case aDumpSecretKeys: 
+        case aDumpExternalKeys:
+        case aDumpSecretKeys:
         case aListKeys:
-        case aListExternalKeys: 
-        case aListSecretKeys: 
-        case aListChain: 
-        case aLearnCard: 
-        case aPasswd: 
+        case aListExternalKeys:
+        case aListSecretKeys:
+        case aListChain:
+        case aLearnCard:
+        case aPasswd:
         case aKeydbClearSomeCertFlags:
           do_not_setup_keys = 1;
           set_cmd (&cmd, pargs.r_opt);
           break;
 
-        case aEncr: 
+        case aEncr:
           recp_required = 1;
           set_cmd (&cmd, pargs.r_opt);
           break;
 
         case aSym:
-        case aDecrypt: 
-        case aSign: 
-        case aClearsign: 
-        case aVerify: 
+        case aDecrypt:
+        case aSign:
+        case aClearsign:
+        case aVerify:
           set_cmd (&cmd, pargs.r_opt);
           break;
 
@@ -1114,19 +1139,29 @@ main ( int argc, char **argv)
         case oArmor:
           ctrl.create_pem = 1;
           break;
-        case oBase64: 
+        case oBase64:
           ctrl.create_pem = 0;
           ctrl.create_base64 = 1;
           break;
-        case oNoArmor: 
+        case oNoArmor:
           ctrl.create_pem = 0;
           ctrl.create_base64 = 0;
           break;
-          
+
         case oP12Charset:
           opt.p12_charset = pargs.r.ret_str;
           break;
 
+        case oPassphraseFD:
+         pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
+         break;
+
+        case oPinentryMode:
+         opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str);
+         if (opt.pinentry_mode == -1)
+            log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
+         break;
+
           /* Input encoding selection.  */
         case oAssumeArmor:
           ctrl.autodetect_encoding = 0;
@@ -1167,8 +1202,8 @@ main ( int argc, char **argv)
           ctrl.use_ocsp = opt.enable_ocsp = 1;
           break;
 
-        case oIncludeCerts: 
-          ctrl.include_certs = default_include_certs = pargs.r.ret_int; 
+        case oIncludeCerts:
+          ctrl.include_certs = default_include_certs = pargs.r.ret_int;
           break;
 
         case oPolicyFile:
@@ -1185,14 +1220,14 @@ main ( int argc, char **argv)
         case oEnablePolicyChecks:
           opt.no_policy_check = 0;
           break;
-          
+
         case oAutoIssuerKeyRetrieve:
           opt.auto_issuer_key_retrieve = 1;
           break;
 
         case oOutput: opt.outfile = pargs.r.ret_str; break;
 
-        
+
         case oQuiet: opt.quiet = 1; break;
         case oNoTTY: /* fixme:tty_no_terminal(1);*/ break;
         case oDryRun: opt.dry_run = 1; break;
@@ -1207,23 +1242,29 @@ main ( int argc, char **argv)
           break;
 
         case oLogFile: logfile = pargs.r.ret_str; break;
-        case oNoLogFile: logfile = NULL; break;          
+        case oNoLogFile: logfile = NULL; break;
 
         case oAuditLog: auditlog = pargs.r.ret_str; break;
         case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break;
 
-        case oBatch: 
+        case oBatch:
           opt.batch = 1;
           greeting = 0;
           break;
         case oNoBatch: opt.batch = 0; break;
-          
+
         case oAnswerYes: opt.answer_yes = 1; break;
         case oAnswerNo: opt.answer_no = 1; break;
 
         case oKeyring: append_to_strlist (&nrings, pargs.r.ret_str); break;
 
-        case oDebug: debug_value |= pargs.r.ret_ulong; break;
+        case oDebug:
+          if (parse_debug_flag (pargs.r.ret_str, &debug_value, debug_flags))
+            {
+              pargs.r_opt = ARGPARSE_INVALID_ARG;
+              pargs.err = ARGPARSE_PRINT_ERROR;
+            }
+          break;
         case oDebugAll: debug_value = ~0; break;
         case oDebugNone: debug_value = 0; break;
         case oDebugLevel: debug_level = pargs.r.ret_str; break;
@@ -1233,18 +1274,21 @@ main ( int argc, char **argv)
           break;
         case oDebugNoChainValidation: opt.no_chain_validation = 1; break;
         case oDebugIgnoreExpiration: opt.ignore_expiration = 1; break;
-        case oFixedPassphrase: opt.fixed_passphrase = pargs.r.ret_str; break;
 
         case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
         case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
         case oWithMD5Fingerprint:
-          opt.with_md5_fingerprint=1; /*fall thru*/
+          opt.with_md5_fingerprint=1; /*fall through*/
         case oWithFingerprint:
-          with_fpr=1; /*fall thru*/
+          with_fpr=1; /*fall through*/
         case aFingerprint:
           opt.fingerprint++;
           break;
 
+        case oWithKeygrip:
+          opt.with_keygrip = 1;
+          break;
+
         case oOptions:
           /* config files may not be nested (silently ignore them) */
           if (!configfp)
@@ -1254,8 +1298,8 @@ main ( int argc, char **argv)
               goto next_pass;
            }
           break;
-        case oNoOptions: break; /* no-options */
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
 
         case oDisplay:
@@ -1276,14 +1320,14 @@ main ( int argc, char **argv)
 
         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 oPreferSystemDirmngr: /* Obsolete */; break;
         case oProtectToolProgram:
-          opt.protect_tool_program = pargs.r.ret_str; 
+          opt.protect_tool_program = pargs.r.ret_str;
           break;
-          
+
         case oFakedSystemTime:
           {
-            time_t faked_time = isotime2epoch (pargs.r.ret_str); 
+            time_t 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);
@@ -1315,8 +1359,9 @@ main ( int argc, char **argv)
           opt.def_recipient_self = 0;
           break;
 
-        case oWithKeyData: opt.with_key_data=1; /* fall thru */
+        case oWithKeyData: opt.with_key_data=1; /* fall through */
         case oWithColons: ctrl.with_colons = 1; break;
+        case oWithSecret: ctrl.with_secret = 1; break;
         case oWithValidation: ctrl.with_validation=1; break;
         case oWithEphemeralKeys: ctrl.with_ephemeral_keys=1; break;
 
@@ -1339,20 +1384,20 @@ main ( int argc, char **argv)
           break;
 
         case oNoSecmemWarn:
-          gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); 
+          gcry_control (GCRYCTL_DISABLE_SECMEM_WARN);
           break;
 
         case oCipherAlgo:
           opt.def_cipher_algoid = pargs.r.ret_str;
           break;
 
-        case oDisableCipherAlgo: 
+        case oDisableCipherAlgo:
           {
             int algo = gcry_cipher_map_name (pargs.r.ret_str);
             gcry_cipher_ctl (NULL, GCRYCTL_DISABLE_ALGO, &algo, sizeof algo);
           }
           break;
-        case oDisablePubkeyAlgo: 
+        case oDisablePubkeyAlgo:
           {
             int algo = gcry_pk_map_name (pargs.r.ret_str);
             gcry_pk_ctl (GCRYCTL_DISABLE_ALGO,&algo, sizeof algo );
@@ -1363,7 +1408,7 @@ main ( int argc, char **argv)
           forced_digest_algo = pargs.r.ret_str;
           break;
 
-        case oExtraDigestAlgo: 
+        case oExtraDigestAlgo:
           extra_digest_algo = pargs.r.ret_str;
           break;
 
@@ -1371,7 +1416,9 @@ main ( int argc, char **argv)
         case oNoRandomSeedFile: use_random_seed = 0; break;
         case oNoCommonCertsImport: no_common_certs_import = 1; break;
 
-        case oEnableSpecialFilenames: allow_special_filenames =1; break;
+        case oEnableSpecialFilenames:
+          enable_special_filenames ();
+          break;
 
         case oValidationModel: parse_validation_model (pargs.r.ret_str); break;
 
@@ -1397,8 +1444,26 @@ main ( int argc, char **argv)
           add_to_strlist (&opt.ignored_cert_extensions, pargs.r.ret_str);
           break;
 
-        default: 
-          pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR; 
+        case oNoAutostart: opt.autostart = 0; break;
+
+        case oCompliance:
+          {
+            struct gnupg_compliance_option compliance_options[] =
+              {
+                { "de-vs", CO_DE_VS }
+              };
+            int compliance = gnupg_parse_compliance_option (pargs.r.ret_str,
+                                                            compliance_options,
+                                                            DIM (compliance_options),
+                                                            opt.quiet);
+            if (compliance < 0)
+              gpgsm_exit (1);
+            opt.compliance = compliance;
+          }
+          break;
+
+        default:
+          pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
           break;
        }
     }
@@ -1416,23 +1481,28 @@ main ( int argc, char **argv)
   configname = NULL;
 
   if (!opt.config_filename)
-    opt.config_filename = make_filename (opt.homedir, "gpgsm.conf", NULL);
+    opt.config_filename = make_filename (gnupg_homedir (),
+                                         GPGSM_NAME EXTSEP_S "conf",
+                                         NULL);
 
   if (log_get_errorcount(0))
     gpgsm_exit(2);
 
+  if (pwfd != -1)      /* Read the passphrase now.  */
+    read_passphrase_from_fd (pwfd);
+
   /* Now that we have the options parsed we need to update the default
      control structure.  */
   gpgsm_init_default_ctrl (&ctrl);
 
   if (nogreeting)
     greeting = 0;
-  
+
   if (greeting)
     {
-      fprintf(stderr, "%s %s; %s\n",
-              strusage(11), strusage(13), strusage(14) );
-      fprintf(stderr, "%s\n", strusage(15) );
+      es_fprintf (es_stderr, "%s %s; %s\n",
+                  strusage(11), strusage(13), strusage(14) );
+      es_fprintf (es_stderr, "%s\n", strusage(15) );
     }
 #  ifdef IS_DEVELOPMENT_VERSION
   if (!opt.batch)
@@ -1447,14 +1517,14 @@ main ( int argc, char **argv)
     log_info (_("WARNING: program may create a core file!\n"));
 
 /*   if (opt.qualsig_approval && !opt.quiet) */
-/*     log_info (_("This software has offically been approved to " */
+/*     log_info (_("This software has officially been approved to " */
 /*                 "create and verify\n" */
 /*                 "qualified signatures according to German law.\n")); */
 
   if (logfile && cmd == aServer)
     {
       log_set_file (logfile);
-      log_set_prefix (NULL, 1|2|4);
+      log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
     }
 
   if (gnupg_faked_time_p ())
@@ -1466,7 +1536,17 @@ main ( int argc, char **argv)
       dump_isotime (tbuf);
       log_printf ("\n");
     }
-  
+
+  /* Print a warning if an argument looks like an option.  */
+  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
+    {
+      int i;
+
+      for (i=0; i < argc; i++)
+        if (argv[i][0] == '-' && argv[i][1] == '-')
+          log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
+    }
+
 /*FIXME    if (opt.batch) */
 /*      tty_batchmode (1); */
 
@@ -1474,7 +1554,7 @@ main ( int argc, char **argv)
 
   set_debug ();
 
-  /* Although we alwasy use gpgsm_exit, we better install a regualr
+  /* Although we always use gpgsm_exit, we better install a regualr
      exit handler so that at least the secure memory gets wiped
      out. */
   if (atexit (emergency_cleanup))
@@ -1493,6 +1573,8 @@ main ( int argc, char **argv)
   else if (!strcmp (opt.def_cipher_algoid, "AES")
            || !strcmp (opt.def_cipher_algoid, "AES128"))
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.2";
+  else if (!strcmp (opt.def_cipher_algoid, "AES192") )
+    opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.22";
   else if (!strcmp (opt.def_cipher_algoid, "AES256") )
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.42";
   else if (!strcmp (opt.def_cipher_algoid, "SERPENT")
@@ -1500,11 +1582,11 @@ main ( int argc, char **argv)
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.2";
   else if (!strcmp (opt.def_cipher_algoid, "SERPENT192") )
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.22";
-  else if (!strcmp (opt.def_cipher_algoid, "SERPENT192") )
+  else if (!strcmp (opt.def_cipher_algoid, "SERPENT256") )
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.42";
   else if (!strcmp (opt.def_cipher_algoid, "SEED") )
     opt.def_cipher_algoid = "1.2.410.200004.1.4";
-  else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA") 
+  else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA")
            || !strcmp (opt.def_cipher_algoid, "CAMELLIA128") )
     opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.2";
   else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA192") )
@@ -1532,36 +1614,74 @@ 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 (! gnupg_cipher_is_allowed (opt.compliance,
+                                 cmd == aEncr || cmd == aSignEncr,
+                                 gcry_cipher_map_name (opt.def_cipher_algoid),
+                                 GCRY_CIPHER_MODE_NONE)
+      && ! gnupg_cipher_is_allowed (opt.compliance,
+                                    cmd == aEncr || cmd == aSignEncr,
+                                    gcry_cipher_mode_from_oid
+                                    (opt.def_cipher_algoid),
+                                    GCRY_CIPHER_MODE_NONE))
+    log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
+               opt.def_cipher_algoid,
+               gnupg_compliance_option_string (opt.compliance));
+
+  if (forced_digest_algo
+      && ! gnupg_digest_is_allowed (opt.compliance,
+                                     cmd == aSign
+                                     || cmd == aSignEncr
+                                     || cmd == aClearsign,
+                                     opt.forced_digest_algo))
+    log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
+               forced_digest_algo,
+               gnupg_compliance_option_string (opt.compliance));
+
+  if (extra_digest_algo
+      && ! gnupg_digest_is_allowed (opt.compliance,
+                                     cmd == aSign
+                                     || cmd == aSignEncr
+                                     || cmd == aClearsign,
+                                     opt.extra_digest_algo))
+    log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
+               forced_digest_algo,
+               gnupg_compliance_option_string (opt.compliance));
+
   if (log_get_errorcount(0))
     gpgsm_exit(2);
-  
+
   /* Set the random seed file. */
-  if (use_random_seed) 
+  if (use_random_seed)
     {
-      char *p = make_filename (opt.homedir, "random_seed", NULL);
+      char *p = make_filename (gnupg_homedir (), "random_seed", NULL);
       gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
       xfree(p);
     }
-  
+
   if (!cmd && opt.fingerprint && !with_fpr)
     set_cmd (&cmd, aListKeys);
-  
+
   /* Add default keybox. */
   if (!nrings && default_keyring)
     {
       int created;
 
-      keydb_add_resource ("pubring.kbx", 0, 0, &created);
+      keydb_add_resource (&ctrl, "pubring.kbx", 0, &created);
       if (created && !no_common_certs_import)
         {
           /* Import the standard certificates for a new default keybox. */
           char *filelist[2];
-          
+
           filelist[0] = make_filename (gnupg_datadir (),"com-certs.pem", NULL);
           filelist[1] = NULL;
           if (!access (filelist[0], F_OK))
             {
-              log_info (_("importing common certificates `%s'\n"),
+              log_info (_("importing common certificates '%s'\n"),
                         filelist[0]);
               gpgsm_import_files (&ctrl, 1, filelist, open_read);
             }
@@ -1569,7 +1689,7 @@ main ( int argc, char **argv)
         }
     }
   for (sl = nrings; sl; sl = sl->next)
-    keydb_add_resource (sl->d, 0, 0, NULL);
+    keydb_add_resource (&ctrl, sl->d, 0, NULL);
   FREE_STRLIST(nrings);
 
 
@@ -1578,7 +1698,7 @@ main ( int argc, char **argv)
     {
       switch (cmd)
         {
-        case aEncr: 
+        case aEncr:
         case aSign:
         case aDecrypt:
         case aVerify:
@@ -1602,7 +1722,7 @@ main ( int argc, char **argv)
           int rc = gpgsm_add_to_certlist (&ctrl, sl->d, 1, &signerlist, 0);
           if (rc)
             {
-              log_error (_("can't sign using `%s': %s\n"),
+              log_error (_("can't sign using '%s': %s\n"),
                          sl->d, gpg_strerror (rc));
               gpgsm_status2 (&ctrl, STATUS_INV_SGNR,
                              get_inv_recpsgnr_code (rc), sl->d, NULL);
@@ -1610,10 +1730,10 @@ main ( int argc, char **argv)
                              get_inv_recpsgnr_code (rc), sl->d, NULL);
             }
         }
-      
+
       /* Build the recipient list.  We first add the regular ones and then
          the encrypt-to ones because the underlying function will silently
-         ignore duplicates and we can't allow to keep a duplicate which is
+         ignore duplicates and we can't allow keeping a duplicate which is
          flagged as encrypt-to as the actually encrypt function would then
          complain about no (regular) recipients. */
       for (sl = remusr; sl; sl = sl->next)
@@ -1629,46 +1749,43 @@ main ( int argc, char **argv)
 
   if (log_get_errorcount(0))
     gpgsm_exit(1); /* Must stop for invalid recipients. */
-  
-  fname = argc? *argv : NULL;
-  
+
   /* Dispatch command.  */
   switch (cmd)
     {
-    case aGPGConfList: 
+    case aGPGConfList:
       { /* List options and default values in the GPG Conf format.  */
        char *config_filename_esc = percent_escape (opt.config_filename, NULL);
 
-        printf ("gpgconf-gpgsm.conf:%lu:\"%s\n",
-                GC_OPT_FLAG_DEFAULT, config_filename_esc);
+        es_printf ("%s-%s.conf:%lu:\"%s\n",
+                   GPGCONF_NAME, GPGSM_NAME,
+                   GC_OPT_FLAG_DEFAULT, config_filename_esc);
         xfree (config_filename_esc);
 
-        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:%d:\n", GC_OPT_FLAG_DEFAULT,
-                DEFAULT_INCLUDE_CERTS);
-        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);
-#endif
-        printf ("cipher-algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
-                DEFAULT_CIPHER_ALGO);
-        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);
+        es_printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE);
+       es_printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE);
+       es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
+       es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("disable-crl-checks:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("enable-crl-checks:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("disable-trusted-cert-crl-check:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("enable-ocsp:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("include-certs:%lu:%d:\n", GC_OPT_FLAG_DEFAULT,
+                   DEFAULT_INCLUDE_CERTS);
+        es_printf ("disable-policy-checks:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("auto-issuer-key-retrieve:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("disable-dirmngr:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("cipher-algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
+                   DEFAULT_CIPHER_ALGO);
+        es_printf ("p12-charset:%lu:\n", GC_OPT_FLAG_DEFAULT);
+        es_printf ("default-key:%lu:\n", GC_OPT_FLAG_DEFAULT);
+        es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_DEFAULT);
+       es_printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE);
 
         /* The next one is an info only item and should match what
            proc_parameters actually implements.  */
-        printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
-                "RSA-2048");
+        es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
+                   "RSA-2048");
 
       }
       break;
@@ -1707,7 +1824,7 @@ main ( int argc, char **argv)
         set_binary (stdin);
 
         if (!argc) /* Source is stdin. */
-          gpgsm_encrypt (&ctrl, recplist, 0, fp); 
+          gpgsm_encrypt (&ctrl, recplist, 0, fp);
         else if (argc == 1)  /* Source is the given file. */
           gpgsm_encrypt (&ctrl, recplist, open_read (*argv), fp);
         else
@@ -1721,21 +1838,21 @@ main ( int argc, char **argv)
       {
         estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
-        /* Fixme: We should also allow to concatenate multiple files for
+        /* Fixme: We should also allow concatenation of multiple files for
            signing because that is what gpg does.*/
         set_binary (stdin);
         if (!argc) /* Create from stdin. */
-          gpgsm_sign (&ctrl, signerlist, 0, detached_sig, fp); 
+          gpgsm_sign (&ctrl, signerlist, 0, detached_sig, fp);
         else if (argc == 1) /* From file. */
           gpgsm_sign (&ctrl, signerlist,
-                      open_read (*argv), detached_sig, fp); 
+                      open_read (*argv), detached_sig, fp);
         else
           wrong_args ("--sign [datafile]");
 
         es_fclose (fp);
       }
       break;
-        
+
     case aSignEncr: /* sign and encrypt the given file */
       log_error ("this command has not yet been implemented\n");
       break;
@@ -1759,7 +1876,7 @@ main ( int argc, char **argv)
         else if (argc == 1)
           gpgsm_verify (&ctrl, open_read (*argv), -1, fp); /* std signature */
         else if (argc == 2) /* detached signature (sig, detached) */
-          gpgsm_verify (&ctrl, open_read (*argv), open_read (argv[1]), NULL); 
+          gpgsm_verify (&ctrl, open_read (*argv), open_read (argv[1]), NULL);
         else
           wrong_args ("--verify [signature [detached_data]]");
 
@@ -1792,7 +1909,7 @@ main ( int argc, char **argv)
 
     case aListChain:
     case aDumpChain:
-       ctrl.with_chain = 1;
+       ctrl.with_chain = 1; /* fall through */
     case aListKeys:
     case aDumpKeys:
     case aListExternalKeys:
@@ -1807,7 +1924,7 @@ main ( int argc, char **argv)
           {
           case aListChain:
           case aListKeys:         mode = (0   | 0 | (1<<6)); break;
-          case aDumpChain: 
+          case aDumpChain:
           case aDumpKeys:         mode = (256 | 0 | (1<<6)); break;
           case aListExternalKeys: mode = (0   | 0 | (1<<7)); break;
           case aDumpExternalKeys: mode = (256 | 0 | (1<<7)); break;
@@ -1829,27 +1946,26 @@ main ( int argc, char **argv)
     case aKeygen: /* Generate a key; well kind of. */
       {
         estream_t fpin = NULL;
-        FILE *fpout;
+        estream_t fpout;
 
         if (opt.batch)
           {
             if (!argc) /* Create from stdin. */
-              fpin = open_es_fread ("-"); 
+              fpin = open_es_fread ("-", "r");
             else if (argc == 1) /* From file. */
-              fpin = open_es_fread (*argv); 
+              fpin = open_es_fread (*argv, "r");
             else
-              wrong_args ("--gen-key --batch [parmfile]");
+              wrong_args ("--generate-key --batch [parmfile]");
           }
-        
-        fpout = open_fwrite (opt.outfile?opt.outfile:"-");
+
+        fpout = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         if (fpin)
           gpgsm_genkey (&ctrl, fpin, fpout);
         else
           gpgsm_gencertreq_tty (&ctrl, fpout);
 
-        if (fpout != stdout)
-          fclose (fpout);
+        es_fclose (fpout);
       }
       break;
 
@@ -1860,30 +1976,56 @@ main ( int argc, char **argv)
 
     case aExport:
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        estream_t fp;
 
+        fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
         for (sl=NULL; argc; argc--, argv++)
           add_to_strlist (&sl, *argv);
-        gpgsm_export (&ctrl, sl, fp, NULL);
+        gpgsm_export (&ctrl, sl, fp);
         free_strlist(sl);
-        if (fp != stdout)
-          fclose (fp);
+        es_fclose (fp);
       }
       break;
 
     case aExportSecretKeyP12:
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         if (argc == 1)
-          gpgsm_p12_export (&ctrl, *argv, fp);
+          gpgsm_p12_export (&ctrl, *argv, fp, 0);
         else
           wrong_args ("--export-secret-key-p12 KEY-ID");
-        if (fp != stdout)
-          fclose (fp);
+        if (fp != es_stdout)
+          es_fclose (fp);
+      }
+      break;
+
+    case aExportSecretKeyP8:
+      {
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
+
+        if (argc == 1)
+          gpgsm_p12_export (&ctrl, *argv, fp, 1);
+        else
+          wrong_args ("--export-secret-key-p8 KEY-ID");
+        if (fp != es_stdout)
+          es_fclose (fp);
+      }
+      break;
+
+    case aExportSecretKeyRaw:
+      {
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
+
+        if (argc == 1)
+          gpgsm_p12_export (&ctrl, *argv, fp, 2);
+        else
+          wrong_args ("--export-secret-key-raw KEY-ID");
+        if (fp != es_stdout)
+          es_fclose (fp);
       }
       break;
-      
+
     case aSendKeys:
     case aRecvKeys:
       log_error ("this command has not yet been implemented\n");
@@ -1903,19 +2045,19 @@ main ( int argc, char **argv)
 
     case aPasswd:
       if (argc != 1)
-        wrong_args ("--passwd <key-Id>");
+        wrong_args ("--change-passphrase <key-Id>");
       else
         {
           int rc;
           ksba_cert_t cert = NULL;
           char *grip = NULL;
 
-          rc = gpgsm_find_cert (*argv, NULL, &cert);
+          rc = gpgsm_find_cert (&ctrl, *argv, NULL, &cert, 0);
           if (rc)
             ;
           else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
             rc = gpg_error (GPG_ERR_BUG);
-          else 
+          else
             {
               char *desc = gpgsm_format_keydesc (cert);
               rc = gpgsm_agent_passwd (&ctrl, grip, desc);
@@ -1953,7 +2095,7 @@ main ( int argc, char **argv)
       es_fclose (auditfp);
       es_fclose (htmlauditfp);
     }
-  
+
   /* cleanup */
   keyserver_list_free (opt.keyserver);
   opt.keyserver = NULL;
@@ -1996,45 +2138,29 @@ gpgsm_init_default_ctrl (struct server_control_s *ctrl)
   ctrl->include_certs = default_include_certs;
   ctrl->use_ocsp = opt.enable_ocsp;
   ctrl->validation_model = default_validation_model;
+  ctrl->offline = opt.disable_dirmngr;
 }
 
 
 int
 gpgsm_parse_validation_model (const char *model)
-{     
+{
   if (!ascii_strcasecmp (model, "shell") )
     return 0;
   else if ( !ascii_strcasecmp (model, "chain") )
     return 1;
+  else if ( !ascii_strcasecmp (model, "steed") )
+    return 2;
   else
     return -1;
 }
 
 
-/* Check whether the filename has the form "-&nnnn", where n is a
-   non-zero number.  Returns this number or -1 if it is not the case.  */
-static int
-check_special_filename (const char *fname, int for_write)
-{
-  if (allow_special_filenames
-      && fname && *fname == '-' && fname[1] == '&' ) {
-    int i;
-    
-    fname += 2;
-    for (i=0; isdigit (fname[i]); i++ )
-      ;
-    if ( !fname[i] ) 
-      return translate_sys2libc_fd_int (atoi (fname), for_write);
-  }
-  return -1;
-}
-
-
 
 /* Open the FILENAME for read and return the file descriptor.  Stop
    with an error message in case of problems.  "-" denotes stdin and
    if special filenames are allowed the given fd is opened instead.  */
-static int 
+static int
 open_read (const char *filename)
 {
   int fd;
@@ -2044,13 +2170,13 @@ open_read (const char *filename)
       set_binary (stdin);
       return 0; /* stdin */
     }
-  fd = check_special_filename (filename, 0);
+  fd = check_special_filename (filename, 0, 0);
   if (fd != -1)
     return fd;
   fd = open (filename, O_RDONLY | O_BINARY);
   if (fd == -1)
     {
-      log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
+      log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fd;
@@ -2058,7 +2184,7 @@ open_read (const char *filename)
 
 /* Same as open_read but return an estream_t.  */
 static estream_t
-open_es_fread (const char *filename)
+open_es_fread (const char *filename, const char *mode)
 {
   int fd;
   estream_t fp;
@@ -2066,10 +2192,10 @@ open_es_fread (const char *filename)
   if (filename[0] == '-' && !filename[1])
     fd = fileno (stdin);
   else
-    fd = check_special_filename (filename, 0);
+    fd = check_special_filename (filename, 0, 0);
   if (fd != -1)
     {
-      fp = es_fdopen_nc (fd, "rb");
+      fp = es_fdopen_nc (fd, mode);
       if (!fp)
         {
           log_error ("es_fdopen(%d) failed: %s\n", fd, strerror (errno));
@@ -2077,48 +2203,10 @@ open_es_fread (const char *filename)
         }
       return fp;
     }
-  fp = es_fopen (filename, "rb");
+  fp = es_fopen (filename, mode);
   if (!fp)
     {
-      log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
-      gpgsm_exit (2);
-    }
-  return fp;
-}
-
-
-/* Open FILENAME for fwrite and return the stream.  Stop with an error
-   message in case of problems.  "-" denotes stdout and if special
-   filenames are allowed the given fd is opened instead. Caller must
-   close the returned stream unless it is stdout. */
-static FILE *
-open_fwrite (const char *filename)
-{
-  int fd;
-  FILE *fp;
-
-  if (filename[0] == '-' && !filename[1])
-    {
-      set_binary (stdout);
-      return stdout;
-    }
-
-  fd = check_special_filename (filename, 1);
-  if (fd != -1)
-    {
-      fp = fdopen (dup (fd), "wb");
-      if (!fp)
-        {
-          log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
-          gpgsm_exit (2);
-        }
-      set_binary (fp);
-      return fp;
-    }
-  fp = fopen (filename, "wb");
-  if (!fp)
-    {
-      log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
+      log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fp;
@@ -2142,7 +2230,7 @@ open_es_fwrite (const char *filename)
       return fp;
     }
 
-  fd = check_special_filename (filename, 1);
+  fd = check_special_filename (filename, 1, 0);
   if (fd != -1)
     {
       fp = es_fdopen_nc (fd, "wb");
@@ -2156,7 +2244,7 @@ open_es_fwrite (const char *filename)
   fp = es_fopen (filename, "wb");
   if (!fp)
     {
-      log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
+      log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fp;
@@ -2166,7 +2254,10 @@ open_es_fwrite (const char *filename)
 static void
 run_protect_tool (int argc, char **argv)
 {
-#ifndef HAVE_W32_SYSTEM
+#ifdef HAVE_W32_SYSTEM
+  (void)argc;
+  (void)argv;
+#else
   const char *pgm;
   char **av;
   int i;
@@ -2183,8 +2274,8 @@ run_protect_tool (int argc, char **argv)
   for (i=1; argc; i++, argc--, argv++)
     av[i] = *argv;
   av[i] = NULL;
-  execv (pgm, av); 
-  log_error ("error executing `%s': %s\n", pgm, strerror (errno));
-#endif /*HAVE_W32_SYSTEM*/
+  execv (pgm, av);
+  log_error ("error executing '%s': %s\n", pgm, strerror (errno));
+#endif /*!HAVE_W32_SYSTEM*/
   gpgsm_exit (2);
 }