g10: Use es_fopen instead of open.
[gnupg.git] / g10 / gpg.c
index fd21fde..c54facb 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -16,7 +16,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -60,6 +60,7 @@
 #include "call-dirmngr.h"
 #include "tofu.h"
 #include "../common/init.h"
+#include "../common/mbox-util.h"
 #include "../common/shareddefs.h"
 
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
@@ -192,6 +193,11 @@ enum cmd_and_opt_values
     oWithKeygrip,
     oWithSecret,
     oWithWKDHash,
+    oWithColons,
+    oWithKeyData,
+    oWithTofuInfo,
+    oWithSigList,
+    oWithSigCheck,
     oAnswerYes,
     oAnswerNo,
     oKeyring,
@@ -218,6 +224,7 @@ enum cmd_and_opt_values
     oMarginalsNeeded,
     oMaxCertDepth,
     oLoadExtension,
+    oCompliance,
     oGnuPG,
     oRFC2440,
     oRFC4880,
@@ -226,6 +233,7 @@ enum cmd_and_opt_values
     oPGP6,
     oPGP7,
     oPGP8,
+    oDE_VS,
     oRFC2440Text,
     oNoRFC2440Text,
     oCipherAlgo,
@@ -258,10 +266,6 @@ enum cmd_and_opt_values
     oNoOptions,
     oNoBatch,
     oHomedir,
-    oWithColons,
-    oWithKeyData,
-    oWithSigList,
-    oWithSigCheck,
     oSkipVerify,
     oSkipHiddenRecipients,
     oNoSkipHiddenRecipients,
@@ -339,6 +343,7 @@ enum cmd_and_opt_values
     oIgnoreMDCError,
     oShowSessionKey,
     oOverrideSessionKey,
+    oOverrideSessionKeyFD,
     oNoRandomSeedFile,
     oAutoKeyRetrieve,
     oNoAutoKeyRetrieve,
@@ -406,6 +411,7 @@ enum cmd_and_opt_values
     oUnwrap,
     oOnlySignTextIDs,
     oDisableSignerUID,
+    oSender,
 
     oNoop
   };
@@ -525,6 +531,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oEncryptToDefaultKey, "encrypt-to-default-key", "@"),
   ARGPARSE_s_s (oLocalUser, "local-user",
                 N_("|USER-ID|use USER-ID to sign or decrypt")),
+  ARGPARSE_s_s (oSender, "sender", "@"),
 
   ARGPARSE_s_s (oTrySecretKey, "try-secret-key", "@"),
 
@@ -609,6 +616,7 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oLoadExtension, "load-extension", "@"),  /* Dummy.  */
 
+  ARGPARSE_s_s (oCompliance, "compliance",   "@"),
   ARGPARSE_s_n (oGnuPG, "gnupg",   "@"),
   ARGPARSE_s_n (oGnuPG, "no-pgp2", "@"),
   ARGPARSE_s_n (oGnuPG, "no-pgp6", "@"),
@@ -696,6 +704,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oHomedir, "homedir", "@"),
   ARGPARSE_s_n (oNoBatch, "no-batch", "@"),
   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", "@"),
@@ -768,6 +777,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oIgnoreMDCError, "ignore-mdc-error", "@"),
   ARGPARSE_s_n (oShowSessionKey, "show-session-key", "@"),
   ARGPARSE_s_s (oOverrideSessionKey, "override-session-key", "@"),
+  ARGPARSE_s_i (oOverrideSessionKeyFD, "override-session-key-fd", "@"),
   ARGPARSE_s_n (oNoRandomSeedFile,  "no-random-seed-file", "@"),
   ARGPARSE_s_n (oAutoKeyRetrieve, "auto-key-retrieve", "@"),
   ARGPARSE_s_n (oNoAutoKeyRetrieve, "no-auto-key-retrieve", "@"),
@@ -911,6 +921,7 @@ 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 *
@@ -1185,15 +1196,15 @@ set_debug (const char *level)
       g10_exit (2);
     }
 
-  if (opt.debug & DBG_MEMORY_VALUE )
+  if ((opt.debug & DBG_MEMORY_VALUE))
     memory_debug_mode = 1;
-  if (opt.debug & DBG_MEMSTAT_VALUE )
+  if ((opt.debug & DBG_MEMSTAT_VALUE))
     memory_stat_debug_mode = 1;
-  if (opt.debug & DBG_MPI_VALUE)
+  if (DBG_MPI)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
-  if (opt.debug & DBG_CRYPTO_VALUE )
+  if (DBG_CRYPTO)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
-  if (opt.debug & DBG_IOBUF_VALUE )
+  if ((opt.debug & DBG_IOBUF_VALUE))
     iobuf_debug_mode = 1;
   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
 
@@ -2005,7 +2016,7 @@ parse_tofu_policy (const char *policystr)
 
   if (!ascii_strcasecmp (policystr, "help"))
     {
-      log_info (_("available TOFU policies:\n"));
+      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);
@@ -2022,6 +2033,113 @@ parse_tofu_policy (const char *policystr)
   g10_exit (1);
 }
 
