diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:14:06 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:14:06 +0000 |
commit | eee068778cb28ecf3c14e1bf843a95547d72c42d (patch) | |
tree | 0e07b30ddc5ea579d682d5dbe57998200d1c9ab7 /g10/gpg.c | |
parent | Initial commit. (diff) | |
download | gnupg2-eee068778cb28ecf3c14e1bf843a95547d72c42d.tar.xz gnupg2-eee068778cb28ecf3c14e1bf843a95547d72c42d.zip |
Adding upstream version 2.2.40.upstream/2.2.40upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | g10/gpg.c | 5569 |
1 files changed, 5569 insertions, 0 deletions
diff --git a/g10/gpg.c b/g10/gpg.c new file mode 100644 index 0000000..bd65612 --- /dev/null +++ b/g10/gpg.c @@ -0,0 +1,5569 @@ +/* gpg.c - The GnuPG utility (main for gpg) + * Copyright (C) 1998-2020 Free Software Foundation, Inc. + * Copyright (C) 1997-2019 Werner Koch + * Copyright (C) 2015-2021 g10 Code GmbH + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <config.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#ifdef HAVE_STAT +#include <sys/stat.h> /* for stat() */ +#endif +#include <fcntl.h> +#ifdef HAVE_W32_SYSTEM +# ifdef HAVE_WINSOCK2_H +# include <winsock2.h> +# endif +# include <windows.h> +#endif + +#define INCLUDED_BY_MAIN_MODULE 1 +#include "gpg.h" +#include <assuan.h> +#include "../common/iobuf.h" +#include "../common/util.h" +#include "packet.h" +#include "../common/membuf.h" +#include "main.h" +#include "options.h" +#include "keydb.h" +#include "trustdb.h" +#include "filter.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 "../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 +#ifndef S_IRGRP +# define S_IRGRP 0 +# define S_IWGRP 0 +#endif +#else +#define MY_O_BINARY 0 +#endif + +enum cmd_and_opt_values + { + aNull = 0, + oArmor = 'a', + aDetachedSign = 'b', + aSym = 'c', + aDecrypt = 'd', + aEncr = 'e', + oRecipientFile = 'f', + oHiddenRecipientFile = 'F', + oInteractive = 'i', + aListKeys = 'k', + oDryRun = 'n', + oOutput = 'o', + oQuiet = 'q', + oRecipient = 'r', + oHiddenRecipient = 'R', + aSign = 's', + oTextmodeShort= 't', + oLocalUser = 'u', + oVerbose = 'v', + oCompress = 'z', + oSetNotation = 'N', + aListSecretKeys = 'K', + oBatch = 500, + oMaxOutput, + oInputSizeHint, + oSigNotation, + oCertNotation, + oShowNotation, + oNoShowNotation, + oKnownNotation, + aEncrFiles, + aEncrSym, + aDecryptFiles, + aClearsign, + aStore, + aQuickKeygen, + aFullKeygen, + aKeygen, + aSignEncr, + aSignEncrSym, + aSignSym, + aSignKey, + aLSignKey, + aQuickSignKey, + aQuickLSignKey, + aQuickRevSig, + aQuickAddUid, + aQuickAddKey, + aQuickRevUid, + aQuickSetExpire, + aQuickSetPrimaryUid, + aListConfig, + aListGcryptConfig, + aGPGConfList, + aGPGConfTest, + aListPackets, + aEditKey, + aDeleteKeys, + aDeleteSecretKeys, + aDeleteSecretAndPublicKeys, + aImport, + aFastImport, + aVerify, + aVerifyFiles, + aListSigs, + aSendKeys, + aRecvKeys, + aLocateKeys, + aLocateExtKeys, + aSearchKeys, + aRefreshKeys, + aFetchKeys, + aShowKeys, + aExport, + aExportSecret, + aExportSecretSub, + aExportSshKey, + aCheckKeys, + aGenRevoke, + aDesigRevoke, + aPrimegen, + aPrintMD, + aPrintMDs, + aCheckTrustDB, + aUpdateTrustDB, + aFixTrustDB, + aListTrustDB, + aListTrustPath, + aExportOwnerTrust, + aImportOwnerTrust, + aDeArmor, + aEnArmor, + aGenRandom, + aRebuildKeydbCaches, + aCardStatus, + aCardEdit, + aChangePIN, + aPasswd, + aServer, + aTOFUPolicy, + + oMimemode, + oTextmode, + oNoTextmode, + oExpert, + oNoExpert, + oDefSigExpire, + oAskSigExpire, + oNoAskSigExpire, + oDefCertExpire, + oAskCertExpire, + oNoAskCertExpire, + oDefCertLevel, + oMinCertLevel, + oAskCertLevel, + oNoAskCertLevel, + oFingerprint, + oWithFingerprint, + oWithSubkeyFingerprint, + oWithICAOSpelling, + oWithKeygrip, + oWithSecret, + oWithWKDHash, + oWithColons, + oWithKeyData, + oWithKeyOrigin, + oWithTofuInfo, + oWithSigList, + oWithSigCheck, + oAnswerYes, + oAnswerNo, + oKeyring, + oPrimaryKeyring, + oSecretKeyring, + oShowKeyring, + oDefaultKey, + oDefRecipient, + oDefRecipientSelf, + oNoDefRecipient, + oTrySecretKey, + oOptions, + oDebug, + oDebugLevel, + oDebugAll, + oDebugIOLBF, + oStatusFD, + oStatusFile, + oAttributeFD, + oAttributeFile, + oEmitVersion, + oNoEmitVersion, + oCompletesNeeded, + oMarginalsNeeded, + oMaxCertDepth, + oLoadExtension, + oCompliance, + oGnuPG, + oRFC2440, + oRFC4880, + oRFC4880bis, + oOpenPGP, + oPGP6, + oPGP7, + oPGP8, + oDE_VS, + oMinRSALength, + oRFC2440Text, + oNoRFC2440Text, + oCipherAlgo, + oDigestAlgo, + oCertDigestAlgo, + oCompressAlgo, + oCompressLevel, + oBZ2CompressLevel, + oBZ2DecompressLowmem, + oPassphrase, + oPassphraseFD, + oPassphraseFile, + oPassphraseRepeat, + oPinentryMode, + oCommandFD, + oCommandFile, + oQuickRandom, + oNoVerbose, + oTrustDBName, + oNoSecmemWarn, + oRequireSecmem, + oNoRequireSecmem, + oNoPermissionWarn, + oNoArmor, + oNoDefKeyring, + oNoKeyring, + oNoGreeting, + oNoTTY, + oNoOptions, + oNoBatch, + oHomedir, + oSkipVerify, + oSkipHiddenRecipients, + oNoSkipHiddenRecipients, + oAlwaysTrust, + oTrustModel, + oForceOwnertrust, + oSetFilename, + oForYourEyesOnly, + oNoForYourEyesOnly, + oSetPolicyURL, + oSigPolicyURL, + oCertPolicyURL, + oShowPolicyURL, + oNoShowPolicyURL, + oSigKeyserverURL, + oUseEmbeddedFilename, + oNoUseEmbeddedFilename, + oComment, + oDefaultComment, + oNoComments, + oThrowKeyids, + oNoThrowKeyids, + oShowPhotos, + oNoShowPhotos, + oPhotoViewer, + oS2KMode, + oS2KDigest, + oS2KCipher, + oS2KCount, + oDisplayCharset, + oNotDashEscaped, + oEscapeFrom, + oNoEscapeFrom, + oLockOnce, + oLockMultiple, + oLockNever, + oKeyServer, + oKeyServerOptions, + oImportOptions, + oImportFilter, + oExportOptions, + oExportFilter, + oListOptions, + oVerifyOptions, + oTempDir, + oExecPath, + oEncryptTo, + oHiddenEncryptTo, + oNoEncryptTo, + oEncryptToDefaultKey, + oLoggerFD, + oLoggerFile, + oUtf8Strings, + oNoUtf8Strings, + oDisableCipherAlgo, + oDisablePubkeyAlgo, + oAllowNonSelfsignedUID, + oNoAllowNonSelfsignedUID, + oAllowFreeformUID, + oNoAllowFreeformUID, + oAllowSecretKeyImport, + oEnableSpecialFilenames, + oNoLiteral, + oSetFilesize, + oHonorHttpProxy, + oFastListMode, + oListOnly, + oIgnoreTimeConflict, + oIgnoreValidFrom, + oIgnoreCrcError, + oIgnoreMDCError, + oShowSessionKey, + oOverrideSessionKey, + oOverrideSessionKeyFD, + oOverrideComplianceCheck, + oNoRandomSeedFile, + oAutoKeyRetrieve, + oNoAutoKeyRetrieve, + oAutoKeyImport, + oNoAutoKeyImport, + oUseAgent, + oNoUseAgent, + oGpgAgentInfo, + oMergeOnly, + oTryAllSecrets, + oTrustedKey, + oNoExpensiveTrustChecks, + oFixedListMode, + oLegacyListMode, + oNoSigCache, + oAutoCheckTrustDB, + oNoAutoCheckTrustDB, + oPreservePermissions, + oDefaultPreferenceList, + oDefaultKeyserverURL, + oPersonalCipherPreferences, + oPersonalDigestPreferences, + oPersonalCompressPreferences, + oAgentProgram, + oDirmngrProgram, + oDisableDirmngr, + oDisplay, + oTTYname, + oTTYtype, + oLCctype, + oLCmessages, + oXauthority, + oGroup, + oUnGroup, + oNoGroups, + oStrict, + oNoStrict, + oMangleDosFilenames, + oNoMangleDosFilenames, + oEnableProgressFilter, + oMultifile, + oKeyidFormat, + oExitOnStatusWriteError, + oLimitCardInsertTries, + oReaderPort, + octapiDriver, + opcscDriver, + oDisableCCID, + oRequireCrossCert, + oNoRequireCrossCert, + oAutoKeyLocate, + oNoAutoKeyLocate, + oAllowMultisigVerification, + oEnableLargeRSA, + oDisableLargeRSA, + oEnableDSA2, + oDisableDSA2, + oAllowMultipleMessages, + oNoAllowMultipleMessages, + oAllowWeakDigestAlgos, + oAllowWeakKeySignatures, + oFakedSystemTime, + oNoAutostart, + oPrintPKARecords, + oPrintDANERecords, + oTOFUDefaultPolicy, + oTOFUDBFormat, + oDefaultNewKeyAlgo, + oWeakDigest, + oUnwrap, + oOnlySignTextIDs, + oDisableSignerUID, + oSender, + oKeyOrigin, + oRequestOrigin, + oNoSymkeyCache, + oUseOnlyOpenPGPCard, + oIncludeKeyBlock, + oNoIncludeKeyBlock, + oForceSignKey, + oForbidGenKey, + oRequireCompliance, + + oNoop + }; + + +static ARGPARSE_OPTS opts[] = { + + ARGPARSE_group (300, N_("@Commands:\n ")), + + ARGPARSE_c (aSign, "sign", N_("make a signature")), + ARGPARSE_c (aClearsign, "clear-sign", N_("make a clear text signature")), + ARGPARSE_c (aClearsign, "clearsign", "@"), + ARGPARSE_c (aDetachedSign, "detach-sign", N_("make a detached signature")), + ARGPARSE_c (aEncr, "encrypt", N_("encrypt data")), + ARGPARSE_c (aEncrFiles, "encrypt-files", "@"), + ARGPARSE_c (aSym, "symmetric", N_("encryption only with symmetric cipher")), + ARGPARSE_c (aStore, "store", "@"), + ARGPARSE_c (aDecrypt, "decrypt", N_("decrypt data (default)")), + ARGPARSE_c (aDecryptFiles, "decrypt-files", "@"), + ARGPARSE_c (aVerify, "verify" , N_("verify a signature")), + ARGPARSE_c (aVerifyFiles, "verify-files" , "@" ), + ARGPARSE_c (aListKeys, "list-keys", N_("list keys")), + 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-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, "generate-key", + N_("generate a new key pair")), + ARGPARSE_c (aKeygen, "gen-key", "@"), + ARGPARSE_c (aQuickKeygen, "quick-generate-key" , + N_("quickly generate a new key pair")), + 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-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 (aQuickSetPrimaryUid, "quick-set-primary-uid", "@"), + ARGPARSE_c (aFullKeygen, "full-generate-key" , + N_("full featured key pair generation")), + 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", + N_("remove keys from the secret keyring")), + ARGPARSE_c (aQuickSignKey, "quick-sign-key" , + N_("quickly sign a key")), + ARGPARSE_c (aQuickLSignKey, "quick-lsign-key", + N_("quickly sign a key locally")), + ARGPARSE_c (aQuickRevSig, "quick-revoke-sig" , + N_("quickly revoke a key signature")), + ARGPARSE_c (aSignKey, "sign-key" ,N_("sign a key")), + 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, "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") ), + ARGPARSE_c (aRecvKeys, "receive-keys" , N_("import keys from a keyserver") ), + ARGPARSE_c (aRecvKeys, "recv-keys" , "@"), + ARGPARSE_c (aSearchKeys, "search-keys" , + N_("search for keys on a keyserver") ), + ARGPARSE_c (aRefreshKeys, "refresh-keys", + N_("update all keys from a keyserver")), + ARGPARSE_c (aLocateKeys, "locate-keys", "@"), + ARGPARSE_c (aLocateExtKeys, "locate-external-keys", "@"), + ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ), + ARGPARSE_c (aShowKeys, "show-keys" , "@" ), + ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ), + ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ), + ARGPARSE_c (aExportSshKey, "export-ssh-key", "@" ), + ARGPARSE_c (aImport, "import", N_("import/merge keys")), + ARGPARSE_c (aFastImport, "fast-import", "@"), +#ifdef ENABLE_CARD_SUPPORT + ARGPARSE_c (aCardStatus, "card-status", N_("print the card status")), + 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", "@"), + ARGPARSE_c (aListGcryptConfig, "list-gcrypt-config", "@"), + ARGPARSE_c (aGPGConfList, "gpgconf-list", "@" ), + ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@" ), + ARGPARSE_c (aListPackets, "list-packets","@"), + +#ifndef NO_TRUST_MODELS + ARGPARSE_c (aExportOwnerTrust, "export-ownertrust", "@"), + ARGPARSE_c (aImportOwnerTrust, "import-ownertrust", "@"), + ARGPARSE_c (aUpdateTrustDB,"update-trustdb", + N_("update the trust database")), + ARGPARSE_c (aCheckTrustDB, "check-trustdb", "@"), + ARGPARSE_c (aFixTrustDB, "fix-trustdb", "@"), + ARGPARSE_c (aListTrustDB, "list-trustdb", "@"), +#endif + + ARGPARSE_c (aDeArmor, "dearmor", "@"), + ARGPARSE_c (aDeArmor, "dearmour", "@"), + ARGPARSE_c (aEnArmor, "enarmor", "@"), + ARGPARSE_c (aEnArmor, "enarmour", "@"), + ARGPARSE_c (aPrintMD, "print-md", N_("print message digests")), + ARGPARSE_c (aPrintMDs, "print-mds", "@"), /* old */ + ARGPARSE_c (aPrimegen, "gen-prime", "@" ), + ARGPARSE_c (aGenRandom,"gen-random", "@" ), + ARGPARSE_c (aServer, "server", N_("run in server mode")), + ARGPARSE_c (aTOFUPolicy, "tofu-policy", + N_("|VALUE|set the TOFU policy for a key")), + /* Not yet used: + ARGPARSE_c (aListTrustPath, "list-trust-path", "@"), */ + ARGPARSE_c (aDeleteSecretAndPublicKeys, + "delete-secret-and-public-keys", "@"), + ARGPARSE_c (aRebuildKeydbCaches, "rebuild-keydb-caches", "@"), + ARGPARSE_c (aListKeys, "list-key", "@"), /* alias */ + ARGPARSE_c (aListSigs, "list-sig", "@"), /* alias */ + ARGPARSE_c (aCheckKeys, "check-sig", "@"), /* alias */ + ARGPARSE_c (aShowKeys, "show-key", "@"), /* alias */ + + + ARGPARSE_header ("Monitor", N_("Options controlling the diagnostic output")), + + ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")), + ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"), + ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")), + ARGPARSE_s_n (oNoTTY, "no-tty", "@"), + ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"), + ARGPARSE_s_s (oDebug, "debug", "@"), + ARGPARSE_s_s (oDebugLevel, "debug-level", "@"), + ARGPARSE_s_n (oDebugAll, "debug-all", "@"), + ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"), + ARGPARSE_s_s (oDisplayCharset, "display-charset", "@"), + ARGPARSE_s_s (oDisplayCharset, "charset", "@"), + ARGPARSE_conffile (oOptions, "options", N_("|FILE|read options from FILE")), + ARGPARSE_noconffile (oNoOptions, "no-options", "@"), + ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"), + ARGPARSE_s_s (oLoggerFile, "log-file", + N_("|FILE|write server mode logs to FILE")), + ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */ + ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"), + + + ARGPARSE_header ("Configuration", + N_("Options controlling the configuration")), + + ARGPARSE_s_s (oHomedir, "homedir", "@"), + ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"), + ARGPARSE_s_s (oDefaultKey, "default-key", + N_("|NAME|use NAME as default secret key")), + ARGPARSE_s_s (oEncryptTo, "encrypt-to", + N_("|NAME|encrypt to user ID NAME as well")), + ARGPARSE_s_n (oNoEncryptTo, "no-encrypt-to", "@"), + ARGPARSE_s_s (oHiddenEncryptTo, "hidden-encrypt-to", "@"), + ARGPARSE_s_n (oEncryptToDefaultKey, "encrypt-to-default-key", "@"), + ARGPARSE_s_s (oDefRecipient, "default-recipient", "@"), + ARGPARSE_s_n (oDefRecipientSelf, "default-recipient-self", "@"), + ARGPARSE_s_n (oNoDefRecipient, "no-default-recipient", "@"), + ARGPARSE_s_s (oGroup, "group", + N_("|SPEC|set up email aliases")), + ARGPARSE_s_s (oUnGroup, "ungroup", "@"), + ARGPARSE_s_n (oNoGroups, "no-groups", "@"), + ARGPARSE_s_s (oCompliance, "compliance", "@"), + ARGPARSE_s_n (oGnuPG, "gnupg", "@"), + ARGPARSE_s_n (oGnuPG, "no-pgp2", "@"), + ARGPARSE_s_n (oGnuPG, "no-pgp6", "@"), + ARGPARSE_s_n (oGnuPG, "no-pgp7", "@"), + ARGPARSE_s_n (oGnuPG, "no-pgp8", "@"), + ARGPARSE_s_n (oRFC2440, "rfc2440", "@"), + ARGPARSE_s_n (oRFC4880, "rfc4880", "@"), + ARGPARSE_s_n (oRFC4880bis, "rfc4880bis", "@"), + ARGPARSE_s_n (oOpenPGP, "openpgp", N_("use strict OpenPGP behavior")), + ARGPARSE_s_n (oPGP6, "pgp6", "@"), + ARGPARSE_s_n (oPGP7, "pgp7", "@"), + ARGPARSE_s_n (oPGP8, "pgp8", "@"), + ARGPARSE_s_s (oDefaultNewKeyAlgo, "default-new-key-algo", "@"), + ARGPARSE_p_u (oMinRSALength, "min-rsa-length", "@"), +#ifndef NO_TRUST_MODELS + ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"), +#endif + ARGPARSE_s_s (oTrustModel, "trust-model", "@"), + ARGPARSE_s_s (oPhotoViewer, "photo-viewer", "@"), + ARGPARSE_s_s (oKnownNotation, "known-notation", "@"), + ARGPARSE_s_s (oAgentProgram, "agent-program", "@"), + ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"), + ARGPARSE_s_n (oExitOnStatusWriteError, "exit-on-status-write-error", "@"), + ARGPARSE_s_i (oLimitCardInsertTries, "limit-card-insert-tries", "@"), + ARGPARSE_s_n (oEnableProgressFilter, "enable-progress-filter", "@"), + ARGPARSE_s_s (oTempDir, "temp-directory", "@"), + ARGPARSE_s_s (oExecPath, "exec-path", "@"), + ARGPARSE_s_n (oExpert, "expert", "@"), + ARGPARSE_s_n (oNoExpert, "no-expert", "@"), + ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"), + ARGPARSE_s_n (oRequireSecmem, "require-secmem", "@"), + ARGPARSE_s_n (oNoRequireSecmem, "no-require-secmem", "@"), + ARGPARSE_s_n (oNoPermissionWarn, "no-permission-warning", "@"), + ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")), + ARGPARSE_s_n (oInteractive, "interactive", N_("prompt before overwriting")), + ARGPARSE_s_s (oDefSigExpire, "default-sig-expire", "@"), + ARGPARSE_s_n (oAskSigExpire, "ask-sig-expire", "@"), + ARGPARSE_s_n (oNoAskSigExpire, "no-ask-sig-expire", "@"), + ARGPARSE_s_s (oDefCertExpire, "default-cert-expire", "@"), + ARGPARSE_s_n (oAskCertExpire, "ask-cert-expire", "@"), + ARGPARSE_s_n (oNoAskCertExpire, "no-ask-cert-expire", "@"), + ARGPARSE_s_i (oDefCertLevel, "default-cert-level", "@"), + ARGPARSE_s_i (oMinCertLevel, "min-cert-level", "@"), + ARGPARSE_s_n (oAskCertLevel, "ask-cert-level", "@"), + ARGPARSE_s_n (oNoAskCertLevel, "no-ask-cert-level", "@"), + ARGPARSE_s_n (oOnlySignTextIDs, "only-sign-text-ids", "@"), + ARGPARSE_s_n (oEnableLargeRSA, "enable-large-rsa", "@"), + ARGPARSE_s_n (oDisableLargeRSA, "disable-large-rsa", "@"), + ARGPARSE_s_n (oEnableDSA2, "enable-dsa2", "@"), + ARGPARSE_s_n (oDisableDSA2, "disable-dsa2", "@"), + ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-preferences","@"), + ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-preferences","@"), + ARGPARSE_s_s (oPersonalCompressPreferences, + "personal-compress-preferences", "@"), + ARGPARSE_s_s (oDefaultPreferenceList, "default-preference-list", "@"), + ARGPARSE_s_s (oDefaultKeyserverURL, "default-keyserver-url", "@"), + ARGPARSE_s_n (oNoExpensiveTrustChecks, "no-expensive-trust-checks", "@"), + ARGPARSE_s_n (oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", "@"), + ARGPARSE_s_n (oNoAllowNonSelfsignedUID, "no-allow-non-selfsigned-uid", "@"), + ARGPARSE_s_n (oAllowFreeformUID, "allow-freeform-uid", "@"), + ARGPARSE_s_n (oNoAllowFreeformUID, "no-allow-freeform-uid", "@"), + ARGPARSE_s_n (oPreservePermissions, "preserve-permissions", "@"), + ARGPARSE_s_i (oDefCertLevel, "default-cert-check-level", "@"), /* old */ + ARGPARSE_s_s (oTOFUDefaultPolicy, "tofu-default-policy", "@"), + ARGPARSE_s_n (oLockOnce, "lock-once", "@"), + ARGPARSE_s_n (oLockMultiple, "lock-multiple", "@"), + ARGPARSE_s_n (oLockNever, "lock-never", "@"), + ARGPARSE_s_s (oCompressAlgo,"compress-algo", "@"), + ARGPARSE_s_s (oCompressAlgo, "compression-algo", "@"), /* Alias */ + ARGPARSE_s_n (oBZ2DecompressLowmem, "bzip2-decompress-lowmem", "@"), + ARGPARSE_s_i (oCompletesNeeded, "completes-needed", "@"), + ARGPARSE_s_i (oMarginalsNeeded, "marginals-needed", "@"), + ARGPARSE_s_i (oMaxCertDepth, "max-cert-depth", "@" ), +#ifndef NO_TRUST_MODELS + ARGPARSE_s_s (oTrustDBName, "trustdb-name", "@"), + ARGPARSE_s_n (oAutoCheckTrustDB, "auto-check-trustdb", "@"), + ARGPARSE_s_n (oNoAutoCheckTrustDB, "no-auto-check-trustdb", "@"), + ARGPARSE_s_s (oForceOwnertrust, "force-ownertrust", "@"), +#endif + + + ARGPARSE_header ("Input", N_("Options controlling the input")), + + ARGPARSE_s_n (oMultifile, "multifile", "@"), + ARGPARSE_s_s (oInputSizeHint, "input-size-hint", "@"), + ARGPARSE_s_n (oUtf8Strings, "utf8-strings", "@"), + ARGPARSE_s_n (oNoUtf8Strings, "no-utf8-strings", "@"), + ARGPARSE_p_u (oSetFilesize, "set-filesize", "@"), + ARGPARSE_s_n (oNoLiteral, "no-literal", "@"), + ARGPARSE_s_s (oSetNotation, "set-notation", "@"), + ARGPARSE_s_s (oSigNotation, "sig-notation", "@"), + ARGPARSE_s_s (oCertNotation, "cert-notation", "@"), + ARGPARSE_s_s (oSetPolicyURL, "set-policy-url", "@"), + ARGPARSE_s_s (oSigPolicyURL, "sig-policy-url", "@"), + ARGPARSE_s_s (oCertPolicyURL, "cert-policy-url", "@"), + ARGPARSE_s_s (oSigKeyserverURL, "sig-keyserver-url", "@"), + + + + ARGPARSE_header ("Output", N_("Options controlling the output")), + + ARGPARSE_s_n (oArmor, "armor", N_("create ascii armored output")), + ARGPARSE_s_n (oArmor, "armour", "@"), + ARGPARSE_s_n (oNoArmor, "no-armor", "@"), + ARGPARSE_s_n (oNoArmor, "no-armour", "@"), + ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")), + ARGPARSE_p_u (oMaxOutput, "max-output", "@"), + ARGPARSE_s_s (oComment, "comment", "@"), + ARGPARSE_s_n (oDefaultComment, "default-comment", "@"), + ARGPARSE_s_n (oNoComments, "no-comments", "@"), + ARGPARSE_s_n (oEmitVersion, "emit-version", "@"), + ARGPARSE_s_n (oNoEmitVersion, "no-emit-version", "@"), + ARGPARSE_s_n (oNoEmitVersion, "no-version", "@"), /* alias */ + ARGPARSE_s_n (oNotDashEscaped, "not-dash-escaped", "@"), + ARGPARSE_s_n (oEscapeFrom, "escape-from-lines", "@"), + ARGPARSE_s_n (oNoEscapeFrom, "no-escape-from-lines", "@"), + ARGPARSE_s_n (oMimemode, "mimemode", "@"), + ARGPARSE_s_n (oTextmodeShort, NULL, "@"), + ARGPARSE_s_n (oTextmode, "textmode", N_("use canonical text mode")), + ARGPARSE_s_n (oNoTextmode, "no-textmode", "@"), + ARGPARSE_s_s (oSetFilename, "set-filename", "@"), + ARGPARSE_s_n (oForYourEyesOnly, "for-your-eyes-only", "@"), + ARGPARSE_s_n (oNoForYourEyesOnly, "no-for-your-eyes-only", "@"), + ARGPARSE_s_n (oShowNotation, "show-notation", "@"), + ARGPARSE_s_n (oNoShowNotation, "no-show-notation", "@"), + ARGPARSE_s_n (oShowSessionKey, "show-session-key", "@"), + ARGPARSE_s_n (oUseEmbeddedFilename, "use-embedded-filename", "@"), + ARGPARSE_s_n (oNoUseEmbeddedFilename, "no-use-embedded-filename", "@"), + ARGPARSE_s_n (oUnwrap, "unwrap", "@"), + ARGPARSE_s_n (oMangleDosFilenames, "mangle-dos-filenames", "@"), + ARGPARSE_s_n (oNoMangleDosFilenames, "no-mangle-dos-filenames", "@"), + ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"), + ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"), + ARGPARSE_s_n (oListOnly, "list-only", "@"), + ARGPARSE_s_i (oCompress, NULL, + N_("|N|set compress level to N (0 disables)")), + ARGPARSE_s_i (oCompressLevel, "compress-level", "@"), + ARGPARSE_s_i (oBZ2CompressLevel, "bzip2-compress-level", "@"), + ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"), + + + ARGPARSE_header ("ImportExport", + N_("Options controlling key import and export")), + + ARGPARSE_s_s (oAutoKeyLocate, "auto-key-locate", + N_("|MECHANISMS|use MECHANISMS to locate keys by mail address")), + ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"), + ARGPARSE_s_n (oAutoKeyImport, "auto-key-import", + N_("import missing key from a signature")), + ARGPARSE_s_n (oNoAutoKeyImport, "no-auto-key-import", "@"), + ARGPARSE_s_n (oAutoKeyRetrieve, "auto-key-retrieve", "@"), + ARGPARSE_s_n (oNoAutoKeyRetrieve, "no-auto-key-retrieve", "@"), + ARGPARSE_s_n (oIncludeKeyBlock, "include-key-block", + N_("include the public key in signatures")), + ARGPARSE_s_n (oNoIncludeKeyBlock, "no-include-key-block", "@"), + ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", + N_("disable all access to the dirmngr")), + ARGPARSE_s_s (oKeyServer, "keyserver", "@"), /* Deprecated. */ + 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", "@"), + ARGPARSE_s_s (oExportFilter, "export-filter", "@"), + ARGPARSE_s_n (oMergeOnly, "merge-only", "@" ), + ARGPARSE_s_n (oAllowSecretKeyImport, "allow-secret-key-import", "@"), + + + ARGPARSE_header ("Keylist", N_("Options controlling key listings")), + + ARGPARSE_s_s (oListOptions, "list-options", "@"), + ARGPARSE_s_n (oShowPhotos, "show-photos", "@"), + ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"), + ARGPARSE_s_n (oShowPolicyURL, "show-policy-url", "@"), + ARGPARSE_s_n (oNoShowPolicyURL, "no-show-policy-url", "@"), + ARGPARSE_s_n (oWithColons, "with-colons", "@"), + ARGPARSE_s_n (oWithTofuInfo,"with-tofu-info", "@"), + ARGPARSE_s_n (oWithKeyData,"with-key-data", "@"), + ARGPARSE_s_n (oWithSigList,"with-sig-list", "@"), + ARGPARSE_s_n (oWithSigCheck,"with-sig-check", "@"), + ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"), + ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprint", "@"), + ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"), + ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"), + 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_n (oFastListMode, "fast-list-mode", "@"), + ARGPARSE_s_n (oFixedListMode, "fixed-list-mode", "@"), + ARGPARSE_s_n (oLegacyListMode, "legacy-list-mode", "@"), + ARGPARSE_s_n (oPrintPKARecords, "print-pka-records", "@"), + ARGPARSE_s_n (oPrintDANERecords, "print-dane-records", "@"), + ARGPARSE_s_s (oKeyidFormat, "keyid-format", "@"), + ARGPARSE_s_n (oShowKeyring, "show-keyring", "@"), + + + ARGPARSE_header (NULL, N_("Options to specify keys")), + + ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")), + ARGPARSE_s_s (oHiddenRecipient, "hidden-recipient", "@"), + ARGPARSE_s_s (oRecipientFile, "recipient-file", "@"), + ARGPARSE_s_s (oHiddenRecipientFile, "hidden-recipient-file", "@"), + ARGPARSE_s_s (oRecipient, "remote-user", "@"), /* (old option name) */ + ARGPARSE_s_n (oThrowKeyids, "throw-keyids", "@"), + ARGPARSE_s_n (oNoThrowKeyids, "no-throw-keyids", "@"), + ARGPARSE_s_s (oLocalUser, "local-user", + N_("|USER-ID|use USER-ID to sign or decrypt")), + ARGPARSE_s_s (oTrustedKey, "trusted-key", "@"), + ARGPARSE_s_s (oSender, "sender", "@"), + ARGPARSE_s_s (oTrySecretKey, "try-secret-key", "@"), + ARGPARSE_s_n (oTryAllSecrets, "try-all-secrets", "@"), + ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"), + ARGPARSE_s_n (oNoKeyring, "no-keyring", "@"), + ARGPARSE_s_s (oKeyring, "keyring", "@"), + ARGPARSE_s_s (oPrimaryKeyring, "primary-keyring", "@"), + ARGPARSE_s_s (oSecretKeyring, "secret-keyring", "@"), + ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"), + ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"), + ARGPARSE_s_s (oOverrideSessionKey, "override-session-key", "@"), + ARGPARSE_s_i (oOverrideSessionKeyFD, "override-session-key-fd", "@"), + + + ARGPARSE_header ("Security", N_("Options controlling the security")), + + ARGPARSE_s_i (oS2KMode, "s2k-mode", "@"), + ARGPARSE_s_s (oS2KDigest, "s2k-digest-algo", "@"), + ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"), + ARGPARSE_s_i (oS2KCount, "s2k-count", "@"), + ARGPARSE_s_n (oRequireCrossCert, "require-backsigs", "@"), + ARGPARSE_s_n (oRequireCrossCert, "require-cross-certification", "@"), + ARGPARSE_s_n (oNoRequireCrossCert, "no-require-backsigs", "@"), + ARGPARSE_s_n (oNoRequireCrossCert, "no-require-cross-certification", "@"), + ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"), + ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"), + ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"), + ARGPARSE_s_n (oNoSigCache, "no-sig-cache", "@"), + ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"), + ARGPARSE_s_n (oIgnoreValidFrom, "ignore-valid-from", "@"), + ARGPARSE_s_n (oIgnoreCrcError, "ignore-crc-error", "@"), + ARGPARSE_s_n (oIgnoreMDCError, "ignore-mdc-error", "@"), + ARGPARSE_s_s (oDisableCipherAlgo, "disable-cipher-algo", "@"), + ARGPARSE_s_s (oDisablePubkeyAlgo, "disable-pubkey-algo", "@"), + ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"), + ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"), + ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"), + ARGPARSE_s_n (oOverrideComplianceCheck, "override-compliance-check", "@"), + /* Options to override new security defaults. */ + ARGPARSE_s_n (oAllowWeakKeySignatures, "allow-weak-key-signatures", "@"), + ARGPARSE_s_n (oAllowWeakDigestAlgos, "allow-weak-digest-algos", "@"), + ARGPARSE_s_s (oWeakDigest, "weak-digest","@"), + ARGPARSE_s_n (oAllowMultisigVerification, + "allow-multisig-verification", "@"), + ARGPARSE_s_n (oAllowMultipleMessages, "allow-multiple-messages", "@"), + ARGPARSE_s_n (oNoAllowMultipleMessages, "no-allow-multiple-messages", "@"), + + + + ARGPARSE_header (NULL, N_("Options for unattended use")), + + ARGPARSE_s_n (oBatch, "batch", "@"), + ARGPARSE_s_n (oNoBatch, "no-batch", "@"), + ARGPARSE_s_n (oAnswerYes, "yes", "@"), + ARGPARSE_s_n (oAnswerNo, "no", "@"), + ARGPARSE_s_i (oStatusFD, "status-fd", "@"), + ARGPARSE_s_s (oStatusFile, "status-file", "@"), + ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"), + ARGPARSE_s_s (oAttributeFile, "attribute-file", "@"), + ARGPARSE_s_i (oCommandFD, "command-fd", "@"), + ARGPARSE_s_s (oCommandFile, "command-file", "@"), + ARGPARSE_o_s (oPassphrase, "passphrase", "@"), + ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"), + ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"), + ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"), + ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"), + ARGPARSE_s_n (oForceSignKey, "force-sign-key", "@"), + + ARGPARSE_header (NULL, N_("Other options")), + + ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"), + ARGPARSE_s_s (oDisplay, "display", "@"), + ARGPARSE_s_s (oTTYname, "ttyname", "@"), + ARGPARSE_s_s (oTTYtype, "ttytype", "@"), + ARGPARSE_s_s (oLCctype, "lc-ctype", "@"), + ARGPARSE_s_s (oLCmessages, "lc-messages","@"), + ARGPARSE_s_s (oXauthority, "xauthority", "@"), + ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), + ARGPARSE_s_n (oForbidGenKey, "forbid-gen-key", "@"), + ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"), + /* Options which can be used in special circumstances. They are not + * published and we hope they are never required. */ + ARGPARSE_s_n (oUseOnlyOpenPGPCard, "use-only-openpgp-card", "@"), + /* Esoteric compatibility options. */ + ARGPARSE_s_n (oRFC2440Text, "rfc2440-text", "@"), + ARGPARSE_s_n (oNoRFC2440Text, "no-rfc2440-text", "@"), + + ARGPARSE_header (NULL, ""), /* Stop the header group. */ + + + /* Aliases. I constantly mistype these, and assume other people do + as well. */ + ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"), + ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"), + ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"), + + /* These two are aliases to help users of the PGP command line + product use gpg with minimal pain. Many commands are common + already as they seem to have borrowed commands from us. Now I'm + returning the favor. */ + ARGPARSE_s_s (oLocalUser, "sign-with", "@"), + ARGPARSE_s_s (oRecipient, "user", "@"), + + + /* Dummy options with warnings. */ + ARGPARSE_s_n (oUseAgent, "use-agent", "@"), + ARGPARSE_s_n (oNoUseAgent, "no-use-agent", "@"), + ARGPARSE_s_s (oGpgAgentInfo, "gpg-agent-info", "@"), + ARGPARSE_s_s (oReaderPort, "reader-port", "@"), + ARGPARSE_s_s (octapiDriver, "ctapi-driver", "@"), + ARGPARSE_s_s (opcscDriver, "pcsc-driver", "@"), + ARGPARSE_s_n (oDisableCCID, "disable-ccid", "@"), + ARGPARSE_s_n (oHonorHttpProxy, "honor-http-proxy", "@"), + ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"), + + /* Dummy options. */ + ARGPARSE_ignore (oStrict, "strict"), + ARGPARSE_ignore (oNoStrict, "no-strict"), + ARGPARSE_ignore (oLoadExtension, "load-extension"), /* from 1.4. */ + + ARGPARSE_s_n (oNoop, "sk-comments", "@"), + ARGPARSE_s_n (oNoop, "no-sk-comments", "@"), + ARGPARSE_s_n (oNoop, "compress-keys", "@"), + ARGPARSE_s_n (oNoop, "compress-sigs", "@"), + ARGPARSE_s_n (oNoop, "force-v3-sigs", "@"), + ARGPARSE_s_n (oNoop, "no-force-v3-sigs", "@"), + ARGPARSE_s_n (oNoop, "force-v4-certs", "@"), + ARGPARSE_s_n (oNoop, "no-force-v4-certs", "@"), + ARGPARSE_s_n (oNoop, "no-mdc-warning", "@"), + ARGPARSE_s_n (oNoop, "force-mdc", "@"), + ARGPARSE_s_n (oNoop, "no-force-mdc", "@"), + ARGPARSE_s_n (oNoop, "disable-mdc", "@"), + ARGPARSE_s_n (oNoop, "no-disable-mdc", "@"), + + + 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" + " --clear-sign [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")), + + + ARGPARSE_end () +}; + + +/* The list of supported debug flags. */ +static struct debug_flags_s debug_flags [] = + { + { DBG_PACKET_VALUE , "packet" }, + { DBG_MPI_VALUE , "mpi" }, + { DBG_CRYPTO_VALUE , "crypto" }, + { DBG_FILTER_VALUE , "filter" }, + { DBG_IOBUF_VALUE , "iobuf" }, + { DBG_MEMORY_VALUE , "memory" }, + { DBG_CACHE_VALUE , "cache" }, + { DBG_MEMSTAT_VALUE, "memstat" }, + { DBG_TRUST_VALUE , "trust" }, + { DBG_HASHING_VALUE, "hashing" }, + { DBG_IPC_VALUE , "ipc" }, + { DBG_CLOCK_VALUE , "clock" }, + { DBG_LOOKUP_VALUE , "lookup" }, + { DBG_EXTPROG_VALUE, "extprog" }, + { 0, NULL } + }; + + +#ifdef ENABLE_SELINUX_HACKS +#define ALWAYS_ADD_KEYRINGS 1 +#else +#define ALWAYS_ADD_KEYRINGS 0 +#endif + +/* The list of the default AKL methods. */ +#define DEFAULT_AKL_LIST "local,wkd" + + +int g10_errors_seen = 0; + +static int utf8_strings = +#ifdef HAVE_W32_SYSTEM + 1 +#else + 0 +#endif + ; +static int maybe_setuid = 1; + +/* Collection of options used only in this module. */ +static struct { + unsigned int forbid_gen_key; +} mopt; + + +static char *build_list( const char *text, char letter, + const char *(*mapf)(int), int (*chkf)(int) ); +static void set_cmd( enum cmd_and_opt_values *ret_cmd, + enum cmd_and_opt_values new_cmd ); +static void print_mds( const char *fname, int algo ); +static void add_notation_data( const char *string, int which ); +static void add_policy_url( const char *string, int which ); +static void add_keyserver_url( const char *string, int which ); +static void emergency_cleanup (void); +static void read_sessionkey_from_fd (int fd); + + +static char * +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. */ + maybe_setuid = 0; + } + s = getfnc (NULL); + result = xmalloc (strlen (libname) + 1 + strlen (s) + 1); + strcpy (stpcpy (stpcpy (result, libname), " "), s); + return result; +} + + +static int +build_list_pk_test_algo (int algo) +{ + /* Show only one "RSA" string. If RSA_E or RSA_S is available RSA + is also available. */ + if (algo == PUBKEY_ALGO_RSA_E + || algo == PUBKEY_ALGO_RSA_S) + return GPG_ERR_DIGEST_ALGO; + + return openpgp_pk_test_algo (algo); +} + +static const char * +build_list_pk_algo_name (int algo) +{ + return openpgp_pk_algo_name (algo); +} + +static int +build_list_cipher_test_algo (int algo) +{ + return openpgp_cipher_test_algo (algo); +} + +static const char * +build_list_cipher_algo_name (int algo) +{ + return openpgp_cipher_algo_name (algo); +} + +static int +build_list_md_test_algo (int algo) +{ + /* By default we do not accept MD5 based signatures. To avoid + confusion we do not announce support for it either. */ + if (algo == DIGEST_ALGO_MD5) + return GPG_ERR_DIGEST_ALGO; + + return openpgp_md_test_algo (algo); +} + +static const char * +build_list_md_algo_name (int algo) +{ + return openpgp_md_algo_name (algo); +} + + +static const char * +my_strusage( int level ) +{ + static char *digests, *pubkeys, *ciphers, *zips, *ver_gcry; + const char *p; + + switch (level) + { + case 9: p = "GPL-3.0-or-later"; break; + case 11: p = "@GPG@ (@GNUPG@)"; + break; + case 13: p = VERSION; break; + case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break; + case 17: p = PRINTABLE_OS_NAME; break; + case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break; + + case 20: + if (!ver_gcry) + ver_gcry = make_libversion ("libgcrypt", gcry_check_version); + p = ver_gcry; + break; + +#ifdef IS_DEVELOPMENT_VERSION + case 25: + p="NOTE: THIS IS A DEVELOPMENT VERSION!"; + break; + case 26: + p="It is only intended for test purposes and should NOT be"; + break; + case 27: + p="used in a production environment or with production keys!"; + break; +#endif + + case 1: + case 40: p = + _("Usage: @GPG@ [options] [files] (-h for help)"); + break; + case 41: p = + _("Syntax: @GPG@ [options] [files]\n" + "Sign, check, encrypt or decrypt\n" + "Default operation depends on the input data\n"); + break; + + case 31: p = "\nHome: "; break; +#ifndef __riscos__ + case 32: p = gnupg_homedir (); break; +#else /* __riscos__ */ + case 32: p = make_filename(gnupg_homedir (), NULL); break; +#endif /* __riscos__ */ + case 33: p = _("\nSupported algorithms:\n"); break; + case 34: + if (!pubkeys) + pubkeys = build_list (_("Pubkey: "), 1, + build_list_pk_algo_name, + build_list_pk_test_algo ); + p = pubkeys; + break; + case 35: + if( !ciphers ) + ciphers = build_list(_("Cipher: "), 'S', + build_list_cipher_algo_name, + build_list_cipher_test_algo ); + p = ciphers; + break; + case 36: + if( !digests ) + digests = build_list(_("Hash: "), 'H', + build_list_md_algo_name, + build_list_md_test_algo ); + p = digests; + break; + case 37: + if( !zips ) + zips = build_list(_("Compression: "),'Z', + compress_algo_to_string, + check_compress_algo); + p = zips; + break; + + case 95: + p = "1"; /* <-- Enable globbing under Windows (see init.c) */ + break; + + default: p = NULL; + } + return p; +} + + +static char * +build_list (const char *text, char letter, + const char * (*mapf)(int), int (*chkf)(int)) +{ + membuf_t mb; + int indent; + int i, j, len; + const char *s; + char *string; + + if (maybe_setuid) + gcry_control (GCRYCTL_INIT_SECMEM, 0, 0); /* Drop setuid. */ + + indent = utf8_charcount (text, -1); + len = 0; + init_membuf (&mb, 512); + + for (i=0; i <= 110; i++ ) + { + if (!chkf (i) && (s = mapf (i))) + { + if (mb.len - len > 60) + { + put_membuf_str (&mb, ",\n"); + len = mb.len; + for (j=0; j < indent; j++) + put_membuf_str (&mb, " "); + } + else if (mb.len) + put_membuf_str (&mb, ", "); + else + put_membuf_str (&mb, text); + + put_membuf_str (&mb, s); + if (opt.verbose && letter) + { + char num[20]; + if (letter == 1) + snprintf (num, sizeof num, " (%d)", i); + else + snprintf (num, sizeof num, " (%c%d)", letter, i); + put_membuf_str (&mb, num); + } + } + } + if (mb.len) + put_membuf_str (&mb, "\n"); + put_membuf (&mb, "", 1); + + string = get_membuf (&mb, NULL); + return xrealloc (string, strlen (string)+1); +} + + +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); +} + + +static char * +make_username( const char *string ) +{ + char *p; + if( utf8_strings ) + p = xstrdup(string); + else + p = native_to_utf8( string ); + return p; +} + + +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", + gpg_strerror (err)); +} + + +/* Setup the debugging. With a LEVEL of NULL only the active debug + flags are propagated to the subsystems. With LEVEL set, a specific + set of debug flags is set; thus overriding all flags already + set. */ +static void +set_debug (const char *level) +{ + int numok = (level && digitp (level)); + int numlvl = numok? atoi (level) : 0; + + if (!level) + ; + else if (!strcmp (level, "none") || (numok && numlvl < 1)) + opt.debug = 0; + else if (!strcmp (level, "basic") || (numok && numlvl <= 2)) + opt.debug = DBG_MEMSTAT_VALUE; + else if (!strcmp (level, "advanced") || (numok && numlvl <= 5)) + opt.debug = DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE; + else if (!strcmp (level, "expert") || (numok && numlvl <= 8)) + opt.debug = (DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE + |DBG_CACHE_VALUE|DBG_LOOKUP|DBG_FILTER_VALUE|DBG_PACKET_VALUE); + else if (!strcmp (level, "guru") || numok) + { + opt.debug = ~0; + /* 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. */ + if (numok) + opt.debug &= ~(DBG_HASHING_VALUE); + } + else + { + log_error (_("invalid debug-level '%s' given\n"), level); + g10_exit (2); + } + + if ((opt.debug & DBG_MEMORY_VALUE)) + memory_debug_mode = 1; + if ((opt.debug & DBG_MEMSTAT_VALUE)) + memory_stat_debug_mode = 1; + if (DBG_MPI) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2); + if (DBG_CRYPTO) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1); + if ((opt.debug & DBG_IOBUF_VALUE)) + iobuf_debug_mode = 1; + gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); + + if (opt.debug) + parse_debug_flag (NULL, &opt.debug, debug_flags); + + /* Make sure that we are --verbose in debug mode. */ + if (opt.debug && !opt.verbose) + opt.verbose = 1; + if (opt.debug && opt.quiet) + opt.quiet = 0; +} + + +/* We set the screen dimensions for UI purposes. Do not allow screens + smaller than 80x24 for the sake of simplicity. */ +static void +set_screen_dimensions(void) +{ +#ifndef HAVE_W32_SYSTEM + char *str; + + str=getenv("COLUMNS"); + if(str) + opt.screen_columns=atoi(str); + + str=getenv("LINES"); + if(str) + opt.screen_lines=atoi(str); +#endif + + if(opt.screen_columns<80 || opt.screen_columns>255) + opt.screen_columns=80; + + if(opt.screen_lines<24 || opt.screen_lines>255) + opt.screen_lines=24; +} + + +/* Helper to open a file FNAME either for reading or writing to be + used with --status-file etc functions. Not generally useful but it + avoids the riscos specific functions and well some Windows people + might like it too. Prints an error message and returns -1 on + error. On success the file descriptor is returned. */ +static int +open_info_file (const char *fname, int for_write, int binary) +{ +#ifdef __riscos__ + return riscos_fdopenfile (fname, for_write); +#elif defined (ENABLE_SELINUX_HACKS) + /* We can't allow these even when testing for a secured filename + because files to be secured might not yet been secured. This is + similar to the option file but in that case it is unlikely that + sensitive information may be retrieved by means of error + messages. */ + (void)fname; + (void)for_write; + (void)binary; + return -1; +#else + int fd; + + if (binary) + binary = MY_O_BINARY; + +/* if (is_secured_filename (fname)) */ +/* { */ +/* fd = -1; */ +/* gpg_err_set_errno (EPERM); */ +/* } */ +/* else */ +/* { */ + do + { + if (for_write) + fd = gnupg_open (fname, O_CREAT | O_TRUNC | O_WRONLY | binary, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + else + fd = gnupg_open (fname, O_RDONLY | binary, 0); + } + while (fd == -1 && errno == EINTR); +/* } */ + if ( fd == -1) + log_error ( for_write? _("can't create '%s': %s\n") + : _("can't open '%s': %s\n"), fname, strerror(errno)); + + return fd; +#endif +} + +static void +set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ) +{ + enum cmd_and_opt_values cmd = *ret_cmd; + + if( !cmd || cmd == new_cmd ) + cmd = new_cmd; + else if( cmd == aSign && new_cmd == aEncr ) + cmd = aSignEncr; + else if( cmd == aEncr && new_cmd == aSign ) + cmd = aSignEncr; + else if( cmd == aSign && new_cmd == aSym ) + cmd = aSignSym; + else if( cmd == aSym && new_cmd == aSign ) + cmd = aSignSym; + else if( cmd == aSym && new_cmd == aEncr ) + cmd = aEncrSym; + else if( cmd == aEncr && new_cmd == aSym ) + cmd = aEncrSym; + else if (cmd == aSignEncr && new_cmd == aSym) + cmd = aSignEncrSym; + else if (cmd == aSignSym && new_cmd == aEncr) + cmd = aSignEncrSym; + else if (cmd == aEncrSym && new_cmd == aSign) + cmd = aSignEncrSym; + else if( ( cmd == aSign && new_cmd == aClearsign ) + || ( cmd == aClearsign && new_cmd == aSign ) ) + cmd = aClearsign; + else { + log_error(_("conflicting commands\n")); + g10_exit(2); + } + + *ret_cmd = cmd; +} + + +static void +add_group(char *string) +{ + char *name,*value; + struct groupitem *item; + + /* Break off the group name */ + name=strsep(&string,"="); + if(string==NULL) + { + log_error(_("no = sign found in group definition '%s'\n"),name); + return; + } + + trim_trailing_ws(name,strlen(name)); + + /* Does this group already exist? */ + for(item=opt.grouplist;item;item=item->next) + if(strcasecmp(item->name,name)==0) + break; + + if(!item) + { + item=xmalloc(sizeof(struct groupitem)); + item->name=name; + item->next=opt.grouplist; + item->values=NULL; + opt.grouplist=item; + } + + /* Break apart the values */ + while ((value= strsep(&string," \t"))) + { + if (*value) + add_to_strlist2(&item->values,value,utf8_strings); + } +} + + +static void +rm_group(char *name) +{ + struct groupitem *item,*last=NULL; + + trim_trailing_ws(name,strlen(name)); + + for(item=opt.grouplist;item;last=item,item=item->next) + { + if(strcasecmp(item->name,name)==0) + { + if(last) + last->next=item->next; + else + opt.grouplist=item->next; + + free_strlist(item->values); + xfree(item); + break; + } + } +} + + +/* We need to check three things. + + 0) The homedir. It must be x00, a directory, and owned by the + user. + + 1) The options/gpg.conf file. Okay unless it or its containing + directory is group or other writable or not owned by us. Disable + exec in this case. + + 2) Extensions. Same as #1. + + Returns true if the item is unsafe. */ +static int +check_permissions (const char *path, int item) +{ +#if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM) + static int homedir_cache=-1; + char *tmppath,*dir; + struct stat statbuf,dirbuf; + int homedir=0,ret=0,checkonly=0; + int perm=0,own=0,enc_dir_perm=0,enc_dir_own=0; + + if(opt.no_perm_warn) + return 0; + + log_assert(item==0 || item==1 || item==2); + + /* extensions may attach a path */ + if(item==2 && path[0]!=DIRSEP_C) + { + if(strchr(path,DIRSEP_C)) + tmppath=make_filename(path,NULL); + else + tmppath=make_filename(gnupg_libdir (),path,NULL); + } + else + tmppath=xstrdup(path); + + /* If the item is located in the homedir, but isn't the homedir, + don't continue if we already checked the homedir itself. This is + to avoid user confusion with an extra options file warning which + could be rectified if the homedir itself had proper + permissions. */ + if(item!=0 && homedir_cache>-1 + && !ascii_strncasecmp (gnupg_homedir (), tmppath, + strlen (gnupg_homedir ()))) + { + ret=homedir_cache; + goto end; + } + + /* It's okay if the file or directory doesn't exist */ + if (gnupg_stat (tmppath,&statbuf)) + { + ret=0; + goto end; + } + + /* Now check the enclosing directory. Theoretically, we could walk + this test up to the root directory /, but for the sake of sanity, + I'm stopping at one level down. */ + dir=make_dirname(tmppath); + + if (gnupg_stat (dir,&dirbuf) || !S_ISDIR (dirbuf.st_mode)) + { + /* Weird error */ + ret=1; + goto end; + } + + xfree(dir); + + /* Assume failure */ + ret=1; + + if(item==0) + { + /* The homedir must be x00, a directory, and owned by the user. */ + + if(S_ISDIR(statbuf.st_mode)) + { + if(statbuf.st_uid==getuid()) + { + if((statbuf.st_mode & (S_IRWXG|S_IRWXO))==0) + ret=0; + else + perm=1; + } + else + own=1; + + homedir_cache=ret; + } + } + else if(item==1 || item==2) + { + /* The options or extension file. Okay unless it or its + containing directory is group or other writable or not owned + by us or root. */ + + if(S_ISREG(statbuf.st_mode)) + { + if(statbuf.st_uid==getuid() || statbuf.st_uid==0) + { + if((statbuf.st_mode & (S_IWGRP|S_IWOTH))==0) + { + /* it's not writable, so make sure the enclosing + directory is also not writable */ + if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0) + { + if((dirbuf.st_mode & (S_IWGRP|S_IWOTH))==0) + ret=0; + else + enc_dir_perm=1; + } + else + enc_dir_own=1; + } + else + { + /* it's writable, so the enclosing directory had + better not let people get to it. */ + if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0) + { + if((dirbuf.st_mode & (S_IRWXG|S_IRWXO))==0) + ret=0; + else + perm=enc_dir_perm=1; /* unclear which one to fix! */ + } + else + enc_dir_own=1; + } + } + else + own=1; + } + } + else + BUG(); + + if(!checkonly) + { + if(own) + { + if(item==0) + log_info(_("WARNING: unsafe ownership on" + " homedir '%s'\n"),tmppath); + else if(item==1) + log_info(_("WARNING: unsafe ownership on" + " configuration file '%s'\n"),tmppath); + else + log_info(_("WARNING: unsafe ownership on" + " extension '%s'\n"),tmppath); + } + if(perm) + { + if(item==0) + log_info(_("WARNING: unsafe permissions on" + " homedir '%s'\n"),tmppath); + else if(item==1) + log_info(_("WARNING: unsafe permissions on" + " configuration file '%s'\n"),tmppath); + else + log_info(_("WARNING: unsafe permissions on" + " extension '%s'\n"),tmppath); + } + if(enc_dir_own) + { + if(item==0) + log_info(_("WARNING: unsafe enclosing directory ownership on" + " homedir '%s'\n"),tmppath); + else if(item==1) + log_info(_("WARNING: unsafe enclosing directory ownership on" + " configuration file '%s'\n"),tmppath); + else + log_info(_("WARNING: unsafe enclosing directory ownership on" + " extension '%s'\n"),tmppath); + } + if(enc_dir_perm) + { + if(item==0) + log_info(_("WARNING: unsafe enclosing directory permissions on" + " homedir '%s'\n"),tmppath); + else if(item==1) + log_info(_("WARNING: unsafe enclosing directory permissions on" + " configuration file '%s'\n"),tmppath); + else + log_info(_("WARNING: unsafe enclosing directory permissions on" + " extension '%s'\n"),tmppath); + } + } + + end: + xfree(tmppath); + + if(homedir) + homedir_cache=ret; + + return ret; + +#else /*!(HAVE_STAT && !HAVE_DOSISH_SYSTEM)*/ + (void)path; + (void)item; + return 0; +#endif /*!(HAVE_STAT && !HAVE_DOSISH_SYSTEM)*/ +} + + +/* Print the OpenPGP defined algo numbers. */ +static void +print_algo_numbers(int (*checker)(int)) +{ + int i,first=1; + + for(i=0;i<=110;i++) + { + if(!checker(i)) + { + if(first) + first=0; + else + es_printf (";"); + es_printf ("%d",i); + } + } +} + + +static void +print_algo_names(int (*checker)(int),const char *(*mapper)(int)) +{ + int i,first=1; + + for(i=0;i<=110;i++) + { + if(!checker(i)) + { + if(first) + first=0; + else + es_printf (";"); + es_printf ("%s",mapper(i)); + } + } +} + +/* In the future, we can do all sorts of interesting configuration + output here. For now, just give "group" as the Enigmail folks need + it, and pubkey, cipher, hash, and compress as they may be useful + for frontends. */ +static void +list_config(char *items) +{ + int show_all = !items; + char *name = NULL; + const char *s; + struct groupitem *giter; + int first, iter; + + if(!opt.with_colons) + return; + + while(show_all || (name=strsep(&items," "))) + { + int any=0; + + if(show_all || ascii_strcasecmp(name,"group")==0) + { + for (giter = opt.grouplist; giter; giter = giter->next) + { + strlist_t sl; + + es_fprintf (es_stdout, "cfg:group:"); + es_write_sanitized (es_stdout, giter->name, strlen(giter->name), + ":", NULL); + es_putc (':', es_stdout); + + for(sl=giter->values; sl; sl=sl->next) + { + es_write_sanitized (es_stdout, sl->d, strlen (sl->d), + ":;", NULL); + if(sl->next) + es_printf(";"); + } + + es_printf("\n"); + } + + any=1; + } + + if(show_all || ascii_strcasecmp(name,"version")==0) + { + es_printf("cfg:version:"); + es_write_sanitized (es_stdout, VERSION, strlen(VERSION), ":", NULL); + es_printf ("\n"); + any=1; + } + + if(show_all || ascii_strcasecmp(name,"pubkey")==0) + { + es_printf ("cfg:pubkey:"); + print_algo_numbers (build_list_pk_test_algo); + es_printf ("\n"); + any=1; + } + + if(show_all || ascii_strcasecmp(name,"pubkeyname")==0) + { + es_printf ("cfg:pubkeyname:"); + print_algo_names (build_list_pk_test_algo, + build_list_pk_algo_name); + es_printf ("\n"); + any=1; + } + + if(show_all || ascii_strcasecmp(name,"cipher")==0) + { + es_printf ("cfg:cipher:"); + print_algo_numbers (build_list_cipher_test_algo); + es_printf ("\n"); + any=1; + } + + if (show_all || !ascii_strcasecmp (name,"ciphername")) + { + es_printf ("cfg:ciphername:"); + print_algo_names (build_list_cipher_test_algo, + build_list_cipher_algo_name); + es_printf ("\n"); + any = 1; + } + + if(show_all + || ascii_strcasecmp(name,"digest")==0 + || ascii_strcasecmp(name,"hash")==0) + { + es_printf ("cfg:digest:"); + print_algo_numbers (build_list_md_test_algo); + es_printf ("\n"); + any=1; + } + + if (show_all + || !ascii_strcasecmp(name,"digestname") + || !ascii_strcasecmp(name,"hashname")) + { + es_printf ("cfg:digestname:"); + print_algo_names (build_list_md_test_algo, + build_list_md_algo_name); + es_printf ("\n"); + any=1; + } + + if(show_all || ascii_strcasecmp(name,"compress")==0) + { + es_printf ("cfg:compress:"); + print_algo_numbers(check_compress_algo); + es_printf ("\n"); + any=1; + } + + if(show_all || ascii_strcasecmp (name, "compressname") == 0) + { + es_printf ("cfg:compressname:"); + print_algo_names (check_compress_algo, + compress_algo_to_string); + es_printf ("\n"); + any=1; + } + + if (show_all || !ascii_strcasecmp(name,"ccid-reader-id")) + { + /* We ignore this for GnuPG 1.4 backward compatibility. */ + any=1; + } + + if (show_all || !ascii_strcasecmp (name,"curve")) + { + es_printf ("cfg:curve:"); + for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first=0) + es_printf ("%s%s", first?"":";", s); + es_printf ("\n"); + any=1; + } + + /* Curve OIDs are rarely useful and thus only printed if requested. */ + if (name && !ascii_strcasecmp (name,"curveoid")) + { + es_printf ("cfg:curveoid:"); + for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first = 0) + { + s = openpgp_curve_to_oid (s, NULL, NULL); + es_printf ("%s%s", first?"":";", s? s:"[?]"); + } + es_printf ("\n"); + any=1; + } + + if(show_all) + break; + + if(!any) + log_error(_("unknown configuration item '%s'\n"),name); + } +} + + +/* List options and default values in the GPG Conf format. This is a + new tool distributed with gnupg 1.9.x but we also want some limited + support in older gpg versions. The output is the name of the + configuration file and a list of options available for editing by + gpgconf. */ +static void +gpgconf_list (const char *configfile) +{ + char *configfile_esc = percent_escape (configfile, NULL); + + es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT); + es_printf ("compliance:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "gnupg"); + + /* The next one is an info only item and should match the macros at + the top of keygen.c */ + es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, + get_default_pubkey_algo ()); + /* This info only mode tells whether the we are running in de-vs + * compliance mode. This does not test all parameters but the basic + * conditions like a proper RNG and Libgcrypt. */ + es_printf ("compliance_de_vs:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, + opt.compliance==CO_DE_VS && gnupg_rng_is_compliant (CO_DE_VS)); + + xfree (configfile_esc); +} + + +static int +parse_subpacket_list(char *list) +{ + char *tok; + byte subpackets[128],i; + int count=0; + + if(!list) + { + /* No arguments means all subpackets */ + memset(subpackets+1,1,sizeof(subpackets)-1); + count=127; + } + else + { + memset(subpackets,0,sizeof(subpackets)); + + /* Merge with earlier copy */ + if(opt.show_subpackets) + { + byte *in; + + for(in=opt.show_subpackets;*in;in++) + { + if(*in>127 || *in<1) + BUG(); + + if(!subpackets[*in]) + count++; + subpackets[*in]=1; + } + } + + while((tok=strsep(&list," ,"))) + { + if(!*tok) + continue; + + i=atoi(tok); + if(i>127 || i<1) + return 0; + + if(!subpackets[i]) + count++; + subpackets[i]=1; + } + } + + xfree(opt.show_subpackets); + opt.show_subpackets=xmalloc(count+1); + opt.show_subpackets[count--]=0; + + for(i=1;i<128 && count>=0;i++) + if(subpackets[i]) + opt.show_subpackets[count--]=i; + + return 1; +} + + +static int +parse_list_options(char *str) +{ + char *subpackets=""; /* something that isn't NULL */ + struct parse_options lopts[]= + { + {"show-photos",LIST_SHOW_PHOTOS,NULL, + N_("display photo IDs during key listings")}, + {"show-usage",LIST_SHOW_USAGE,NULL, + N_("show key usage information during key listings")}, + {"show-policy-urls",LIST_SHOW_POLICY_URLS,NULL, + N_("show policy URLs during signature listings")}, + {"show-notations",LIST_SHOW_NOTATIONS,NULL, + N_("show all notations during signature listings")}, + {"show-std-notations",LIST_SHOW_STD_NOTATIONS,NULL, + N_("show IETF standard notations during signature listings")}, + {"show-standard-notations",LIST_SHOW_STD_NOTATIONS,NULL, + NULL}, + {"show-user-notations",LIST_SHOW_USER_NOTATIONS,NULL, + N_("show user-supplied notations during signature listings")}, + {"show-keyserver-urls",LIST_SHOW_KEYSERVER_URLS,NULL, + N_("show preferred keyserver URLs during signature listings")}, + {"show-uid-validity",LIST_SHOW_UID_VALIDITY,NULL, + N_("show user ID validity during key listings")}, + {"show-unusable-uids",LIST_SHOW_UNUSABLE_UIDS,NULL, + N_("show revoked and expired user IDs in key listings")}, + {"show-unusable-subkeys",LIST_SHOW_UNUSABLE_SUBKEYS,NULL, + N_("show revoked and expired subkeys in key listings")}, + {"show-keyring",LIST_SHOW_KEYRING,NULL, + N_("show the keyring name in key listings")}, + {"show-sig-expire",LIST_SHOW_SIG_EXPIRE,NULL, + N_("show expiration dates during signature listings")}, + {"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL, + NULL}, + {"show-only-fpr-mbox",LIST_SHOW_ONLY_FPR_MBOX, NULL, + NULL}, + {NULL,0,NULL,NULL} + }; + + /* C99 allows for non-constant initializers, but we'd like to + compile everywhere, so fill in the show-sig-subpackets argument + here. Note that if the parse_options array changes, we'll have + to change the subscript here. */ + lopts[13].value=&subpackets; + + if(parse_options(str,&opt.list_options,lopts,1)) + { + if(opt.list_options&LIST_SHOW_SIG_SUBPACKETS) + { + /* Unset so users can pass multiple lists in. */ + opt.list_options&=~LIST_SHOW_SIG_SUBPACKETS; + if(!parse_subpacket_list(subpackets)) + return 0; + } + else if(subpackets==NULL && opt.show_subpackets) + { + /* User did 'no-show-subpackets' */ + xfree(opt.show_subpackets); + opt.show_subpackets=NULL; + } + + return 1; + } + else + return 0; +} + + +/* Collapses argc/argv into a single string that must be freed */ +static char * +collapse_args(int argc,char *argv[]) +{ + char *str=NULL; + int i,first=1,len=0; + + for(i=0;i<argc;i++) + { + len+=strlen(argv[i])+2; + str=xrealloc(str,len); + if(first) + { + str[0]='\0'; + first=0; + } + else + strcat(str," "); + + strcat(str,argv[i]); + } + + return str; +} + + +#ifndef NO_TRUST_MODELS +static void +parse_trust_model(const char *model) +{ + if(ascii_strcasecmp(model,"pgp")==0) + opt.trust_model=TM_PGP; + else if(ascii_strcasecmp(model,"classic")==0) + opt.trust_model=TM_CLASSIC; + else if(ascii_strcasecmp(model,"always")==0) + opt.trust_model=TM_ALWAYS; + else if(ascii_strcasecmp(model,"direct")==0) + opt.trust_model=TM_DIRECT; +#ifdef USE_TOFU + else if(ascii_strcasecmp(model,"tofu")==0) + opt.trust_model=TM_TOFU; + else if(ascii_strcasecmp(model,"tofu+pgp")==0) + opt.trust_model=TM_TOFU_PGP; +#endif /*USE_TOFU*/ + else if(ascii_strcasecmp(model,"auto")==0) + opt.trust_model=TM_AUTO; + else + log_error("unknown trust model '%s'\n",model); +} +#endif /*NO_TRUST_MODELS*/ + + +static int +parse_tofu_policy (const char *policystr) +{ +#ifdef USE_TOFU + struct { const char *keyword; int policy; } list[] = { + { "auto", TOFU_POLICY_AUTO }, + { "good", TOFU_POLICY_GOOD }, + { "unknown", TOFU_POLICY_UNKNOWN }, + { "bad", TOFU_POLICY_BAD }, + { "ask", TOFU_POLICY_ASK } + }; + int i; + + if (!ascii_strcasecmp (policystr, "help")) + { + log_info (_("valid values for option '%s':\n"), "--tofu-policy"); + 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 (policystr, list[i].keyword)) + return list[i].policy; +#endif /*USE_TOFU*/ + + log_error (_("unknown TOFU policy '%s'\n"), policystr); + if (!opt.quiet) + log_info (_("(use \"help\" to list choices)\n")); + g10_exit (1); +} + + +static struct gnupg_compliance_option compliance_options[] = + { + { "gnupg", oGnuPG }, + { "openpgp", oOpenPGP }, + { "rfc4880bis", oRFC4880bis }, + { "rfc4880", oRFC4880 }, + { "rfc2440", oRFC2440 }, + { "pgp6", oPGP6 }, + { "pgp7", oPGP7 }, + { "pgp8", oPGP8 }, + { "de-vs", oDE_VS } + }; + + +/* 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 +set_compliance_option (enum cmd_and_opt_values option) +{ + switch (option) + { + case oRFC4880bis: + opt.flags.rfc4880bis = 1; + /* fall through. */ + case oOpenPGP: + case oRFC4880: + /* This is effectively the same as RFC2440, but with + "--enable-dsa2 --no-rfc2440-text --escape-from-lines + --require-cross-certification". */ + opt.compliance = CO_RFC4880; + opt.flags.dsa2 = 1; + opt.flags.require_cross_cert = 1; + opt.rfc2440_text = 0; + opt.allow_non_selfsigned_uid = 1; + opt.allow_freeform_uid = 1; + opt.escape_from = 1; + opt.not_dash_escaped = 0; + opt.def_cipher_algo = 0; + opt.def_digest_algo = 0; + opt.cert_digest_algo = 0; + opt.compress_algo = -1; + opt.s2k_mode = 3; /* iterated+salted */ + opt.s2k_digest_algo = DIGEST_ALGO_SHA1; + opt.s2k_cipher_algo = CIPHER_ALGO_3DES; + break; + case oRFC2440: + opt.compliance = CO_RFC2440; + opt.flags.dsa2 = 0; + opt.rfc2440_text = 1; + opt.allow_non_selfsigned_uid = 1; + opt.allow_freeform_uid = 1; + opt.escape_from = 0; + opt.not_dash_escaped = 0; + opt.def_cipher_algo = 0; + opt.def_digest_algo = 0; + opt.cert_digest_algo = 0; + opt.compress_algo = -1; + opt.s2k_mode = 3; /* iterated+salted */ + opt.s2k_digest_algo = DIGEST_ALGO_SHA1; + opt.s2k_cipher_algo = CIPHER_ALGO_3DES; + break; + case oPGP6: opt.compliance = CO_PGP6; break; + case oPGP7: opt.compliance = CO_PGP7; break; + case oPGP8: opt.compliance = CO_PGP8; break; + case oGnuPG: opt.compliance = CO_GNUPG; break; + + case oDE_VS: + set_compliance_option (oOpenPGP); + opt.compliance = CO_DE_VS; + /* We divert here from the backward compatible rfc4880 algos. */ + opt.s2k_digest_algo = DIGEST_ALGO_SHA256; + opt.s2k_cipher_algo = CIPHER_ALGO_AES256; + break; + + default: + BUG (); + } +} + + +static void +gen_key_forbidden (void) +{ + write_status_failure ("gen-key", gpg_error (GPG_ERR_NOT_ENABLED)); + log_error (_("This command is not allowed while in %s mode.\n"), + "forbid-gen-key"); +} + + +/* This function called to initialized a new control object. It is + assumed that this object has been zeroed out before calling this + function. */ +static void +gpg_init_default_ctrl (ctrl_t ctrl) +{ + ctrl->magic = SERVER_CONTROL_MAGIC; +} + + +/* This function is called to deinitialize a control object. It is + not deallocated. */ +static void +gpg_deinit_default_ctrl (ctrl_t ctrl) +{ +#ifdef USE_TOFU + tofu_closedbs (ctrl); +#endif + gpg_dirmngr_deinit_session_data (ctrl); + + keydb_release (ctrl->cached_getkey_kdb); +} + + +int +main (int argc, char **argv) +{ + ARGPARSE_ARGS pargs; + IOBUF a; + int rc=0; + int orig_argc; + char **orig_argv; + const char *fname; + char *username; + int may_coredump; + strlist_t sl; + strlist_t remusr = NULL; + strlist_t locusr = NULL; + strlist_t nrings = NULL; + armor_filter_context_t *afx = NULL; + int detached_sig = 0; + char *last_configname = NULL; + const char *configname = NULL; /* NULL or points to last_configname. + * NULL also indicates that we are + * processing options from the cmdline. */ + int debug_argparser = 0; + int default_keyring = 1; + int greeting = 0; + int nogreeting = 0; + char *logfile = NULL; + int use_random_seed = 1; + enum cmd_and_opt_values cmd = 0; + const char *debug_level = NULL; +#ifndef NO_TRUST_MODELS + const char *trustdb_name = NULL; +#endif /*!NO_TRUST_MODELS*/ + char *def_cipher_string = NULL; + char *def_digest_string = NULL; + char *compress_algo_string = NULL; + char *cert_digest_string = NULL; + char *s2k_cipher_string = NULL; + char *s2k_digest_string = NULL; + char *pers_cipher_list = NULL; + char *pers_digest_list = NULL; + char *pers_compress_list = NULL; + int eyes_only=0; + int multifile=0; + int pwfd = -1; + 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; + ctrl_t ctrl; + + static int print_dane_records; + static int print_pka_records; + + +#ifdef __riscos__ + opt.lock_once = 1; +#endif /* __riscos__ */ + + /* 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. */ + early_system_init (); + gnupg_reopen_std (GPG_NAME); + trap_unaligned (); + gnupg_rl_initialize (); + set_strusage (my_strusage); + gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); + log_set_prefix (GPG_NAME, GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY); + + /* Make sure that our subsystems are ready. */ + i18n_init(); + init_common_subsystems (&argc, &argv); + + /* Use our own logging handler for Libcgrypt. */ + setup_libgcrypt_logging (); + + /* Put random number into secure memory */ + gcry_control (GCRYCTL_USE_SECURE_RNDPOOL); + + may_coredump = disable_core_dumps(); + + gnupg_init_signals (0, emergency_cleanup); + + 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) + log_fatal ("error allocating session environment block: %s\n", + strerror (errno)); + + opt.command_fd = -1; /* no command fd */ + opt.compress_level = -1; /* defaults to standard compress level */ + opt.bz2_compress_level = -1; /* defaults to standard compress level */ + /* note: if you change these lines, look at oOpenPGP */ + opt.def_cipher_algo = 0; + opt.def_digest_algo = 0; + opt.cert_digest_algo = 0; + opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */ + opt.s2k_mode = 3; /* iterated+salted */ + opt.s2k_count = 0; /* Auto-calibrate when needed. */ + opt.s2k_cipher_algo = DEFAULT_CIPHER_ALGO; + opt.completes_needed = 1; + opt.marginals_needed = 3; + opt.max_cert_depth = 5; + opt.escape_from = 1; + opt.flags.require_cross_cert = 1; + opt.import_options = IMPORT_REPAIR_KEYS; + opt.export_options = EXPORT_ATTRIBUTES; + opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS + | IMPORT_REPAIR_PKS_SUBKEY_BUG + | IMPORT_SELF_SIGS_ONLY + | IMPORT_CLEAN); + opt.keyserver_options.export_options = EXPORT_ATTRIBUTES; + opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD; + opt.verify_options = (LIST_SHOW_UID_VALIDITY + | VERIFY_SHOW_POLICY_URLS + | VERIFY_SHOW_STD_NOTATIONS + | VERIFY_SHOW_KEYSERVER_URLS); + opt.list_options = (LIST_SHOW_UID_VALIDITY + | LIST_SHOW_USAGE); +#ifdef NO_TRUST_MODELS + opt.trust_model = TM_ALWAYS; +#else + opt.trust_model = TM_AUTO; +#endif + opt.tofu_default_policy = TOFU_POLICY_AUTO; + opt.mangle_dos_filenames = 0; + opt.min_cert_level = 2; + set_screen_dimensions (); + opt.keyid_format = KF_NONE; + opt.def_sig_expire = "0"; + opt.def_cert_expire = "0"; + gnupg_set_homedir (NULL); + opt.passphrase_repeat = 1; + opt.emit_version = 0; + opt.weak_digests = NULL; + + /* Check special options given on the command line. */ + orig_argc = argc; + orig_argv = argv; + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION); + while (gnupg_argparse (NULL, &pargs, opts)) + { + switch (pargs.r_opt) + { + case oDebug: + case oDebugAll: + debug_argparser++; + break; + + case oDebugIOLBF: + es_setvbuf (es_stdout, NULL, _IOLBF, 0); + break; + + case oNoOptions: + /* Set here here because the homedir would otherwise be + * created before main option parsing starts. */ + opt.no_homedir_creation = 1; + break; + + case oHomedir: + gnupg_set_homedir (pargs.r.ret_str); + break; + + case oNoPermissionWarn: + opt.no_perm_warn = 1; + break; + } + } + /* Reset the flags. */ + pargs.flags &= ~(ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION); + +#ifdef HAVE_DOSISH_SYSTEM + if ( strchr (gnupg_homedir (), '\\') ) { + char *d, *buf = xmalloc (strlen (gnupg_homedir ())+1); + const char *s; + for (d=buf, s = gnupg_homedir (); *s; s++) + { + *d++ = *s == '\\'? '/': *s; +#ifdef HAVE_W32_SYSTEM + if (s[1] && IsDBCSLeadByte (*s)) + *d++ = *++s; +#endif + } + *d = 0; + gnupg_set_homedir (buf); + } +#endif + + /* Initialize the secure memory. */ + if (!gcry_control (GCRYCTL_INIT_SECMEM, SECMEM_BUFFER_SIZE, 0)) + got_secmem = 1; +#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) + /* There should be no way to get to this spot while still carrying + setuid privs. Just in case, bomb out if we are. */ + if ( getuid () != geteuid () ) + BUG (); +#endif + maybe_setuid = 0; + + /* Okay, we are now working under our real uid */ + + /* malloc hooks go here ... */ + malloc_hooks.malloc = gcry_malloc; + malloc_hooks.realloc = gcry_realloc; + malloc_hooks.free = gcry_free; + assuan_set_malloc_hooks (&malloc_hooks); + 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 (DEFAULT_AKL_LIST); + + argc = orig_argc; + argv = orig_argv; + pargs.argc = &argc; + pargs.argv = &argv; + /* We are re-using the struct, thus the reset flag. We OR the + * flags so that the internal intialized flag won't be cleared. */ + pargs.flags |= (ARGPARSE_FLAG_RESET + | ARGPARSE_FLAG_KEEP + | ARGPARSE_FLAG_SYS + | ARGPARSE_FLAG_USER + | ARGPARSE_FLAG_USERVERS); + + /* By this point we have a homedir, and cannot change it. */ + check_permissions (gnupg_homedir (), 0); + + /* The configuraton directories for use by gpgrt_argparser. */ + gnupg_set_confdir (GNUPG_CONFDIR_SYS, gnupg_sysconfdir ()); + gnupg_set_confdir (GNUPG_CONFDIR_USER, gnupg_homedir ()); + + while (gnupg_argparser (&pargs, opts, GPG_NAME EXTSEP_S "conf")) + { + switch (pargs.r_opt) + { + case ARGPARSE_CONFFILE: + if (debug_argparser) + log_info (_("reading options from '%s'\n"), + pargs.r_type? pargs.r.ret_str: "[cmdline]"); + if (pargs.r_type) + { + xfree (last_configname); + last_configname = xstrdup (pargs.r.ret_str); + configname = last_configname; + if (is_secured_filename (configname)) + { + pargs.r_opt = ARGPARSE_PERMISSION_ERROR; + pargs.err = ARGPARSE_PRINT_ERROR; + } + else if (strncmp (configname, gnupg_sysconfdir (), + strlen (gnupg_sysconfdir ()))) + { + /* This is not the global config file and thus we + * need to check the permissions: If the file is + * unsafe, then disable any external programs for + * keyserver calls or photo IDs. Since the + * external program to call is set in the options + * file, a unsafe options file can lead to an + * arbitrary program being run. */ + if (check_permissions (configname, 1)) + opt.exec_disable=1; + } + } + else + configname = NULL; + break; + + /* case oOptions: + * case oNoOptions: + * We will never see these options here because + * gpgrt_argparse handles them for us. + */ + + case aListConfig: + case aListGcryptConfig: + case aGPGConfList: + case aGPGConfTest: + set_cmd (&cmd, pargs.r_opt); + /* Do not register a keyring for these commands. */ + default_keyring = -1; + break; + + case aCheckKeys: + case aListPackets: + case aImport: + case aFastImport: + case aSendKeys: + case aRecvKeys: + case aSearchKeys: + case aRefreshKeys: + case aFetchKeys: + case aExport: +#ifdef ENABLE_CARD_SUPPORT + case aCardStatus: + case aCardEdit: + case aChangePIN: +#endif /* ENABLE_CARD_SUPPORT*/ + case aListKeys: + case aLocateKeys: + case aLocateExtKeys: + case aListSigs: + case aExportSecret: + case aExportSecretSub: + case aExportSshKey: + case aSym: + case aClearsign: + case aGenRevoke: + case aDesigRevoke: + case aPrimegen: + case aGenRandom: + case aPrintMD: + case aPrintMDs: + case aListTrustDB: + case aCheckTrustDB: + case aUpdateTrustDB: + case aFixTrustDB: + case aListTrustPath: + case aDeArmor: + case aEnArmor: + case aSign: + case aQuickSignKey: + case aQuickLSignKey: + case aQuickRevSig: + case aSignKey: + case aLSignKey: + case aStore: + case aQuickKeygen: + case aQuickAddUid: + case aQuickAddKey: + case aQuickRevUid: + case aQuickSetExpire: + case aQuickSetPrimaryUid: + case aExportOwnerTrust: + case aImportOwnerTrust: + case aRebuildKeydbCaches: + set_cmd (&cmd, pargs.r_opt); + break; + + case aKeygen: + case aFullKeygen: + case aEditKey: + case aDeleteSecretKeys: + case aDeleteSecretAndPublicKeys: + case aDeleteKeys: + case aPasswd: + set_cmd (&cmd, pargs.r_opt); + greeting=1; + break; + + case aShowKeys: + set_cmd (&cmd, pargs.r_opt); + opt.import_options |= IMPORT_SHOW; + opt.import_options |= IMPORT_DRY_RUN; + opt.import_options &= ~IMPORT_REPAIR_KEYS; + opt.list_options |= LIST_SHOW_UNUSABLE_UIDS; + opt.list_options |= LIST_SHOW_UNUSABLE_SUBKEYS; + opt.list_options |= LIST_SHOW_NOTATIONS; + opt.list_options |= LIST_SHOW_POLICY_URLS; + break; + + case aDetachedSign: detached_sig = 1; set_cmd( &cmd, aSign ); break; + + case aDecryptFiles: multifile=1; /* fall through */ + case aDecrypt: set_cmd( &cmd, aDecrypt); break; + + case aEncrFiles: multifile=1; /* fall through */ + case aEncr: set_cmd( &cmd, aEncr); break; + + case aVerifyFiles: multifile=1; /* fall through */ + case aVerify: set_cmd( &cmd, aVerify); break; + + case aServer: + set_cmd (&cmd, pargs.r_opt); + opt.batch = 1; + break; + + case aTOFUPolicy: + set_cmd (&cmd, pargs.r_opt); + break; + + case oArmor: opt.armor = 1; opt.no_armor=0; break; + case oOutput: opt.outfile = pargs.r.ret_str; break; + + case oMaxOutput: opt.max_output = pargs.r.ret_ulong; break; + + case oInputSizeHint: + opt.input_size_hint = string_to_u64 (pargs.r.ret_str); + break; + + case oQuiet: opt.quiet = 1; break; + case oNoTTY: tty_no_terminal(1); break; + case oDryRun: opt.dry_run = 1; break; + case oInteractive: opt.interactive = 1; break; + case oVerbose: + opt.verbose++; + gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); + opt.list_options|=LIST_SHOW_UNUSABLE_UIDS; + opt.list_options|=LIST_SHOW_UNUSABLE_SUBKEYS; + break; + + case oBatch: + opt.batch = 1; + nogreeting = 1; + break; + + case oUseAgent: /* Dummy. */ + break; + + case oNoUseAgent: + obsolete_option (configname, pargs.lineno, "no-use-agent"); + break; + case oGpgAgentInfo: + obsolete_option (configname, pargs.lineno, "gpg-agent-info"); + break; + case oReaderPort: + obsolete_scdaemon_option (configname, pargs.lineno, "reader-port"); + break; + case octapiDriver: + obsolete_scdaemon_option (configname, pargs.lineno, "ctapi-driver"); + break; + case opcscDriver: + obsolete_scdaemon_option (configname, pargs.lineno, "pcsc-driver"); + break; + case oDisableCCID: + obsolete_scdaemon_option (configname, pargs.lineno, "disable-ccid"); + break; + case oHonorHttpProxy: + obsolete_option (configname, pargs.lineno, "honor-http-proxy"); + break; + + case oAnswerYes: opt.answer_yes = 1; break; + case oAnswerNo: opt.answer_no = 1; break; + + case oForceSignKey: opt.flags.force_sign_key = 1; break; + + case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break; + case oPrimaryKeyring: + sl = append_to_strlist (&nrings, pargs.r.ret_str); + sl->flags = KEYDB_RESOURCE_FLAG_PRIMARY; + break; + case oShowKeyring: + deprecated_warning(configname,pargs.lineno,"--show-keyring", + "--list-options ","show-keyring"); + opt.list_options|=LIST_SHOW_KEYRING; + break; + + case oDebug: + if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags)) + { + pargs.r_opt = ARGPARSE_INVALID_ARG; + pargs.err = ARGPARSE_PRINT_ERROR; + } + break; + + case oDebugAll: opt.debug = ~0; break; + case oDebugLevel: debug_level = pargs.r.ret_str; break; + + case oDebugIOLBF: break; /* Already set in pre-parse step. */ + + case oStatusFD: + set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) ); + break; + case oStatusFile: + set_status_fd ( open_info_file (pargs.r.ret_str, 1, 0) ); + break; + case oAttributeFD: + set_attrib_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) ); + break; + case oAttributeFile: + set_attrib_fd ( open_info_file (pargs.r.ret_str, 1, 1) ); + break; + case oLoggerFD: + log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1)); + break; + case oLoggerFile: + logfile = pargs.r.ret_str; + break; + + case oWithFingerprint: + opt.with_fingerprint = 1; + opt.fingerprint++; + break; + case oWithSubkeyFingerprint: + opt.with_subkey_fingerprint = 1; + break; + case oWithICAOSpelling: + opt.with_icao_spelling = 1; + break; + case oFingerprint: + opt.fingerprint++; + fpr_maybe_cmd = 1; + break; + + case oWithKeygrip: + opt.with_keygrip = 1; + break; + + case oWithSecret: + opt.with_secret = 1; + break; + + case oWithWKDHash: + opt.with_wkd_hash = 1; + break; + + case oWithKeyOrigin: + opt.with_key_origin = 1; + break; + + case oSecretKeyring: + obsolete_option (configname, pargs.lineno, "secret-keyring"); + break; + + case oNoArmor: opt.no_armor=1; opt.armor=0; break; + + case oNoDefKeyring: + if (default_keyring > 0) + default_keyring = 0; + break; + case oNoKeyring: + default_keyring = -1; + break; + + case oNoGreeting: nogreeting = 1; break; + case oNoVerbose: + opt.verbose = 0; + gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); + opt.list_sigs=0; + break; + case oQuickRandom: + gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); + break; + case oEmitVersion: opt.emit_version++; break; + case oNoEmitVersion: opt.emit_version=0; break; + case oCompletesNeeded: opt.completes_needed = pargs.r.ret_int; break; + case oMarginalsNeeded: opt.marginals_needed = pargs.r.ret_int; break; + case oMaxCertDepth: opt.max_cert_depth = pargs.r.ret_int; break; + +#ifndef NO_TRUST_MODELS + case oTrustDBName: trustdb_name = pargs.r.ret_str; break; + +#endif /*!NO_TRUST_MODELS*/ + case oDefaultKey: + sl = add_to_strlist (&opt.def_secret_key, pargs.r.ret_str); + sl->flags = (pargs.r_opt << PK_LIST_SHIFT); + if (configname) + sl->flags |= PK_LIST_CONFIG; + break; + case oDefRecipient: + if( *pargs.r.ret_str ) + { + xfree (opt.def_recipient); + opt.def_recipient = make_username(pargs.r.ret_str); + } + break; + case oDefRecipientSelf: + xfree(opt.def_recipient); opt.def_recipient = NULL; + opt.def_recipient_self = 1; + break; + case oNoDefRecipient: + xfree(opt.def_recipient); opt.def_recipient = NULL; + opt.def_recipient_self = 0; + break; + case oHomedir: break; + case oNoBatch: opt.batch = 0; break; + + case oWithTofuInfo: opt.with_tofu_info = 1; break; + + case oWithKeyData: opt.with_key_data=1; /*FALLTHRU*/ + case oWithColons: opt.with_colons=':'; break; + + case oWithSigCheck: opt.check_sigs = 1; /*FALLTHRU*/ + case oWithSigList: opt.list_sigs = 1; break; + + case oSkipVerify: opt.skip_verify=1; break; + + case oSkipHiddenRecipients: opt.skip_hidden_recipients = 1; break; + case oNoSkipHiddenRecipients: opt.skip_hidden_recipients = 0; break; + + case aListSecretKeys: set_cmd( &cmd, aListSecretKeys); break; + +#ifndef NO_TRUST_MODELS + /* There are many programs (like mutt) that call gpg with + --always-trust so keep this option around for a long + time. */ + case oAlwaysTrust: opt.trust_model=TM_ALWAYS; break; + case oTrustModel: + parse_trust_model(pargs.r.ret_str); + break; +#endif /*!NO_TRUST_MODELS*/ + case oTOFUDefaultPolicy: + opt.tofu_default_policy = parse_tofu_policy (pargs.r.ret_str); + break; + case oTOFUDBFormat: + obsolete_option (configname, pargs.lineno, "tofu-db-format"); + break; + + case oForceOwnertrust: + log_info(_("Note: %s is not for normal use!\n"), + "--force-ownertrust"); + opt.force_ownertrust=string_to_trust_value(pargs.r.ret_str); + if(opt.force_ownertrust==-1) + { + log_error("invalid ownertrust '%s'\n",pargs.r.ret_str); + opt.force_ownertrust=0; + } + break; + + case oCompliance: + { + 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: + case oRFC4880: + case oRFC4880bis: + case oPGP6: + case oPGP7: + case oPGP8: + case oGnuPG: + set_compliance_option (pargs.r_opt); + break; + + case oMinRSALength: opt.min_rsa_length = pargs.r.ret_ulong; break; + + case oRFC2440Text: opt.rfc2440_text=1; break; + case oNoRFC2440Text: opt.rfc2440_text=0; break; + + case oSetFilename: + if(utf8_strings) + opt.set_filename = pargs.r.ret_str; + else + opt.set_filename = native_to_utf8(pargs.r.ret_str); + break; + case oForYourEyesOnly: eyes_only = 1; break; + case oNoForYourEyesOnly: eyes_only = 0; break; + case oSetPolicyURL: + add_policy_url(pargs.r.ret_str,0); + add_policy_url(pargs.r.ret_str,1); + break; + case oSigPolicyURL: add_policy_url(pargs.r.ret_str,0); break; + case oCertPolicyURL: add_policy_url(pargs.r.ret_str,1); break; + case oShowPolicyURL: + deprecated_warning(configname,pargs.lineno,"--show-policy-url", + "--list-options ","show-policy-urls"); + deprecated_warning(configname,pargs.lineno,"--show-policy-url", + "--verify-options ","show-policy-urls"); + opt.list_options|=LIST_SHOW_POLICY_URLS; + opt.verify_options|=VERIFY_SHOW_POLICY_URLS; + break; + case oNoShowPolicyURL: + deprecated_warning(configname,pargs.lineno,"--no-show-policy-url", + "--list-options ","no-show-policy-urls"); + deprecated_warning(configname,pargs.lineno,"--no-show-policy-url", + "--verify-options ","no-show-policy-urls"); + opt.list_options&=~LIST_SHOW_POLICY_URLS; + opt.verify_options&=~VERIFY_SHOW_POLICY_URLS; + break; + case oSigKeyserverURL: add_keyserver_url(pargs.r.ret_str,0); break; + case oUseEmbeddedFilename: + opt.flags.use_embedded_filename=1; + break; + case oNoUseEmbeddedFilename: + opt.flags.use_embedded_filename=0; + break; + case oComment: + if(pargs.r.ret_str[0]) + append_to_strlist(&opt.comments,pargs.r.ret_str); + break; + case oDefaultComment: + deprecated_warning(configname,pargs.lineno, + "--default-comment","--no-comments",""); + /* fall through */ + case oNoComments: + free_strlist(opt.comments); + opt.comments=NULL; + break; + case oThrowKeyids: opt.throw_keyids = 1; break; + case oNoThrowKeyids: opt.throw_keyids = 0; break; + case oShowPhotos: + deprecated_warning(configname,pargs.lineno,"--show-photos", + "--list-options ","show-photos"); + deprecated_warning(configname,pargs.lineno,"--show-photos", + "--verify-options ","show-photos"); + opt.list_options|=LIST_SHOW_PHOTOS; + opt.verify_options|=VERIFY_SHOW_PHOTOS; + break; + case oNoShowPhotos: + deprecated_warning(configname,pargs.lineno,"--no-show-photos", + "--list-options ","no-show-photos"); + deprecated_warning(configname,pargs.lineno,"--no-show-photos", + "--verify-options ","no-show-photos"); + opt.list_options&=~LIST_SHOW_PHOTOS; + opt.verify_options&=~VERIFY_SHOW_PHOTOS; + break; + case oPhotoViewer: opt.photo_viewer = pargs.r.ret_str; break; + + case oDisableSignerUID: opt.flags.disable_signer_uid = 1; break; + case oIncludeKeyBlock: opt.flags.include_key_block = 1; break; + case oNoIncludeKeyBlock: opt.flags.include_key_block = 0; break; + + case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break; + case oS2KDigest: s2k_digest_string = xstrdup(pargs.r.ret_str); break; + case oS2KCipher: s2k_cipher_string = xstrdup(pargs.r.ret_str); break; + case oS2KCount: + if (pargs.r.ret_int) + opt.s2k_count = encode_s2k_iterations (pargs.r.ret_int); + else + opt.s2k_count = 0; /* Auto-calibrate when needed. */ + break; + + case oRecipient: + case oHiddenRecipient: + case oRecipientFile: + case oHiddenRecipientFile: + /* Store the recipient. Note that we also store the + * option as private data in the flags. This is achieved + * by shifting the option value to the left so to keep + * enough space for the flags. */ + sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); + sl->flags = (pargs.r_opt << PK_LIST_SHIFT); + if (configname) + sl->flags |= PK_LIST_CONFIG; + if (pargs.r_opt == oHiddenRecipient + || pargs.r_opt == oHiddenRecipientFile) + sl->flags |= PK_LIST_HIDDEN; + if (pargs.r_opt == oRecipientFile + || pargs.r_opt == oHiddenRecipientFile) + sl->flags |= PK_LIST_FROM_FILE; + any_explicit_recipient = 1; + break; + + case oEncryptTo: + case oHiddenEncryptTo: + /* Store an additional recipient. */ + sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); + sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO); + if (configname) + sl->flags |= PK_LIST_CONFIG; + if (pargs.r_opt == oHiddenEncryptTo) + sl->flags |= PK_LIST_HIDDEN; + break; + + case oNoEncryptTo: + opt.no_encrypt_to = 1; + break; + case oEncryptToDefaultKey: + opt.encrypt_to_default_key = configname ? 2 : 1; + break; + + case oTrySecretKey: + add_to_strlist2 (&opt.secret_keys_to_try, + pargs.r.ret_str, utf8_strings); + break; + + case oMimemode: opt.mimemode = opt.textmode = 1; break; + case oTextmodeShort: opt.textmode = 2; break; + case oTextmode: opt.textmode=1; break; + case oNoTextmode: opt.textmode=opt.mimemode=0; break; + + case oExpert: opt.expert = 1; break; + case oNoExpert: opt.expert = 0; break; + case oDefSigExpire: + if(*pargs.r.ret_str!='\0') + { + if(parse_expire_string(pargs.r.ret_str)==(u32)-1) + log_error(_("'%s' is not a valid signature expiration\n"), + pargs.r.ret_str); + else + opt.def_sig_expire=pargs.r.ret_str; + } + break; + case oAskSigExpire: opt.ask_sig_expire = 1; break; + case oNoAskSigExpire: opt.ask_sig_expire = 0; break; + case oDefCertExpire: + if(*pargs.r.ret_str!='\0') + { + if(parse_expire_string(pargs.r.ret_str)==(u32)-1) + log_error(_("'%s' is not a valid signature expiration\n"), + pargs.r.ret_str); + else + opt.def_cert_expire=pargs.r.ret_str; + } + break; + case oAskCertExpire: opt.ask_cert_expire = 1; break; + case oNoAskCertExpire: opt.ask_cert_expire = 0; break; + case oDefCertLevel: opt.def_cert_level=pargs.r.ret_int; break; + case oMinCertLevel: opt.min_cert_level=pargs.r.ret_int; break; + case oAskCertLevel: opt.ask_cert_level = 1; break; + case oNoAskCertLevel: opt.ask_cert_level = 0; break; + case oLocalUser: /* store the local users */ + sl = add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings ); + sl->flags = (pargs.r_opt << PK_LIST_SHIFT); + if (configname) + sl->flags |= PK_LIST_CONFIG; + break; + case oSender: + { + char *mbox = mailbox_from_userid (pargs.r.ret_str); + if (!mbox) + log_error (_("\"%s\" is not a proper mail address\n"), + pargs.r.ret_str); + else + { + add_to_strlist (&opt.sender_list, mbox); + xfree (mbox); + } + } + break; + case oCompress: + /* this is the -z command line option */ + opt.compress_level = opt.bz2_compress_level = pargs.r.ret_int; + break; + case oCompressLevel: opt.compress_level = pargs.r.ret_int; break; + case oBZ2CompressLevel: opt.bz2_compress_level = pargs.r.ret_int; break; + case oBZ2DecompressLowmem: opt.bz2_decompress_lowmem=1; break; + case oPassphrase: + set_passphrase_from_string (pargs.r_type ? pargs.r.ret_str : ""); + break; + case oPassphraseFD: + pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); + break; + case oPassphraseFile: + pwfd = open_info_file (pargs.r.ret_str, 0, 1); + break; + case oPassphraseRepeat: + opt.passphrase_repeat = pargs.r.ret_int; + 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; + + 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); + break; + case oCipherAlgo: + def_cipher_string = xstrdup(pargs.r.ret_str); + break; + case oDigestAlgo: + def_digest_string = xstrdup(pargs.r.ret_str); + break; + case oCompressAlgo: + /* If it is all digits, stick a Z in front of it for + later. This is for backwards compatibility with + versions that took the compress algorithm number. */ + { + char *pt=pargs.r.ret_str; + while(*pt) + { + if (!isascii (*pt) || !isdigit (*pt)) + break; + + pt++; + } + + if(*pt=='\0') + { + compress_algo_string=xmalloc(strlen(pargs.r.ret_str)+2); + strcpy(compress_algo_string,"Z"); + strcat(compress_algo_string,pargs.r.ret_str); + } + else + compress_algo_string = xstrdup(pargs.r.ret_str); + } + break; + case oCertDigestAlgo: + cert_digest_string = xstrdup(pargs.r.ret_str); + break; + + case oNoSecmemWarn: + gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); + break; + + case oRequireSecmem: require_secmem=1; break; + case oNoRequireSecmem: require_secmem=0; break; + case oNoPermissionWarn: opt.no_perm_warn=1; break; + case oDisplayCharset: + if( set_native_charset( pargs.r.ret_str ) ) + log_error(_("'%s' is not a valid character set\n"), + pargs.r.ret_str); + break; + case oNotDashEscaped: opt.not_dash_escaped = 1; break; + case oEscapeFrom: opt.escape_from = 1; break; + case oNoEscapeFrom: opt.escape_from = 0; break; + case oLockOnce: opt.lock_once = 1; break; + case oLockNever: + dotlock_disable (); + break; + case oLockMultiple: +#ifndef __riscos__ + opt.lock_once = 0; +#else /* __riscos__ */ + riscos_not_implemented("lock-multiple"); +#endif /* __riscos__ */ + break; + case oKeyServer: + { + keyserver_spec_t keyserver; + keyserver = parse_keyserver_uri (pargs.r.ret_str, 0); + if (!keyserver) + log_error (_("could not parse keyserver URL\n")); + else + { + /* We only support a single keyserver. Later ones + override earlier ones. (Since we parse the + config file first and then the command line + arguments, the command line takes + precedence.) */ + if (opt.keyserver) + free_keyserver_spec (opt.keyserver); + opt.keyserver = keyserver; + } + } + break; + case oKeyServerOptions: + if(!parse_keyserver_options(pargs.r.ret_str)) + { + if(configname) + log_error(_("%s:%d: invalid keyserver options\n"), + configname,pargs.lineno); + else + log_error(_("invalid keyserver options\n")); + } + break; + case oImportOptions: + if(!parse_import_options(pargs.r.ret_str,&opt.import_options,1)) + { + if(configname) + log_error(_("%s:%d: invalid import options\n"), + configname,pargs.lineno); + else + log_error(_("invalid import options\n")); + } + break; + case oImportFilter: + rc = parse_and_set_import_filter (pargs.r.ret_str); + if (rc) + log_error (_("invalid filter option: %s\n"), gpg_strerror (rc)); + break; + case oExportOptions: + if(!parse_export_options(pargs.r.ret_str,&opt.export_options,1)) + { + if(configname) + log_error(_("%s:%d: invalid export options\n"), + configname,pargs.lineno); + else + log_error(_("invalid export options\n")); + } + break; + case oExportFilter: + rc = parse_and_set_export_filter (pargs.r.ret_str); + if (rc) + log_error (_("invalid filter option: %s\n"), gpg_strerror (rc)); + break; + case oListOptions: + if(!parse_list_options(pargs.r.ret_str)) + { + if(configname) + log_error(_("%s:%d: invalid list options\n"), + configname,pargs.lineno); + else + log_error(_("invalid list options\n")); + } + break; + case oVerifyOptions: + { + struct parse_options vopts[]= + { + {"show-photos",VERIFY_SHOW_PHOTOS,NULL, + N_("display photo IDs during signature verification")}, + {"show-policy-urls",VERIFY_SHOW_POLICY_URLS,NULL, + N_("show policy URLs during signature verification")}, + {"show-notations",VERIFY_SHOW_NOTATIONS,NULL, + N_("show all notations during signature verification")}, + {"show-std-notations",VERIFY_SHOW_STD_NOTATIONS,NULL, + N_("show IETF standard notations during signature verification")}, + {"show-standard-notations",VERIFY_SHOW_STD_NOTATIONS,NULL, + NULL}, + {"show-user-notations",VERIFY_SHOW_USER_NOTATIONS,NULL, + N_("show user-supplied notations during signature verification")}, + {"show-keyserver-urls",VERIFY_SHOW_KEYSERVER_URLS,NULL, + N_("show preferred keyserver URLs during signature verification")}, + {"show-uid-validity",VERIFY_SHOW_UID_VALIDITY,NULL, + N_("show user ID validity during signature verification")}, + {"show-unusable-uids",VERIFY_SHOW_UNUSABLE_UIDS,NULL, + N_("show revoked and expired user IDs in signature verification")}, + {"show-primary-uid-only",VERIFY_SHOW_PRIMARY_UID_ONLY,NULL, + N_("show only the primary user ID in signature verification")}, + {"pka-lookups",VERIFY_PKA_LOOKUPS,NULL, + N_("validate signatures with PKA data")}, + {"pka-trust-increase",VERIFY_PKA_TRUST_INCREASE,NULL, + N_("elevate the trust of signatures with valid PKA data")}, + {NULL,0,NULL,NULL} + }; + + if(!parse_options(pargs.r.ret_str,&opt.verify_options,vopts,1)) + { + if(configname) + log_error(_("%s:%d: invalid verify options\n"), + configname,pargs.lineno); + else + log_error(_("invalid verify options\n")); + } + } + break; + case oTempDir: opt.temp_dir=pargs.r.ret_str; break; + case oExecPath: + if(set_exec_path(pargs.r.ret_str)) + log_error(_("unable to set exec-path to %s\n"),pargs.r.ret_str); + else + opt.exec_path_set=1; + break; + case oSetNotation: + add_notation_data( pargs.r.ret_str, 0 ); + add_notation_data( pargs.r.ret_str, 1 ); + break; + case oSigNotation: add_notation_data( pargs.r.ret_str, 0 ); break; + case oCertNotation: add_notation_data( pargs.r.ret_str, 1 ); break; + case oKnownNotation: register_known_notation (pargs.r.ret_str); break; + case oShowNotation: + deprecated_warning(configname,pargs.lineno,"--show-notation", + "--list-options ","show-notations"); + deprecated_warning(configname,pargs.lineno,"--show-notation", + "--verify-options ","show-notations"); + opt.list_options|=LIST_SHOW_NOTATIONS; + opt.verify_options|=VERIFY_SHOW_NOTATIONS; + break; + case oNoShowNotation: + deprecated_warning(configname,pargs.lineno,"--no-show-notation", + "--list-options ","no-show-notations"); + deprecated_warning(configname,pargs.lineno,"--no-show-notation", + "--verify-options ","no-show-notations"); + opt.list_options&=~LIST_SHOW_NOTATIONS; + opt.verify_options&=~VERIFY_SHOW_NOTATIONS; + break; + case oUtf8Strings: utf8_strings = 1; break; + case oNoUtf8Strings: +#ifdef HAVE_W32_SYSTEM + utf8_strings = 0; +#endif + break; + case oDisableCipherAlgo: + { + int algo = string_to_cipher_algo (pargs.r.ret_str); + gcry_cipher_ctl (NULL, GCRYCTL_DISABLE_ALGO, &algo, sizeof algo); + } + break; + case oDisablePubkeyAlgo: + { + int algo = gcry_pk_map_name (pargs.r.ret_str); + gcry_pk_ctl (GCRYCTL_DISABLE_ALGO, &algo, sizeof algo); + } + break; + case oNoSigCache: opt.no_sig_cache = 1; break; + case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break; + case oNoAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid=0; break; + case oAllowFreeformUID: opt.allow_freeform_uid = 1; break; + case oNoAllowFreeformUID: opt.allow_freeform_uid = 0; break; + case oNoLiteral: opt.no_literal = 1; break; + case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break; + case oFastListMode: opt.fast_list_mode = 1; break; + case oFixedListMode: /* Dummy */ break; + case oLegacyListMode: opt.legacy_list_mode = 1; break; + case oPrintPKARecords: print_pka_records = 1; break; + case oPrintDANERecords: print_dane_records = 1; break; + case oListOnly: opt.list_only=1; break; + case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break; + case oIgnoreValidFrom: opt.ignore_valid_from = 1; break; + case oIgnoreCrcError: opt.ignore_crc_error = 1; break; + case oIgnoreMDCError: opt.ignore_mdc_error = 1; break; + case oNoRandomSeedFile: use_random_seed = 0; break; + + case oAutoKeyImport: opt.flags.auto_key_import = 1; break; + case oNoAutoKeyImport: opt.flags.auto_key_import = 0; break; + + case oAutoKeyRetrieve: + opt.keyserver_options.options |= KEYSERVER_AUTO_KEY_RETRIEVE; + break; + case oNoAutoKeyRetrieve: + 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; + break; + case oOverrideSessionKeyFD: + ovrseskeyfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); + break; + case oMergeOnly: + deprecated_warning(configname,pargs.lineno,"--merge-only", + "--import-options ","merge-only"); + opt.import_options|=IMPORT_MERGE_ONLY; + break; + case oAllowSecretKeyImport: /* obsolete */ break; + case oTryAllSecrets: opt.try_all_secrets = 1; break; + case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break; + + case oEnableSpecialFilenames: + enable_special_filenames (); + break; + + case oNoExpensiveTrustChecks: opt.no_expensive_trust_checks=1; break; + case oAutoCheckTrustDB: opt.no_auto_check_trustdb=0; break; + case oNoAutoCheckTrustDB: opt.no_auto_check_trustdb=1; break; + case oPreservePermissions: opt.preserve_permissions=1; break; + case oDefaultPreferenceList: + opt.def_preference_list = pargs.r.ret_str; + break; + case oDefaultKeyserverURL: + { + keyserver_spec_t keyserver; + keyserver = parse_keyserver_uri (pargs.r.ret_str,1 ); + if (!keyserver) + log_error (_("could not parse keyserver URL\n")); + else + free_keyserver_spec (keyserver); + + opt.def_keyserver_url = pargs.r.ret_str; + } + break; + case oPersonalCipherPreferences: + pers_cipher_list=pargs.r.ret_str; + break; + case oPersonalDigestPreferences: + pers_digest_list=pargs.r.ret_str; + break; + case oPersonalCompressPreferences: + pers_compress_list=pargs.r.ret_str; + 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; + case oUnwrap: + opt.unwrap_encryption = 1; + break; + case oOnlySignTextIDs: + opt.only_sign_text_ids = 1; + break; + + case oDisplay: + set_opt_session_env ("DISPLAY", pargs.r.ret_str); + break; + case oTTYname: + set_opt_session_env ("GPG_TTY", pargs.r.ret_str); + break; + case oTTYtype: + set_opt_session_env ("TERM", pargs.r.ret_str); + break; + case oXauthority: + set_opt_session_env ("XAUTHORITY", pargs.r.ret_str); + break; + + case oLCctype: opt.lc_ctype = pargs.r.ret_str; break; + case oLCmessages: opt.lc_messages = pargs.r.ret_str; break; + + case oGroup: add_group(pargs.r.ret_str); break; + case oUnGroup: rm_group(pargs.r.ret_str); break; + case oNoGroups: + while(opt.grouplist) + { + struct groupitem *iter=opt.grouplist; + free_strlist(iter->values); + opt.grouplist=opt.grouplist->next; + xfree(iter); + } + break; + + case oMangleDosFilenames: opt.mangle_dos_filenames = 1; break; + case oNoMangleDosFilenames: opt.mangle_dos_filenames = 0; break; + case oEnableProgressFilter: opt.enable_progress_filter = 1; break; + case oMultifile: multifile=1; break; + case oKeyidFormat: + if(ascii_strcasecmp(pargs.r.ret_str,"short")==0) + opt.keyid_format=KF_SHORT; + else if(ascii_strcasecmp(pargs.r.ret_str,"long")==0) + opt.keyid_format=KF_LONG; + else if(ascii_strcasecmp(pargs.r.ret_str,"0xshort")==0) + opt.keyid_format=KF_0xSHORT; + else if(ascii_strcasecmp(pargs.r.ret_str,"0xlong")==0) + opt.keyid_format=KF_0xLONG; + else if(ascii_strcasecmp(pargs.r.ret_str,"none")==0) + opt.keyid_format = KF_NONE; + else + log_error("unknown keyid-format '%s'\n",pargs.r.ret_str); + break; + + case oExitOnStatusWriteError: + opt.exit_on_status_write_error = 1; + break; + + case oLimitCardInsertTries: + opt.limit_card_insert_tries = pargs.r.ret_int; + break; + + case oRequireCrossCert: opt.flags.require_cross_cert=1; break; + case oNoRequireCrossCert: opt.flags.require_cross_cert=0; break; + + case oAutoKeyLocate: + if (default_akl) + { + /* This is the first time --auto-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) + log_error(_("%s:%d: invalid auto-key-locate list\n"), + configname,pargs.lineno); + else + log_error(_("invalid auto-key-locate list\n")); + } + break; + case oNoAutoKeyLocate: + 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; +#else + if (configname) + log_info("%s:%d: WARNING: gpg not built with large secure " + "memory buffer. Ignoring enable-large-rsa\n", + configname,pargs.lineno); + else + log_info("WARNING: gpg not built with large secure " + "memory buffer. Ignoring --enable-large-rsa\n"); +#endif /* SECMEM_BUFFER_SIZE >= 65536 */ + break; + case oDisableLargeRSA: opt.flags.large_rsa=0; + break; + + case oEnableDSA2: opt.flags.dsa2=1; break; + case oDisableDSA2: opt.flags.dsa2=0; break; + + case oAllowMultisigVerification: + case oAllowMultipleMessages: + opt.flags.allow_multiple_messages=1; + break; + + case oNoAllowMultipleMessages: + opt.flags.allow_multiple_messages=0; + break; + + case oAllowWeakDigestAlgos: + opt.flags.allow_weak_digest_algos = 1; + break; + + case oAllowWeakKeySignatures: + opt.flags.allow_weak_key_signatures = 1; + break; + + case oOverrideComplianceCheck: + opt.flags.override_compliance_check = 1; + break; + + case oFakedSystemTime: + { + 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, 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; + break; + + case oUseOnlyOpenPGPCard: + opt.flags.use_only_openpgp_card = 1; + break; + + case oForbidGenKey: + mopt.forbid_gen_key = 1; + break; + + case oRequireCompliance: + opt.flags.require_compliance = 1; + break; + + case oNoop: break; + + default: + if (configname) + 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; + } + } + + gnupg_argparse (NULL, &pargs, NULL); /* Release internal state. */ + + if (log_get_errorcount (0)) + { + 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. */ + if (cmd == aGPGConfList) + { + /* Note: Here in gpg 2.2 we need to provide a proper config + * file even if that file does not exist. This is because + * gpgconf checks that an absolute filename is provided. */ + if (!last_configname) + last_configname= make_filename (gnupg_homedir (), + GPG_NAME EXTSEP_S "conf", NULL); + gpgconf_list (last_configname); + g10_exit (0); + } + xfree (last_configname); + last_configname = NULL; + + if (print_dane_records) + log_error ("invalid option \"%s\"; use \"%s\" instead\n", + "--print-dane-records", + "--export-options export-dane"); + if (print_pka_records) + log_error ("invalid option \"%s\"; use \"%s\" instead\n", + "--print-pks-records", + "--export-options export-pka"); + if (log_get_errorcount (0)) + { + write_status_failure ("option-checking", gpg_error(GPG_ERR_GENERAL)); + g10_exit(2); + } + + + if( nogreeting ) + greeting = 0; + + if( greeting ) + { + 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) + { + const char *s; + + if((s=strusage(25))) + log_info("%s\n",s); + if((s=strusage(26))) + log_info("%s\n",s); + if((s=strusage(27))) + log_info("%s\n",s); + } +#endif + + /* FIXME: We should use logging to a file only in server mode; + however we have not yet implemetyed that. Thus we try to get + away with --batch as indication for logging to file + required. */ + if (logfile && opt.batch) + { + log_set_file (logfile); + log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID); + } + + if (opt.verbose > 2) + log_info ("using character set '%s'\n", get_native_charset ()); + + if( may_coredump && !opt.quiet ) + log_info(_("WARNING: program may create a core file!\n")); + + if (opt.flags.rfc4880bis) + log_info ("WARNING: using experimental features from RFC4880bis!\n"); + else + { + opt.mimemode = 0; /* This will use text mode instead. */ + } + + if (eyes_only) { + if (opt.set_filename) + log_info(_("WARNING: %s overrides %s\n"), + "--for-your-eyes-only","--set-filename"); + + opt.set_filename="_CONSOLE"; + } + + if (opt.no_literal) { + log_info(_("Note: %s is not for normal use!\n"), "--no-literal"); + if (opt.textmode) + log_error(_("%s not allowed with %s!\n"), + "--textmode", "--no-literal" ); + if (opt.set_filename) + log_error(_("%s makes no sense with %s!\n"), + eyes_only?"--for-your-eyes-only":"--set-filename", + "--no-literal" ); + } + + + if (opt.set_filesize) + log_info(_("Note: %s is not for normal use!\n"), "--set-filesize"); + if( opt.batch ) + tty_batchmode( 1 ); + + if (gnupg_faked_time_p ()) + { + gnupg_isotime_t tbuf; + + log_info (_("WARNING: running with faked system time: ")); + gnupg_get_isotime (tbuf); + 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]); + } + + + gcry_control (GCRYCTL_RESUME_SECMEM_WARN); + + if(require_secmem && !got_secmem) + { + 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); + } + + /* We allow overriding the compliance check only in non-batch mode + * so that the user has a chance to see the message. */ + if (opt.flags.override_compliance_check && opt.batch) + { + opt.flags.override_compliance_check = 0; + log_info ("Note: '%s' ignored due to batch mode\n", + "--override-compliance-check"); + } + + set_debug (debug_level); + gnupg_set_compliance_extra_info (opt.min_rsa_length); + if (DBG_CLOCK) + log_clock ("start"); + + /* Do these after the switch(), so they can override settings. */ + if(PGP6) + { + /* That does not anymore work because we have no more support + for v3 signatures. */ + opt.escape_from=1; + opt.ask_sig_expire=0; + } + else if(PGP7) + { + /* That does not anymore work because we have no more support + for v3 signatures. */ + opt.escape_from=1; + opt.ask_sig_expire=0; + } + else if(PGP8) + { + opt.escape_from=1; + } + + + if( def_cipher_string ) { + opt.def_cipher_algo = string_to_cipher_algo (def_cipher_string); + xfree(def_cipher_string); def_cipher_string = NULL; + if ( openpgp_cipher_test_algo (opt.def_cipher_algo) ) + log_error(_("selected cipher algorithm is invalid\n")); + } + if( def_digest_string ) { + opt.def_digest_algo = string_to_digest_algo (def_digest_string); + xfree(def_digest_string); def_digest_string = NULL; + if ( openpgp_md_test_algo (opt.def_digest_algo) ) + log_error(_("selected digest algorithm is invalid\n")); + } + if( compress_algo_string ) { + opt.compress_algo = string_to_compress_algo(compress_algo_string); + xfree(compress_algo_string); compress_algo_string = NULL; + if( check_compress_algo(opt.compress_algo) ) + log_error(_("selected compression algorithm is invalid\n")); + } + if( cert_digest_string ) { + opt.cert_digest_algo = string_to_digest_algo (cert_digest_string); + xfree(cert_digest_string); cert_digest_string = NULL; + if (openpgp_md_test_algo(opt.cert_digest_algo)) + log_error(_("selected certification digest algorithm is invalid\n")); + } + if( s2k_cipher_string ) { + opt.s2k_cipher_algo = string_to_cipher_algo (s2k_cipher_string); + xfree(s2k_cipher_string); s2k_cipher_string = NULL; + if (openpgp_cipher_test_algo (opt.s2k_cipher_algo)) + log_error(_("selected cipher algorithm is invalid\n")); + } + if( s2k_digest_string ) { + opt.s2k_digest_algo = string_to_digest_algo (s2k_digest_string); + xfree(s2k_digest_string); s2k_digest_string = NULL; + if (openpgp_md_test_algo(opt.s2k_digest_algo)) + log_error(_("selected digest algorithm is invalid\n")); + } + if( opt.completes_needed < 1 ) + log_error(_("completes-needed must be greater than 0\n")); + if( opt.marginals_needed < 2 ) + log_error(_("marginals-needed must be greater than 1\n")); + if( opt.max_cert_depth < 1 || opt.max_cert_depth > 255 ) + log_error(_("max-cert-depth must be in the range from 1 to 255\n")); + if(opt.def_cert_level<0 || opt.def_cert_level>3) + log_error(_("invalid default-cert-level; must be 0, 1, 2, or 3\n")); + if( opt.min_cert_level < 1 || opt.min_cert_level > 3 ) + log_error(_("invalid min-cert-level; must be 1, 2, or 3\n")); + switch( opt.s2k_mode ) { + case 0: + if (!opt.quiet) + log_info(_("Note: simple S2K mode (0) is strongly discouraged\n")); + break; + case 1: case 3: break; + default: + log_error(_("invalid S2K mode; must be 0, 1 or 3\n")); + } + + /* This isn't actually needed, but does serve to error out if the + string is invalid. */ + if(opt.def_preference_list && + keygen_set_std_prefs(opt.def_preference_list,0)) + log_error(_("invalid default preferences\n")); + + if(pers_cipher_list && + keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM)) + log_error(_("invalid personal cipher preferences\n")); + + if(pers_digest_list && + keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH)) + log_error(_("invalid personal digest preferences\n")); + + if(pers_compress_list && + keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP)) + log_error(_("invalid personal compress preferences\n")); + + /* We don't support all possible commands with multifile yet */ + if(multifile) + { + char *cmdname; + + switch(cmd) + { + case aSign: + cmdname="--sign"; + break; + case aSignEncr: + cmdname="--sign --encrypt"; + break; + case aClearsign: + cmdname="--clear-sign"; + break; + case aDetachedSign: + cmdname="--detach-sign"; + break; + case aSym: + cmdname="--symmetric"; + break; + case aEncrSym: + cmdname="--symmetric --encrypt"; + break; + case aStore: + cmdname="--store"; + break; + default: + cmdname=NULL; + break; + } + + if(cmdname) + log_error(_("%s does not yet work with %s\n"),cmdname,"--multifile"); + } + + if( log_get_errorcount(0) ) + { + write_status_failure ("option-postprocessing", + gpg_error(GPG_ERR_GENERAL)); + g10_exit (2); + } + + if(opt.compress_level==0) + opt.compress_algo=COMPRESS_ALGO_NONE; + + /* Check our chosen algorithms against the list of legal + algorithms. */ + + if(!GNUPG) + { + const char *badalg=NULL; + preftype_t badtype=PREFTYPE_NONE; + + if(opt.def_cipher_algo + && !algo_available(PREFTYPE_SYM,opt.def_cipher_algo,NULL)) + { + badalg = openpgp_cipher_algo_name (opt.def_cipher_algo); + badtype = PREFTYPE_SYM; + } + else if(opt.def_digest_algo + && !algo_available(PREFTYPE_HASH,opt.def_digest_algo,NULL)) + { + badalg = gcry_md_algo_name (opt.def_digest_algo); + badtype = PREFTYPE_HASH; + } + else if(opt.cert_digest_algo + && !algo_available(PREFTYPE_HASH,opt.cert_digest_algo,NULL)) + { + badalg = gcry_md_algo_name (opt.cert_digest_algo); + badtype = PREFTYPE_HASH; + } + else if(opt.compress_algo!=-1 + && !algo_available(PREFTYPE_ZIP,opt.compress_algo,NULL)) + { + badalg = compress_algo_to_string(opt.compress_algo); + badtype = PREFTYPE_ZIP; + } + + if(badalg) + { + switch(badtype) + { + case PREFTYPE_SYM: + 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 (_("digest algorithm '%s'" + " may not be used in %s mode\n"), + badalg, + gnupg_compliance_option_string (opt.compliance)); + break; + case PREFTYPE_ZIP: + log_info (_("compression algorithm '%s'" + " may not be used in %s mode\n"), + badalg, + gnupg_compliance_option_string (opt.compliance)); + break; + default: + BUG(); + } + + compliance_failure(); + } + } + + /* 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 ); + gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p); + if (!gnupg_access (p, F_OK)) + register_secured_file (p); + xfree(p); + } + + /* If there is no command but the --fingerprint is given, default + to the --list-keys command. */ + if (!cmd && fpr_maybe_cmd) + { + set_cmd (&cmd, aListKeys); + } + + + if( opt.verbose > 1 ) + set_packet_list_mode(1); + + /* Add the keyrings, but not for some special commands. We always + * need to add the keyrings if we are running under SELinux, this + * is so that the rings are added to the list of secured files. + * We do not add any keyring if --no-keyring has been used. */ + if (default_keyring >= 0 + && (ALWAYS_ADD_KEYRINGS + || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest))) + { + if (!nrings || default_keyring > 0) /* Add default ring. */ + keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG, + KEYDB_RESOURCE_FLAG_DEFAULT); + for (sl = nrings; sl; sl = sl->next ) + keydb_add_resource (sl->d, sl->flags); + } + FREE_STRLIST(nrings); + + if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK) + /* In loopback mode, never ask for the password multiple + times. */ + { + opt.passphrase_repeat = 0; + } + + if (cmd == aGPGConfTest) + g10_exit(0); + + + if (pwfd != -1) /* Read the passphrase now. */ + read_passphrase_from_fd (pwfd); + + if (ovrseskeyfd != -1 ) /* Read the sessionkey now. */ + read_sessionkey_from_fd (ovrseskeyfd); + + fname = argc? *argv : NULL; + + if(fname && utf8_strings) + opt.flags.utf8_filename=1; + + ctrl = xcalloc (1, sizeof *ctrl); + gpg_init_default_ctrl (ctrl); + +#ifndef NO_TRUST_MODELS + switch (cmd) + { + case aPrimegen: + case aPrintMD: + case aPrintMDs: + case aGenRandom: + case aDeArmor: + case aEnArmor: + case aListConfig: + case aListGcryptConfig: + break; + case aFixTrustDB: + case aExportOwnerTrust: + rc = setup_trustdb (0, trustdb_name); + break; + 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. */ + rc = setup_trustdb (opt.trust_model != TM_ALWAYS, trustdb_name); + break; + } + if (rc) + log_error (_("failed to initialize the TrustDB: %s\n"), + gpg_strerror (rc)); +#endif /*!NO_TRUST_MODELS*/ + + switch (cmd) + { + case aStore: + case aSym: + case aSign: + case aSignSym: + case aClearsign: + if (!opt.quiet && any_explicit_recipient) + log_info (_("WARNING: recipients (-r) given " + "without using public key encryption\n")); + break; + default: + break; + } + + + /* Check for certain command whether we need to migrate a + secring.gpg to the gpg-agent. */ + switch (cmd) + { + case aListSecretKeys: + case aSign: + case aSignEncr: + case aSignEncrSym: + case aSignSym: + case aClearsign: + case aDecrypt: + case aSignKey: + case aLSignKey: + case aEditKey: + case aPasswd: + case aDeleteSecretKeys: + case aDeleteSecretAndPublicKeys: + case aQuickKeygen: + case aQuickAddUid: + case aQuickAddKey: + case aQuickRevUid: + case aQuickSetPrimaryUid: + case aFullKeygen: + case aKeygen: + case aImport: + case aExportSecret: + case aExportSecretSub: + case aGenRevoke: + case aDesigRevoke: + case aCardEdit: + case aChangePIN: + migrate_secring (ctrl); + break; + case aListKeys: + if (opt.with_secret) + migrate_secring (ctrl); + break; + default: + break; + } + + /* The command dispatcher. */ + switch( cmd ) + { + case aServer: + gpg_server (ctrl); + break; + + case aStore: /* only store the file */ + if( argc > 1 ) + wrong_args("--store [filename]"); + if( (rc = encrypt_store(fname)) ) + { + write_status_failure ("store", rc); + log_error ("storing '%s' failed: %s\n", + print_fname_stdin(fname),gpg_strerror (rc) ); + } + break; + case aSym: /* encrypt the given file only with the symmetric cipher */ + if( argc > 1 ) + wrong_args("--symmetric [filename]"); + if( (rc = encrypt_symmetric(fname)) ) + { + write_status_failure ("symencrypt", rc); + log_error (_("symmetric encryption of '%s' failed: %s\n"), + print_fname_stdin(fname),gpg_strerror (rc) ); + } + break; + + case aEncr: /* encrypt the given file */ + if(multifile) + encrypt_crypt_files (ctrl, argc, argv, remusr); + else + { + if( argc > 1 ) + wrong_args("--encrypt [filename]"); + if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 0, NULL, -1)) ) + { + write_status_failure ("encrypt", rc); + log_error("%s: encryption failed: %s\n", + print_fname_stdin(fname), gpg_strerror (rc) ); + } + } + break; + + case aEncrSym: + /* This works with PGP 8 in the sense that it acts just like a + symmetric message. It doesn't work at all with 2 or 6. It + 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]"); + 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" + " in %s mode\n"), + gnupg_compliance_option_string (opt.compliance)); + else + { + if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 1, NULL, -1)) ) + { + write_status_failure ("encrypt", rc); + log_error ("%s: encryption failed: %s\n", + print_fname_stdin(fname), gpg_strerror (rc) ); + } + } + break; + + case aSign: /* sign the given file */ + sl = NULL; + if( detached_sig ) { /* sign all files */ + for( ; argc; argc--, argv++ ) + add_to_strlist( &sl, *argv ); + } + else { + if( argc > 1 ) + wrong_args("--sign [filename]"); + if( argc ) { + sl = xmalloc_clear( sizeof *sl + strlen(fname)); + strcpy(sl->d, fname); + } + } + if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 0, NULL, NULL))) + { + write_status_failure ("sign", rc); + log_error ("signing failed: %s\n", gpg_strerror (rc) ); + } + free_strlist(sl); + break; + + case aSignEncr: /* sign and encrypt the given file */ + if( argc > 1 ) + wrong_args("--sign --encrypt [filename]"); + if( argc ) { + sl = xmalloc_clear( sizeof *sl + strlen(fname)); + strcpy(sl->d, fname); + } + else + sl = NULL; + if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 1, remusr, NULL))) + { + write_status_failure ("sign-encrypt", rc); + log_error("%s: sign+encrypt failed: %s\n", + print_fname_stdin(fname), gpg_strerror (rc) ); + } + free_strlist(sl); + break; + + case aSignEncrSym: /* sign and encrypt the given file */ + if( argc > 1 ) + 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" + " in %s mode\n"), + gnupg_compliance_option_string (opt.compliance)); + else + { + if( argc ) + { + sl = xmalloc_clear( sizeof *sl + strlen(fname)); + strcpy(sl->d, fname); + } + else + sl = NULL; + if ((rc = sign_file (ctrl, sl, detached_sig, locusr, + 2, remusr, NULL))) + { + write_status_failure ("sign-encrypt", rc); + log_error("%s: symmetric+sign+encrypt failed: %s\n", + print_fname_stdin(fname), gpg_strerror (rc) ); + } + free_strlist(sl); + } + break; + + case aSignSym: /* sign and conventionally encrypt the given file */ + if (argc > 1) + wrong_args("--sign --symmetric [filename]"); + rc = sign_symencrypt_file (ctrl, fname, locusr); + if (rc) + { + write_status_failure ("sign-symencrypt", rc); + log_error("%s: sign+symmetric failed: %s\n", + print_fname_stdin(fname), gpg_strerror (rc) ); + } + break; + + case aClearsign: /* make a clearsig */ + if( argc > 1 ) + wrong_args("--clear-sign [filename]"); + if( (rc = clearsign_file (ctrl, fname, locusr, NULL)) ) + { + write_status_failure ("sign", rc); + log_error("%s: clear-sign failed: %s\n", + print_fname_stdin(fname), gpg_strerror (rc) ); + } + break; + + case aVerify: + if (multifile) + { + if ((rc = verify_files (ctrl, argc, argv))) + log_error("verify files failed: %s\n", gpg_strerror (rc) ); + } + else + { + if ((rc = verify_signatures (ctrl, argc, argv))) + log_error("verify signatures failed: %s\n", gpg_strerror (rc) ); + } + if (rc) + write_status_failure ("verify", rc); + break; + + case aDecrypt: + if (multifile) + decrypt_messages (ctrl, argc, argv); + else + { + if( argc > 1 ) + wrong_args("--decrypt [filename]"); + if( (rc = decrypt_message (ctrl, fname) )) + { + write_status_failure ("decrypt", rc); + log_error("decrypt_message failed: %s\n", gpg_strerror (rc) ); + } + } + break; + + case aQuickSignKey: + case aQuickLSignKey: + { + const char *fpr; + + if (argc < 1) + wrong_args ("--quick-[l]sign-key fingerprint [userids]"); + fpr = *argv++; argc--; + sl = NULL; + for( ; argc; argc--, argv++) + append_to_strlist2 (&sl, *argv, utf8_strings); + keyedit_quick_sign (ctrl, fpr, sl, locusr, (cmd == aQuickLSignKey)); + free_strlist (sl); + } + break; + + case aQuickRevSig: + { + const char *userid, *siguserid; + + if (argc < 2) + wrong_args ("--quick-revoke-sig USER-ID SIG-USER-ID [userids]"); + userid = *argv++; argc--; + siguserid = *argv++; argc--; + sl = NULL; + for( ; argc; argc--, argv++) + append_to_strlist2 (&sl, *argv, utf8_strings); + keyedit_quick_revsig (ctrl, userid, siguserid, sl); + free_strlist (sl); + } + break; + + case aSignKey: + if( argc != 1 ) + wrong_args("--sign-key user-id"); + /* fall through */ + case aLSignKey: + if( argc != 1 ) + wrong_args("--lsign-key user-id"); + /* fall through */ + + sl=NULL; + + if(cmd==aSignKey) + append_to_strlist(&sl,"sign"); + else if(cmd==aLSignKey) + append_to_strlist(&sl,"lsign"); + else + BUG(); + + append_to_strlist( &sl, "save" ); + username = make_username( fname ); + keyedit_menu (ctrl, username, locusr, sl, 0, 0 ); + xfree(username); + free_strlist(sl); + break; + + case aEditKey: /* Edit a key signature */ + if( !argc ) + wrong_args("--edit-key user-id [commands]"); + username = make_username( fname ); + if( argc > 1 ) { + sl = NULL; + for( argc--, argv++ ; argc; argc--, argv++ ) + append_to_strlist( &sl, *argv ); + keyedit_menu (ctrl, username, locusr, sl, 0, 1 ); + free_strlist(sl); + } + else + keyedit_menu (ctrl, username, locusr, NULL, 0, 1 ); + xfree(username); + break; + + case aPasswd: + if (argc != 1) + wrong_args("--change-passphrase <user-id>"); + else + { + username = make_username (fname); + keyedit_passwd (ctrl, username); + xfree (username); + } + break; + + case aDeleteKeys: + case aDeleteSecretKeys: + case aDeleteSecretAndPublicKeys: + sl = NULL; + /* Print a note if the user did not specify any key. */ + if (!argc && !opt.quiet) + log_info (_("Note: %s\n"), gpg_strerror (GPG_ERR_NO_KEY)); + /* I'm adding these in reverse order as add_to_strlist2 + reverses them again, and it's easier to understand in the + proper order :) */ + for( ; argc; argc-- ) + add_to_strlist2( &sl, argv[argc-1], utf8_strings ); + delete_keys (ctrl, sl, + cmd==aDeleteSecretKeys, cmd==aDeleteSecretAndPublicKeys); + free_strlist(sl); + break; + + case aCheckKeys: + opt.check_sigs = 1; /* fall through */ + case aListSigs: + opt.list_sigs = 1; /* fall through */ + case aListKeys: + sl = NULL; + for( ; argc; argc--, argv++ ) + add_to_strlist2( &sl, *argv, utf8_strings ); + public_key_list (ctrl, sl, 0, 0); + free_strlist(sl); + break; + case aListSecretKeys: + sl = NULL; + for( ; argc; argc--, argv++ ) + add_to_strlist2( &sl, *argv, utf8_strings ); + secret_key_list (ctrl, sl); + free_strlist(sl); + break; + case aLocateKeys: + case aLocateExtKeys: + sl = NULL; + for (; argc; argc--, argv++) + add_to_strlist2( &sl, *argv, utf8_strings ); + if (cmd == aLocateExtKeys && akl_empty_or_only_local ()) + { + /* This is a kludge to let --locate-external-keys even + * work if the config file has --no-auto-key-locate. This + * better matches the expectations of the user. */ + release_akl (); + parse_auto_key_locate (DEFAULT_AKL_LIST); + } + public_key_list (ctrl, sl, 1, cmd == aLocateExtKeys); + + + free_strlist (sl); + break; + + case aQuickKeygen: + { + const char *x_algo, *x_usage, *x_expire; + + if (argc < 1 || argc > 4) + wrong_args("--quick-generate-key USER-ID [ALGO [USAGE [EXPIRE]]]"); + username = make_username (fname); + argv++, argc--; + x_algo = ""; + x_usage = ""; + x_expire = ""; + if (argc) + { + x_algo = *argv++; argc--; + if (argc) + { + x_usage = *argv++; argc--; + if (argc) + { + x_expire = *argv++; argc--; + } + } + } + if (mopt.forbid_gen_key) + gen_key_forbidden (); + else + quick_generate_keypair (ctrl, username, x_algo, x_usage, x_expire); + xfree (username); + } + break; + + case aKeygen: /* generate a key */ + if (mopt.forbid_gen_key) + gen_key_forbidden (); + else if( opt.batch ) + { + if( argc > 1 ) + 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("--generate-key [parameterfile]"); + + opt.batch = 1; + generate_keypair (ctrl, 0, argc? *argv : NULL, NULL, 0); + } + else if (argc) + wrong_args ("--generate-key"); + else + generate_keypair (ctrl, 0, NULL, NULL, 0); + } + break; + + case aFullKeygen: /* Generate a key with all options. */ + if (mopt.forbid_gen_key) + gen_key_forbidden (); + else if (opt.batch) + { + if (argc > 1) + wrong_args ("--full-generate-key [parameterfile]"); + generate_keypair (ctrl, 1, argc? *argv : NULL, NULL, 0); + } + else + { + if (argc) + wrong_args("--full-generate-key"); + generate_keypair (ctrl, 1, NULL, NULL, 0); + } + break; + + case aQuickAddUid: + { + const char *uid, *newuid; + + if (argc != 2) + wrong_args ("--quick-add-uid USER-ID NEW-USER-ID"); + uid = *argv++; argc--; + newuid = *argv++; argc--; + keyedit_quick_adduid (ctrl, uid, newuid); + } + break; + + case aQuickAddKey: + { + const char *x_fpr, *x_algo, *x_usage, *x_expire; + + if (argc < 1 || argc > 4) + wrong_args ("--quick-add-key FINGERPRINT [ALGO [USAGE [EXPIRE]]]"); + x_fpr = *argv++; argc--; + x_algo = ""; + x_usage = ""; + x_expire = ""; + if (argc) + { + x_algo = *argv++; argc--; + if (argc) + { + x_usage = *argv++; argc--; + if (argc) + { + x_expire = *argv++; argc--; + } + } + } + if (mopt.forbid_gen_key) + gen_key_forbidden (); + else + keyedit_quick_addkey (ctrl, x_fpr, x_algo, x_usage, x_expire); + } + break; + + case aQuickRevUid: + { + const char *uid, *uidtorev; + + if (argc != 2) + wrong_args ("--quick-revoke-uid USER-ID USER-ID-TO-REVOKE"); + uid = *argv++; argc--; + uidtorev = *argv++; argc--; + keyedit_quick_revuid (ctrl, uid, uidtorev); + } + break; + + case aQuickSetExpire: + { + const char *x_fpr, *x_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, 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; /* fall through */ + case aImport: + case aShowKeys: + 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 + "make strlist, call function, report error, free strlist" + pattern. Join them together here and avoid all that + duplicated code. */ + + case aExport: + case aSendKeys: + case aRecvKeys: + sl = NULL; + for( ; argc; argc--, argv++ ) + append_to_strlist2( &sl, *argv, utf8_strings ); + if( cmd == aSendKeys ) + rc = keyserver_export (ctrl, sl ); + else if( cmd == aRecvKeys ) + rc = keyserver_import (ctrl, sl ); + else + { + export_stats_t stats = export_new_stats (); + rc = export_pubkeys (ctrl, sl, opt.export_options, stats); + export_print_stats (stats); + export_release_stats (stats); + } + if(rc) + { + if(cmd==aSendKeys) + { + write_status_failure ("send-keys", rc); + log_error(_("keyserver send failed: %s\n"),gpg_strerror (rc)); + } + else if(cmd==aRecvKeys) + { + write_status_failure ("recv-keys", rc); + log_error (_("keyserver receive failed: %s\n"), + gpg_strerror (rc)); + } + else + { + write_status_failure ("export", rc); + log_error (_("key export failed: %s\n"), gpg_strerror (rc)); + } + } + free_strlist(sl); + break; + + case aExportSshKey: + if (argc != 1) + wrong_args ("--export-ssh-key <user-id>"); + rc = export_ssh_key (ctrl, argv[0]); + if (rc) + { + write_status_failure ("export-ssh-key", rc); + log_error (_("export as ssh key failed: %s\n"), gpg_strerror (rc)); + } + break; + + case aSearchKeys: + sl = NULL; + for (; argc; argc--, argv++) + append_to_strlist2 (&sl, *argv, utf8_strings); + rc = keyserver_search (ctrl, sl); + if (rc) + { + write_status_failure ("search-keys", rc); + log_error (_("keyserver search failed: %s\n"), gpg_strerror (rc)); + } + free_strlist (sl); + break; + + case aRefreshKeys: + sl = NULL; + for( ; argc; argc--, argv++ ) + append_to_strlist2( &sl, *argv, utf8_strings ); + rc = keyserver_refresh (ctrl, sl); + if(rc) + { + write_status_failure ("refresh-keys", rc); + log_error (_("keyserver refresh failed: %s\n"),gpg_strerror (rc)); + } + free_strlist(sl); + break; + + case aFetchKeys: + sl = NULL; + for( ; argc; argc--, argv++ ) + append_to_strlist2( &sl, *argv, utf8_strings ); + rc = keyserver_fetch (ctrl, sl, opt.key_origin); + free_strlist (sl); + if(rc) + { + write_status_failure ("fetch-keys", rc); + log_error ("key fetch failed: %s\n",gpg_strerror (rc)); + if (gpg_err_code (rc) == GPG_ERR_NO_DATA) + g10_exit (1); /* In this case return 1 and not 2. */ + } + break; + + case aExportSecret: + sl = NULL; + for( ; argc; argc--, argv++ ) + add_to_strlist2( &sl, *argv, utf8_strings ); + { + export_stats_t stats = export_new_stats (); + export_seckeys (ctrl, sl, opt.export_options, stats); + export_print_stats (stats); + export_release_stats (stats); + } + free_strlist(sl); + break; + + case aExportSecretSub: + sl = NULL; + for( ; argc; argc--, argv++ ) + add_to_strlist2( &sl, *argv, utf8_strings ); + { + export_stats_t stats = export_new_stats (); + export_secsubkeys (ctrl, sl, opt.export_options, stats); + export_print_stats (stats); + export_release_stats (stats); + } + free_strlist(sl); + break; + + case aGenRevoke: + if( argc != 1 ) + wrong_args("--generate-revocation user-id"); + username = make_username(*argv); + gen_revoke (ctrl, username ); + xfree( username ); + break; + + case aDesigRevoke: + if (argc != 1) + wrong_args ("--generate-designated-revocation user-id"); + username = make_username (*argv); + gen_desig_revoke (ctrl, username, locusr); + xfree (username); + break; + + case aDeArmor: + if( argc > 1 ) + wrong_args("--dearmor [file]"); + rc = dearmor_file( argc? *argv: NULL ); + if( rc ) + { + write_status_failure ("dearmor", rc); + log_error (_("dearmoring failed: %s\n"), gpg_strerror (rc)); + } + break; + + case aEnArmor: + if( argc > 1 ) + wrong_args("--enarmor [file]"); + rc = enarmor_file( argc? *argv: NULL ); + if( rc ) + { + write_status_failure ("enarmor", rc); + log_error (_("enarmoring failed: %s\n"), gpg_strerror (rc)); + } + break; + + + case aPrimegen: +#if 0 /*FIXME*/ + { int mode = argc < 2 ? 0 : atoi(*argv); + + if( mode == 1 && argc == 2 ) { + mpi_print (es_stdout, + generate_public_prime( atoi(argv[1]) ), 1); + } + else if( mode == 2 && argc == 3 ) { + mpi_print (es_stdout, generate_elg_prime( + 0, atoi(argv[1]), + atoi(argv[2]), NULL,NULL ), 1); + } + else if( mode == 3 && argc == 3 ) { + MPI *factors; + mpi_print (es_stdout, generate_elg_prime( + 1, atoi(argv[1]), + atoi(argv[2]), NULL,&factors ), 1); + es_putc ('\n', es_stdout); + mpi_print (es_stdout, factors[0], 1 ); /* print q */ + } + else if( mode == 4 && argc == 3 ) { + MPI g = mpi_alloc(1); + mpi_print (es_stdout, generate_elg_prime( + 0, atoi(argv[1]), + atoi(argv[2]), g, NULL ), 1); + es_putc ('\n', es_stdout); + mpi_print (es_stdout, g, 1 ); + mpi_free (g); + } + else + wrong_args("--gen-prime mode bits [qbits] "); + es_putc ('\n', es_stdout); + } +#endif + wrong_args("--gen-prime not yet supported "); + break; + + case aGenRandom: + { + int level = argc ? atoi(*argv):0; + int count = argc > 1 ? atoi(argv[1]): 0; + int endless = !count; + + if( argc < 1 || argc > 2 || level < 0 || level > 2 || count < 0 ) + wrong_args("--gen-random 0|1|2 [count]"); + + while( endless || count ) { + byte *p; + /* Wee need a multiple of 3, so that in case of + armored output we get a correct string. No + linefolding is done, as it is best to levae this to + other tools */ + size_t n = !endless && count < 99? count : 99; + + p = gcry_random_bytes (n, level); +#ifdef HAVE_DOSISH_SYSTEM + setmode ( fileno(stdout), O_BINARY ); +#endif + if (opt.armor) { + char *tmp = make_radix64_string (p, n); + es_fputs (tmp, es_stdout); + xfree (tmp); + if (n%3 == 1) + es_putc ('=', es_stdout); + if (n%3) + es_putc ('=', es_stdout); + } else { + es_fwrite( p, n, 1, es_stdout ); + } + xfree(p); + if( !endless ) + count -= n; + } + if (opt.armor) + es_putc ('\n', es_stdout); + } + break; + + case aPrintMD: + if( argc < 1) + wrong_args("--print-md algo [files]"); + { + int all_algos = (**argv=='*' && !(*argv)[1]); + int algo = all_algos? 0 : gcry_md_map_name (*argv); + + if( !algo && !all_algos ) + log_error(_("invalid hash algorithm '%s'\n"), *argv ); + else { + argc--; argv++; + if( !argc ) + print_mds(NULL, algo); + else { + for(; argc; argc--, argv++ ) + print_mds(*argv, algo); + } + } + } + break; + + case aPrintMDs: /* old option */ + if( !argc ) + print_mds(NULL,0); + else { + for(; argc; argc--, argv++ ) + print_mds(*argv,0); + } + break; + +#ifndef NO_TRUST_MODELS + case aListTrustDB: + if( !argc ) + list_trustdb (ctrl, es_stdout, NULL); + else { + for( ; argc; argc--, argv++ ) + list_trustdb (ctrl, es_stdout, *argv ); + } + break; + + case aUpdateTrustDB: + if( argc ) + wrong_args("--update-trustdb"); + update_trustdb (ctrl); + break; + + case aCheckTrustDB: + /* Old versions allowed for arguments - ignore them */ + check_trustdb (ctrl); + break; + + case aFixTrustDB: + how_to_fix_the_trustdb (); + break; + + case aListTrustPath: + if( !argc ) + wrong_args("--list-trust-path <user-ids>"); + for( ; argc; argc--, argv++ ) { + username = make_username( *argv ); + list_trust_path( username ); + xfree(username); + } + break; + + case aExportOwnerTrust: + if( argc ) + wrong_args("--export-ownertrust"); + export_ownertrust (ctrl); + break; + + case aImportOwnerTrust: + if( argc > 1 ) + wrong_args("--import-ownertrust [file]"); + import_ownertrust (ctrl, argc? *argv:NULL ); + break; +#endif /*!NO_TRUST_MODELS*/ + + case aRebuildKeydbCaches: + if (argc) + wrong_args ("--rebuild-keydb-caches"); + keydb_rebuild_caches (ctrl, 1); + break; + +#ifdef ENABLE_CARD_SUPPORT + case aCardStatus: + 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: + if (argc) { + sl = NULL; + for (argc--, argv++ ; argc; argc--, argv++) + append_to_strlist (&sl, *argv); + card_edit (ctrl, sl); + free_strlist (sl); + } + else + card_edit (ctrl, NULL); + break; + + case aChangePIN: + if (!argc) + change_pin (0,1); + else if (argc == 1) + change_pin (atoi (*argv),1); + else + wrong_args ("--change-pin [no]"); + break; +#endif /* ENABLE_CARD_SUPPORT*/ + + case aListConfig: + { + char *str=collapse_args(argc,argv); + list_config(str); + xfree(str); + } + break; + + case aListGcryptConfig: + /* Fixme: It would be nice to integrate that with + --list-config but unfortunately there is no way yet to have + libgcrypt print it to an estream for further parsing. */ + gcry_control (GCRYCTL_PRINT_CONFIG, stdout); + break; + + case aTOFUPolicy: +#ifdef USE_TOFU + { + int policy; + int i; + KEYDB_HANDLE hd; + + if (argc < 2) + wrong_args ("--tofu-policy POLICY KEYID [KEYID...]"); + + policy = parse_tofu_policy (argv[0]); + + hd = keydb_new (); + if (! hd) + { + write_status_failure ("tofu-driver", gpg_error(GPG_ERR_GENERAL)); + g10_exit (1); + } + + tofu_begin_batch_update (ctrl); + + for (i = 1; i < argc; i ++) + { + KEYDB_SEARCH_DESC desc; + kbnode_t kb; + + rc = classify_user_id (argv[i], &desc, 0); + if (rc) + { + log_error (_("error parsing key specification '%s': %s\n"), + argv[i], gpg_strerror (rc)); + write_status_failure ("tofu-driver", rc); + g10_exit (1); + } + + if (! (desc.mode == KEYDB_SEARCH_MODE_SHORT_KID + || desc.mode == KEYDB_SEARCH_MODE_LONG_KID + || desc.mode == KEYDB_SEARCH_MODE_FPR16 + || desc.mode == KEYDB_SEARCH_MODE_FPR20 + || desc.mode == KEYDB_SEARCH_MODE_FPR + || desc.mode == KEYDB_SEARCH_MODE_KEYGRIP)) + { + 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); + } + + rc = keydb_search_reset (hd); + if (rc) + { + /* This should not happen, thus no need to tranalate + the string. */ + log_error ("keydb_search_reset failed: %s\n", + gpg_strerror (rc)); + write_status_failure ("tofu-driver", rc); + g10_exit (1); + } + + rc = keydb_search (hd, &desc, 1, NULL); + if (rc) + { + log_error (_("key \"%s\" not found: %s\n"), argv[i], + gpg_strerror (rc)); + write_status_failure ("tofu-driver", rc); + g10_exit (1); + } + + rc = keydb_get_keyblock (hd, &kb); + if (rc) + { + log_error (_("error reading keyblock: %s\n"), + gpg_strerror (rc)); + write_status_failure ("tofu-driver", rc); + g10_exit (1); + } + + merge_keys_and_selfsig (ctrl, kb); + if (tofu_set_policy (ctrl, kb, policy)) + { + write_status_failure ("tofu-driver", rc); + g10_exit (1); + } + + release_kbnode (kb); + } + + tofu_end_batch_update (ctrl); + + keydb_release (hd); + } +#endif /*USE_TOFU*/ + break; + + 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]"); + /* Issue some output for the unix newbie */ + if (!fname && !opt.outfile + && gnupg_isatty (fileno (stdin)) + && gnupg_isatty (fileno (stdout)) + && gnupg_isatty (fileno (stderr))) + log_info(_("Go ahead and type your message ...\n")); + + a = iobuf_open(fname); + if (a && is_secured_file (iobuf_get_fd (a))) + { + iobuf_close (a); + a = NULL; + gpg_err_set_errno (EPERM); + } + if( !a ) + log_error(_("can't open '%s'\n"), print_fname_stdin(fname)); + else { + + if( !opt.no_armor ) { + if( use_armor_filter( a ) ) { + afx = new_armor_context (); + push_armor_filter (afx, a); + } + } + if( cmd == aListPackets ) { + opt.list_packets=1; + set_packet_list_mode(1); + } + rc = proc_packets (ctrl, NULL, a ); + if( rc ) + { + write_status_failure ("-", rc); + log_error ("processing message failed: %s\n", + gpg_strerror (rc)); + } + iobuf_close(a); + } + break; + } + + /* cleanup */ + gpg_deinit_default_ctrl (ctrl); + xfree (ctrl); + release_armor_context (afx); + FREE_STRLIST(remusr); + FREE_STRLIST(locusr); + g10_exit(0); + return 8; /*NEVER REACHED*/ +} + + +/* Note: This function is used by signal handlers!. */ +static void +emergency_cleanup (void) +{ + gcry_control (GCRYCTL_TERM_SECMEM ); +} + + +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"); + + 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); + } + if (opt.debug) + gcry_control (GCRYCTL_DUMP_SECMEM_STATS ); + + emergency_cleanup (); + + rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0; + exit (rc); +} + + +/* Pretty-print hex hashes. This assumes at least an 80-character + display, but there are a few other similar assumptions in the + display code. */ +static void +print_hex (gcry_md_hd_t md, int algo, const char *fname) +{ + int i,n,count,indent=0; + const byte *p; + + if (fname) + indent = es_printf("%s: ",fname); + + if (indent>40) + { + es_printf ("\n"); + indent=0; + } + + if (algo==DIGEST_ALGO_RMD160) + indent += es_printf("RMD160 = "); + else if (algo>0) + indent += es_printf("%6s = ", gcry_md_algo_name (algo)); + else + algo = abs(algo); + + count = indent; + + p = gcry_md_read (md, algo); + n = gcry_md_get_algo_dlen (algo); + + count += es_printf ("%02X",*p++); + + for(i=1;i<n;i++,p++) + { + if(n==16) + { + if(count+2>79) + { + es_printf ("\n%*s",indent," "); + count = indent; + } + else + count += es_printf(" "); + + if (!(i%8)) + count += es_printf(" "); + } + else if (n==20) + { + if(!(i%2)) + { + if(count+4>79) + { + es_printf ("\n%*s",indent," "); + count=indent; + } + else + count += es_printf(" "); + } + + if (!(i%10)) + count += es_printf(" "); + } + else + { + if(!(i%4)) + { + if (count+8>79) + { + es_printf ("\n%*s",indent," "); + count=indent; + } + else + count += es_printf(" "); + } + } + + count += es_printf("%02X",*p); + } + + es_printf ("\n"); +} + +static void +print_hashline( gcry_md_hd_t md, int algo, const char *fname ) +{ + int i, n; + const byte *p; + + if ( fname ) + { + for (p = fname; *p; p++ ) + { + if ( *p <= 32 || *p > 127 || *p == ':' || *p == '%' ) + es_printf ("%%%02X", *p ); + else + es_putc (*p, es_stdout); + } + } + es_putc (':', es_stdout); + es_printf ("%d:", algo); + p = gcry_md_read (md, algo); + n = gcry_md_get_algo_dlen (algo); + for(i=0; i < n ; i++, p++ ) + es_printf ("%02X", *p); + es_fputs (":\n", es_stdout); +} + + +static void +print_mds( const char *fname, int algo ) +{ + estream_t fp; + char buf[1024]; + size_t n; + gcry_md_hd_t md; + + if (!fname) + { + fp = es_stdin; + es_set_binary (fp); + } + else + { + fp = es_fopen (fname, "rb" ); + if (fp && is_secured_file (es_fileno (fp))) + { + es_fclose (fp); + fp = NULL; + gpg_err_set_errno (EPERM); + } + } + if (!fp) + { + log_error("%s: %s\n", fname?fname:"[stdin]", strerror(errno) ); + return; + } + + gcry_md_open (&md, 0, 0); + if (algo) + gcry_md_enable (md, algo); + else + { + if (!gcry_md_test_algo (GCRY_MD_MD5)) + gcry_md_enable (md, GCRY_MD_MD5); + gcry_md_enable (md, GCRY_MD_SHA1); + if (!gcry_md_test_algo (GCRY_MD_RMD160)) + gcry_md_enable (md, GCRY_MD_RMD160); + if (!gcry_md_test_algo (GCRY_MD_SHA224)) + gcry_md_enable (md, GCRY_MD_SHA224); + if (!gcry_md_test_algo (GCRY_MD_SHA256)) + gcry_md_enable (md, GCRY_MD_SHA256); + if (!gcry_md_test_algo (GCRY_MD_SHA384)) + gcry_md_enable (md, GCRY_MD_SHA384); + if (!gcry_md_test_algo (GCRY_MD_SHA512)) + gcry_md_enable (md, GCRY_MD_SHA512); + } + + while ((n=es_fread (buf, 1, DIM(buf), fp))) + gcry_md_write (md, buf, n); + + if (es_ferror(fp)) + log_error ("%s: %s\n", fname?fname:"[stdin]", strerror(errno)); + else + { + gcry_md_final (md); + if (opt.with_colons) + { + if ( algo ) + print_hashline (md, algo, fname); + else + { + if (!gcry_md_test_algo (GCRY_MD_MD5)) + print_hashline( md, GCRY_MD_MD5, fname ); + print_hashline( md, GCRY_MD_SHA1, fname ); + if (!gcry_md_test_algo (GCRY_MD_RMD160)) + print_hashline( md, GCRY_MD_RMD160, fname ); + if (!gcry_md_test_algo (GCRY_MD_SHA224)) + print_hashline (md, GCRY_MD_SHA224, fname); + if (!gcry_md_test_algo (GCRY_MD_SHA256)) + print_hashline( md, GCRY_MD_SHA256, fname ); + if (!gcry_md_test_algo (GCRY_MD_SHA384)) + print_hashline ( md, GCRY_MD_SHA384, fname ); + if (!gcry_md_test_algo (GCRY_MD_SHA512)) + print_hashline ( md, GCRY_MD_SHA512, fname ); + } + } + else + { + if (algo) + print_hex (md, -algo, fname); + else + { + if (!gcry_md_test_algo (GCRY_MD_MD5)) + print_hex (md, GCRY_MD_MD5, fname); + print_hex (md, GCRY_MD_SHA1, fname ); + if (!gcry_md_test_algo (GCRY_MD_RMD160)) + print_hex (md, GCRY_MD_RMD160, fname ); + if (!gcry_md_test_algo (GCRY_MD_SHA224)) + print_hex (md, GCRY_MD_SHA224, fname); + if (!gcry_md_test_algo (GCRY_MD_SHA256)) + print_hex (md, GCRY_MD_SHA256, fname ); + if (!gcry_md_test_algo (GCRY_MD_SHA384)) + print_hex (md, GCRY_MD_SHA384, fname ); + if (!gcry_md_test_algo (GCRY_MD_SHA512)) + print_hex (md, GCRY_MD_SHA512, fname ); + } + } + } + gcry_md_close (md); + + if (fp != es_stdin) + es_fclose (fp); +} + + +/**************** + * Check the supplied name,value string and add it to the notation + * data to be used for signatures. which==0 for sig notations, and 1 + * for cert notations. +*/ +static void +add_notation_data( const char *string, int which ) +{ + struct notation *notation; + + notation=string_to_notation(string,utf8_strings); + if(notation) + { + if(which) + { + notation->next=opt.cert_notations; + opt.cert_notations=notation; + } + else + { + notation->next=opt.sig_notations; + opt.sig_notations=notation; + } + } +} + +static void +add_policy_url( const char *string, int which ) +{ + unsigned int i,critical=0; + strlist_t sl; + + if(*string=='!') + { + string++; + critical=1; + } + + for(i=0;i<strlen(string);i++) + if( !isascii (string[i]) || iscntrl(string[i])) + break; + + if(i==0 || i<strlen(string)) + { + if(which) + log_error(_("the given certification policy URL is invalid\n")); + else + log_error(_("the given signature policy URL is invalid\n")); + } + + if(which) + sl=add_to_strlist( &opt.cert_policy_url, string ); + else + sl=add_to_strlist( &opt.sig_policy_url, string ); + + if(critical) + sl->flags |= 1; +} + +static void +add_keyserver_url( const char *string, int which ) +{ + unsigned int i,critical=0; + strlist_t sl; + + if(*string=='!') + { + string++; + critical=1; + } + + for(i=0;i<strlen(string);i++) + if( !isascii (string[i]) || iscntrl(string[i])) + break; + + if(i==0 || i<strlen(string)) + { + if(which) + BUG(); + else + log_error(_("the given preferred keyserver URL is invalid\n")); + } + + if(which) + BUG(); + else + sl=add_to_strlist( &opt.sig_keyserver_url, string ); + + if(critical) + sl->flags |= 1; +} + + +static void +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 ) + { + char *tmp = line; + len += 100; + line = xmalloc_secure (len); + if (tmp) + { + memcpy (line, tmp, i); + xfree (tmp); + } + else + i=0; + } + if (read (fd, line + i, 1) != 1 || line[i] == '\n') + break; + } + line[i] = 0; + log_debug ("seskey: %s\n", line); + gpgrt_annotate_leaked_object (line); + opt.override_session_key = line; +} |