+
+/* Parse the value of --compliance.  */
+static int
+parse_compliance_option (const char *string)
+{
+  struct { const char *keyword; enum cmd_and_opt_values option; } list[] = {
+    { "gnupg",      oGnuPG },
+    { "openpgp",    oOpenPGP },
+    { "rfc4880bis", oRFC4880bis },
+    { "rfc4880",    oRFC4880 },
+    { "rfc2440",    oRFC2440 },
+    { "pgp6",       oPGP6 },
+    { "pgp7",       oPGP7 },
+    { "pgp8",       oPGP8 },
+    { "de-vs",      oDE_VS }
+  };
+  int i;
+
+  if (!ascii_strcasecmp (string, "help"))
+    {
+      log_info (_("valid values for option '%s':\n"), "--compliance");
+      for (i=0; i < DIM (list); i++)
+        log_info ("  %s\n", list[i].keyword);
+      g10_exit (1);
+    }
+
+  for (i=0; i < DIM (list); i++)
+    if (!ascii_strcasecmp (string, list[i].keyword))
+      return list[i].option;
+
+  log_error (_("invalid value for option '%s'\n"), "--compliance");
+  if (!opt.quiet)
+    log_info (_("(use \"help\" to list choices)\n"));
+  g10_exit (1);
+}
+
+
+
+/* Helper to set compliance related options.  This is a separte
+ * 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;
+      /* Fixme: Change other options.  */
+      break;
+
+    default:
+      BUG ();
+    }
+}
+
+
+
+
+
+
 /* This function called to initialized a new control object.  It is
    assumed that this object has been zeroed out before calling this
    function. */
@@ -2147,6 +2265,7 @@ main (int argc, char **argv)
     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 require_secmem = 0;
@@ -2171,7 +2290,7 @@ main (int argc, char **argv)
     gnupg_rl_initialize ();
     set_strusage (my_strusage);
     gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
-    log_set_prefix (GPG_NAME, 1);
+    log_set_prefix (GPG_NAME, GPGRT_LOG_WITH_PREFIX);
 
     /* Make sure that our subsystems are ready.  */
     i18n_init();
@@ -2312,7 +2431,7 @@ main (int argc, char **argv)
     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);
+    setup_libassuan_logging (&opt.debug, NULL);
 
     /* Try for a version specific config file first */
     default_configname = get_default_configname ();
@@ -2372,11 +2491,16 @@ main (int argc, char **argv)
       {
        switch( pargs.r_opt )
          {
-         case aCheckKeys:
          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:
@@ -2647,6 +2771,8 @@ main (int argc, char **argv)
          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;
 
@@ -2690,52 +2816,24 @@ main (int argc, char **argv)
             /* Dummy so that gpg 1.4 conf files can work. Should
                eventually be removed.  */
            break;
+
+          case oCompliance:
+            set_compliance_option (parse_compliance_option (pargs.r.ret_str));
+            break;
+          case oOpenPGP:
+          case oRFC2440:
+          case oRFC4880:
           case oRFC4880bis:
-            opt.flags.rfc4880bis = 1;
-            /* fall thru.  */
-         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 oRFC2440Text: opt.rfc2440_text=1; break;
-         case oNoRFC2440Text: opt.rfc2440_text=0; break;
+          case oPGP6:
+          case oPGP7:
+          case oPGP8:
+          case oGnuPG:
+            set_compliance_option (pargs.r_opt);
+            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;
@@ -2907,6 +3005,19 @@ main (int argc, char **argv)
             if (configfp)
               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;
@@ -3182,6 +3293,9 @@ main (int argc, char **argv)
          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,configlineno,"--merge-only",
                                   "--import-options ","merge-only");
@@ -3429,7 +3543,7 @@ main (int argc, char **argv)
     if (logfile && opt.batch)
       {
         log_set_file (logfile);
-        log_set_prefix (NULL, 1|2|4);
+        log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
       }
 
     if (opt.verbose > 2)
@@ -3749,8 +3863,11 @@ main (int argc, char **argv)
       g10_exit(0);
 
 
-    if( pwfd != -1 )  /* Read the passphrase now. */
-       read_passphrase_from_fd( pwfd );
+    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;
 
@@ -3769,6 +3886,8 @@ main (int argc, char **argv)
       case aGenRandom:
       case aDeArmor:
       case aEnArmor:
+      case aListConfig:
+      case aListGcryptConfig:
        break;
       case aFixTrustDB:
       case aExportOwnerTrust:
@@ -4644,6 +4763,8 @@ main (int argc, char **argv)
          if (! hd)
             g10_exit (1);
 
+          tofu_begin_batch_update (ctrl);
+
          for (i = 1; i < argc; i ++)
            {
              KEYDB_SEARCH_DESC desc;
@@ -4701,8 +4822,9 @@ main (int argc, char **argv)
                g10_exit (1);
            }
 
-         keydb_release (hd);
+          tofu_end_batch_update (ctrl);
 
+         keydb_release (hd);
        }
 #endif /*USE_TOFU*/
        break;
@@ -5100,3 +5222,34 @@ add_keyserver_url( const char *string, int which )
   if(critical)
     sl->flags |= 1;
 }
+
+
+static void
+read_sessionkey_from_fd (int fd)
+{
+  int i, len;
+  char *line;
+
+  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;
+}