[git] GnuPG - branch, master, updated. gnupg-2.1.15-23-g371ae66

by Neal H. Walfield cvs at cvs.gnupg.org
Tue Aug 30 16:07:08 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  371ae66e9d5c7524431773c4a479fcae1ea3b652 (commit)
       via  3beeaa70bdbde65f93adbb30d52b9c376963ac42 (commit)
       via  d0451440c036106895a291f9ca1c53c2d5159f8f (commit)
       via  6052c147091935fc0321ba24f4a44146df70ef01 (commit)
       via  33e97813d72996d22a295773c64261f5588ce9dd (commit)
       via  4c2abb221b29c9e8e0876fe986472b562ee1c99f (commit)
       via  0858f141a8b8d0c098a0c6097176b7225c4a9db8 (commit)
       via  8dda861ad80228da76cd5c97467008c87b8b6eee (commit)
      from  8b3e691ffbaaa218d309d5aaf8f37532308558ff (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 371ae66e9d5c7524431773c4a479fcae1ea3b652
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Aug 30 15:37:45 2016 +0200

    g10: Improve TOFU batch update code.
    
    * g10/gpg.h (tofu): Rename field batch_update_ref to
    batch_updated_wanted.
    * g10/tofu.c (struct tofu_dbs_s): Rename field batch_update to
    in_batch_transaction.
    (begin_transaction): Only end an extant batch transaction if we are
    not in a normal transaction.  When ending a batch transaction, really
    end it.  Update ctrl->tofu.batch_update_started when starting a batch
    transaction.
    (end_transaction): Only release a batch transaction if ONLY_BATCH is
    true.  When releasing a batch transaction, assert that there is no
    open normal transaction.  Only allow DBS to be NULL if ONLY_BATCH is
    true.
    (tofu_begin_batch_update): Don't update
    ctrl->tofu.batch_update_started.
    (opendbs): Call end_transaction unconditionally.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/gpg.h b/g10/gpg.h
index 154da0d..33a3af6 100644
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -83,7 +83,7 @@ struct server_control_s
   struct {
     tofu_dbs_t dbs;
     int    in_transaction;
-    int    batch_update_ref;
+    int    batch_updated_wanted;
     time_t batch_update_started;
   } tofu;
 
diff --git a/g10/tofu.c b/g10/tofu.c
index 338fb3e..f84609e 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -81,7 +81,7 @@ struct tofu_dbs_s
     sqlite3_stmt *register_insert;
   } s;
 
-  int batch_update;
+  int in_batch_transaction;
 };
 
 
@@ -169,26 +169,39 @@ begin_transaction (ctrl_t ctrl, int only_batch)
 
   log_assert (dbs);
 
-  if (ctrl->tofu.batch_update_ref
+  /* If we've been in batch update mode for a while (on average, more
+   * than 500 ms), to prevent starving other gpg processes, we drop
+   * and retake the batch lock.
+   *
+   * Note: if we wanted higher resolution, we could use
+   * npth_clock_gettime.  */
+  if (/* No real transactions.  */
+      ctrl->tofu.in_transaction == 0
+      /* There is an open batch transaction.  */
+      && dbs->in_batch_transaction
+      /* And some time has gone by since it was started.  */
       && ctrl->tofu.batch_update_started != gnupg_get_time ())
     {
-      /* We've been in batch update mode for a while (on average, more
-       * than 500 ms).  To prevent starving other gpg processes, we
-       * drop and retake the batch lock.
-       *
-       * Note: if we wanted higher resolution, we could use
-       * npth_clock_gettime.  */
-      if (dbs->batch_update)
-        end_transaction (ctrl, 1);
+      /* If we are in a batch update, then batch updates better have
+         been enabled.  */
+      log_assert (ctrl->tofu.batch_updated_wanted);
 
-      ctrl->tofu.batch_update_started = gnupg_get_time ();
+      end_transaction (ctrl, 2);
 
       /* Yield to allow another process a chance to run.  */
       gpgrt_yield ();
     }
 
-  if (ctrl->tofu.batch_update_ref && !dbs->batch_update)
+  if (/* Batch mode is enabled.  */
+      ctrl->tofu.batch_updated_wanted
+      /* But we don't have an open batch transaction.  */
+      && !dbs->in_batch_transaction)
     {
+      /* We are in batch mode, but we don't have an open batch
+       * transaction.  Since the batch save point must be the outer
+       * save point, it must be taken before the inner save point.  */
+      log_assert (ctrl->tofu.in_transaction == 0);
+
       rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_batch,
                           NULL, NULL, &err,
                           "savepoint batch;", SQLITE_ARG_END);
@@ -200,7 +213,8 @@ begin_transaction (ctrl_t ctrl, int only_batch)
           return gpg_error (GPG_ERR_GENERAL);
         }
 
-      dbs->batch_update = 1;
+      dbs->in_batch_transaction = 1;
+      ctrl->tofu.batch_update_started = gnupg_get_time ();
     }
 
   if (only_batch)
@@ -235,35 +249,44 @@ end_transaction (ctrl_t ctrl, int only_batch)
   int rc;
   char *err = NULL;
 
-  if (!dbs)
-    return 0;  /* Shortcut to allow for easier cleanup code.  */
-
-  if ((!ctrl->tofu.batch_update_ref || only_batch == 2) && dbs->batch_update)
+  if (only_batch)
     {
-      /* The batch transaction is still in open, but we left batch
-       * mode.  */
-      dbs->batch_update = 0;
+      if (!dbs)
+        return 0;  /* Shortcut to allow for easier cleanup code.  */
 
-      rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_batch_commit,
-                          NULL, NULL, &err,
-                          "release batch;", SQLITE_ARG_END);
-      if (rc)
+      /* If we are releasing the batch transaction, then we better not
+         be in a normal transaction.  */
+      log_assert (ctrl->tofu.in_transaction == 0);
+
+      if (/* Batch mode disabled?  */
+          (!ctrl->tofu.batch_updated_wanted || only_batch == 2)
+          /* But, we still have an open batch transaction?  */
+          && dbs->in_batch_transaction)
         {
-          log_error (_("error committing transaction on TOFU database: %s\n"),
-                     err);
-          sqlite3_free (err);
-          return gpg_error (GPG_ERR_GENERAL);
+          /* The batch transaction is still in open, but we've left
+           * batch mode.  */
+          dbs->in_batch_transaction = 0;
+
+          rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_batch_commit,
+                             NULL, NULL, &err,
+                             "release batch;", SQLITE_ARG_END);
+          if (rc)
+            {
+              log_error (_("error committing transaction on TOFU database: %s\n"),
+                         err);
+              sqlite3_free (err);
+              return gpg_error (GPG_ERR_GENERAL);
+            }
+
+          return 0;
         }
 
-      /* Releasing an outer transaction releases an open inner
-         transactions.  We're done.  */
       return 0;
     }
 
-  if (only_batch)
-    return 0;
-
+  log_assert (dbs);
   log_assert (ctrl->tofu.in_transaction > 0);
+
   rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
                            "release inner%d;", ctrl->tofu.in_transaction);
   if (rc)
@@ -287,8 +310,7 @@ rollback_transaction (ctrl_t ctrl)
   int rc;
   char *err = NULL;
 
-  if (!dbs)
-    return 0;  /* Shortcut to allow for easier cleanup code.  */
+  log_assert (dbs);
   log_assert (ctrl->tofu.in_transaction > 0);
 
   /* Be careful to not any progress made by closed transactions in
@@ -313,19 +335,16 @@ rollback_transaction (ctrl_t ctrl)
 void
 tofu_begin_batch_update (ctrl_t ctrl)
 {
-  if (!ctrl->tofu.batch_update_ref)
-    ctrl->tofu.batch_update_started = gnupg_get_time ();
-
-  ctrl->tofu.batch_update_ref ++;
+  ctrl->tofu.batch_updated_wanted ++;
 }
 
 void
 tofu_end_batch_update (ctrl_t ctrl)
 {
-  log_assert (ctrl->tofu.batch_update_ref > 0);
-  ctrl->tofu.batch_update_ref --;
+  log_assert (ctrl->tofu.batch_updated_wanted > 0);
+  ctrl->tofu.batch_updated_wanted --;
 
-  if (!ctrl->tofu.batch_update_ref)
+  if (!ctrl->tofu.batch_updated_wanted)
     end_transaction (ctrl, 1);
 }
 
@@ -693,14 +712,13 @@ tofu_closedbs (ctrl_t ctrl)
   tofu_dbs_t dbs;
   sqlite3_stmt **statements;
 
-  log_assert(ctrl->tofu.in_transaction == 0);
+  log_assert (ctrl->tofu.in_transaction == 0);
 
   dbs = ctrl->tofu.dbs;
   if (!dbs)
     return;  /* Not initialized.  */
 
-  if (dbs->batch_update)
-    end_transaction (ctrl, 2);
+  end_transaction (ctrl, 2);
 
   /* Arghh, that is a surprising use of the struct.  */
   for (statements = (void *) &dbs->s;

commit 3beeaa70bdbde65f93adbb30d52b9c376963ac42
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Aug 30 12:33:23 2016 +0200

    g10: Improve TOFU debugging output and some comments.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/tofu.c b/g10/tofu.c
index 055f68d..338fb3e 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -702,7 +702,7 @@ tofu_closedbs (ctrl_t ctrl)
   if (dbs->batch_update)
     end_transaction (ctrl, 2);
 
-  /* Arghh, that is asurprising use of the struct.  */
+  /* Arghh, that is a surprising use of the struct.  */
   for (statements = (void *) &dbs->s;
        (void *) statements < (void *) &(&dbs->s)[1];
        statements ++)
@@ -777,24 +777,25 @@ record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
       if (rc)
 	{
 	  log_debug ("TOFU: Error reading from binding database"
-		     " (reading policy for <%s, %s>): %s\n",
+		     " (reading policy for <key: %s, user id: %s>): %s\n",
 		     fingerprint, email, err);
 	  sqlite3_free (err);
 	}
-    }
 
-  if (DBG_TRUST)
-    {
-      if (policy_old != TOFU_POLICY_NONE)
-	log_debug ("Changing TOFU trust policy for binding <%s, %s>"
-		   " from %s to %s.\n",
-		   fingerprint, email,
-		   tofu_policy_str (policy_old),
-		   tofu_policy_str (policy));
-      else
-	log_debug ("Set TOFU trust policy for binding <%s, %s> to %s.\n",
-		   fingerprint, email,
-		   tofu_policy_str (policy));
+      if (DBG_TRUST)
+        {
+          if (policy_old != TOFU_POLICY_NONE)
+            log_debug ("Changing TOFU trust policy for binding"
+                       " <key: %s, user id: %s> from %s to %s.\n",
+                       fingerprint, email,
+                       tofu_policy_str (policy_old),
+                       tofu_policy_str (policy));
+          else
+            log_debug ("Setting TOFU trust policy for new binding"
+                       " <key: %s, user id: %s> to %s.\n",
+                       fingerprint, email,
+                       tofu_policy_str (policy));
+        }
     }
 
   if (policy_old == policy)
@@ -827,7 +828,7 @@ record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
   if (rc)
     {
       log_error (_("error updating TOFU database: %s\n"), err);
-      print_further_info (" insert bindings <%s, %s> = %s",
+      print_further_info (" insert bindings <key: %s, user id: %s> = %s",
                           fingerprint, email, tofu_policy_str (policy));
       sqlite3_free (err);
       goto leave;
@@ -1072,7 +1073,7 @@ get_policy (tofu_dbs_t dbs, const char *fingerprint, const char *email,
 
   /* If CONFLICT is set, then policy should be TOFU_POLICY_ASK.  But,
      just in case, we do the check again here and ignore the conflict
-     is POLICY is not TOFU_POLICY_ASK.  */
+     if POLICY is not TOFU_POLICY_ASK.  */
   if (conflict)
     {
       if (policy == TOFU_POLICY_ASK && *strlist->next->d)
@@ -1553,7 +1554,8 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
     {
       policy = opt.tofu_default_policy;
       if (DBG_TRUST)
-	log_debug ("TOFU: binding <%s, %s>'s policy is auto (default: %s).\n",
+	log_debug ("TOFU: binding <key: %s, user id: %s>'s policy is "
+                   " auto (default: %s).\n",
 		   fingerprint, email,
 		   tofu_policy_str (opt.tofu_default_policy));
     }
@@ -1566,7 +1568,7 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
       /* The saved judgement is auto -> auto, good, unknown or bad.
        * We don't need to ask the user anything.  */
       if (DBG_TRUST)
-	log_debug ("TOFU: Known binding <%s, %s>'s policy: %s\n",
+	log_debug ("TOFU: Known binding <key: %s, user id: %s>'s policy: %s\n",
 		   fingerprint, email, tofu_policy_str (policy));
       trust_level = tofu_policy_to_trust_level (policy);
       goto out;
@@ -1646,8 +1648,8 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
       log_assert (policy == TOFU_POLICY_NONE);
 
       if (DBG_TRUST)
-	log_debug ("TOFU: New binding <%s, %s>, no conflict.\n",
-		   email, fingerprint);
+	log_debug ("TOFU: New binding <key: %s, user id: %s>, no conflict.\n",
+		   fingerprint, email);
 
       if (record_binding (dbs, fingerprint, email, user_id,
 			  TOFU_POLICY_AUTO, 0) != 0)

commit d0451440c036106895a291f9ca1c53c2d5159f8f
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Aug 30 12:36:55 2016 +0200

    g10: If a key has no valid user ids, change TOFU to return TRUST_NEVER.
    
    * g10/tofu.c (tofu_get_validity): If a key has no valid (non-expired)
    user ids, change TOFU to return TRUST_NEVER.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/tofu.c b/g10/tofu.c
index da09cd5..055f68d 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -2444,6 +2444,8 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
   char *fingerprint = NULL;
   strlist_t user_id;
   int trust_level = TRUST_UNKNOWN;
+  int bindings = 0;
+  int bindings_valid = 0;
 
   dbs = opendbs (ctrl);
   if (! dbs)
@@ -2457,7 +2459,7 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
 
   begin_transaction (ctrl, 0);
 
-  for (user_id = user_id_list; user_id; user_id = user_id->next)
+  for (user_id = user_id_list; user_id; user_id = user_id->next, bindings ++)
     {
       char *email = email_from_user_id (user_id->d);
 
@@ -2481,6 +2483,9 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
       if (user_id->flags)
         tl = TRUST_EXPIRED;
 
+      if (tl != TRUST_EXPIRED)
+        bindings_valid ++;
+
       if (may_ask && tl != TRUST_ULTIMATE && tl != TRUST_EXPIRED)
         show_statistics (dbs, fingerprint, email, user_id->d, NULL, NULL);
 
@@ -2512,6 +2517,16 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
   end_transaction (ctrl, 0);
 
   xfree (fingerprint);
+
+  if (bindings_valid == 0)
+    {
+      if (DBG_TRUST)
+        log_debug ("no (of %d) valid bindings."
+                   "  Can't get TOFU validity for this set of user ids.\n",
+                   bindings);
+      return TRUST_NEVER;
+    }
+
   return trust_level;
 }
 

commit 6052c147091935fc0321ba24f4a44146df70ef01
Author: Neal H. Walfield <neal at g10code.com>
Date:   Mon Aug 29 16:16:44 2016 +0200

    g10: Change tofu_register & tofu_get_validity to process multiple uids.
    
    * g10/tofu.c (tofu_register): Take a list of user ids, not a single
    user id.  Only register the bindings, don't compute the trust.  Thus,
    change return type to an int and remove the may_ask parameter.  Update
    callers.
    (tofu_get_validity): Take a list of user ids, not a single user id.
    Update callers.  Observe signatures made by expired user ids, but
    don't include them in the trust calculation.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/tofu.c b/g10/tofu.c
index 809dac9..da09cd5 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -2164,8 +2164,9 @@ email_from_user_id (const char *user_id)
   return email;
 }
 
-/* Register the signature with the binding <fingerprint, USER_ID>.
-   The fingerprint is taken from the primary key packet PK.
+/* Register the signature with the bindings <fingerprint, USER_ID>,
+   for each USER_ID in USER_ID_LIST.  The fingerprint is taken from
+   the primary key packet PK.
 
    SIG_DIGEST_BIN is the binary representation of the message's
    digest.  SIG_DIGEST_BIN_LEN is its length.
@@ -2181,159 +2182,152 @@ email_from_user_id (const char *user_id)
    This is necessary if there is a conflict or the binding's policy is
    TOFU_POLICY_ASK.
 
-   This function returns the binding's trust level on return.  If an
-   error occurs, this function returns TRUST_UNKNOWN.  */
-int
-tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
+   This function returns 0 on success and an error code if an error
+   occured.  */
+gpg_error_t
+tofu_register (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
 	       const byte *sig_digest_bin, int sig_digest_bin_len,
-	       time_t sig_time, const char *origin, int may_ask)
+	       time_t sig_time, const char *origin)
 {
+  gpg_error_t rc;
   tofu_dbs_t dbs;
   char *fingerprint = NULL;
+  strlist_t user_id;
   char *email = NULL;
   char *err = NULL;
-  int rc;
-  int trust_level = TRUST_UNKNOWN;
   char *sig_digest;
   unsigned long c;
-  int already_verified = 0;
-
-  sig_digest = make_radix64_string (sig_digest_bin, sig_digest_bin_len);
 
   dbs = opendbs (ctrl);
   if (! dbs)
     {
+      rc = gpg_error (GPG_ERR_GENERAL);
       log_error (_("error opening TOFU database: %s\n"),
-                 gpg_strerror (GPG_ERR_GENERAL));
-      goto die;
+                 gpg_strerror (rc));
+      return rc;
     }
 
-  fingerprint = hexfingerprint (pk, NULL, 0);
-
-  if (! *user_id)
-    {
-      log_debug ("TOFU: user id is empty.  Can't continue.\n");
-      goto die;
-    }
+  /* We do a query and then an insert.  Make sure they are atomic
+     by wrapping them in a transaction.  */
+  rc = begin_transaction (ctrl, 0);
+  if (rc)
+    return rc;
 
-  email = email_from_user_id (user_id);
+  sig_digest = make_radix64_string (sig_digest_bin, sig_digest_bin_len);
+  fingerprint = hexfingerprint (pk, NULL, 0);
 
   if (! origin)
     /* The default origin is simply "unknown".  */
     origin = "unknown";
 
-  /* It's necessary to get the trust so that we are certain that the
-     binding has been registered.  */
-  trust_level = get_trust (dbs, pk, fingerprint, email, user_id, may_ask);
-  if (trust_level == _tofu_GET_TRUST_ERROR)
-    /* An error.  */
+  for (user_id = user_id_list; user_id; user_id = user_id->next)
     {
-      trust_level = TRUST_UNKNOWN;
-      goto die;
-    }
+      email = email_from_user_id (user_id->d);
 
-  /* We do a query and then an insert.  Make sure they are atomic
-     by wrapping them in a transaction.  */
-  rc = begin_transaction (ctrl, 0);
-  if (rc)
-    goto die;
-
-  /* If we've already seen this signature before, then don't add
-     it again.  */
-  rc = gpgsql_stepx
-    (dbs->db, &dbs->s.register_already_seen,
-     get_single_unsigned_long_cb2, &c, &err,
-     "select count (*)\n"
-     " from signatures left join bindings\n"
-     "  on signatures.binding = bindings.oid\n"
-     " where fingerprint = ? and email = ? and sig_time = ?\n"
-     "  and sig_digest = ?",
-     SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
-     SQLITE_ARG_LONG_LONG, (long long) sig_time,
-     SQLITE_ARG_STRING, sig_digest,
-     SQLITE_ARG_END);
-  if (rc)
-    {
-      log_error (_("error reading TOFU database: %s\n"), err);
-      print_further_info ("checking existence");
-      sqlite3_free (err);
-    }
-  else if (c > 1)
-    /* Duplicates!  This should not happen.  In particular,
-       because <fingerprint, email, sig_time, sig_digest> is the
-       primary key!  */
-    log_debug ("SIGNATURES DB contains duplicate records"
-	       " <%s, %s, 0x%lx, %s, %s>."
-	       "  Please report.\n",
-	       fingerprint, email, (unsigned long) sig_time,
-	       sig_digest, origin);
-  else if (c == 1)
-    {
-      already_verified = 1;
-      if (DBG_TRUST)
-	log_debug ("Already observed the signature"
-		   " <%s, %s, 0x%lx, %s, %s>\n",
-		   fingerprint, email, (unsigned long) sig_time,
-		   sig_digest, origin);
-    }
-  else if (opt.dry_run)
-    {
-      log_info ("TOFU database update skipped due to --dry-run\n");
-    }
-  else
-    /* This is the first time that we've seen this signature.
-       Record it.  */
-    {
       if (DBG_TRUST)
-	log_debug ("TOFU: Saving signature <%s, %s, %s>\n",
-		   fingerprint, email, sig_digest);
-
-      log_assert (c == 0);
+	log_debug ("TOFU: Registering signature %s with binding"
+                   " <key: %s, user id: %s>\n",
+		   sig_digest, fingerprint, email);
+
+      /* Make sure the binding exists and record any TOFU
+         conflicts.  */
+      if (get_trust (dbs, pk, fingerprint, email, user_id->d, 0)
+          == _tofu_GET_TRUST_ERROR)
+        {
+          rc = gpg_error (GPG_ERR_GENERAL);
+          xfree (email);
+          break;
+        }
 
+      /* If we've already seen this signature before, then don't add
+         it again.  */
       rc = gpgsql_stepx
-	(dbs->db, &dbs->s.register_insert, NULL, NULL, &err,
-	 "insert into signatures\n"
-	 " (binding, sig_digest, origin, sig_time, time)\n"
-	 " values\n"
-	 " ((select oid from bindings\n"
-	 "    where fingerprint = ? and email = ?),\n"
-	 "  ?, ?, ?, strftime('%s', 'now'));",
-	 SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
-         SQLITE_ARG_STRING, sig_digest, SQLITE_ARG_STRING, origin,
+        (dbs->db, &dbs->s.register_already_seen,
+         get_single_unsigned_long_cb2, &c, &err,
+         "select count (*)\n"
+         " from signatures left join bindings\n"
+         "  on signatures.binding = bindings.oid\n"
+         " where fingerprint = ? and email = ? and sig_time = ?\n"
+         "  and sig_digest = ?",
+         SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
          SQLITE_ARG_LONG_LONG, (long long) sig_time,
+         SQLITE_ARG_STRING, sig_digest,
          SQLITE_ARG_END);
       if (rc)
-	{
-	  log_error (_("error updating TOFU database: %s\n"), err);
-          print_further_info ("insert signatures");
-	  sqlite3_free (err);
-	}
+        {
+          log_error (_("error reading TOFU database: %s\n"), err);
+          print_further_info ("checking existence");
+          sqlite3_free (err);
+        }
+      else if (c > 1)
+        /* Duplicates!  This should not happen.  In particular,
+           because <fingerprint, email, sig_time, sig_digest> is the
+           primary key!  */
+        log_debug ("SIGNATURES DB contains duplicate records"
+                   " <key: %s, fingerprint: %s, time: 0x%lx, sig: %s,"
+                   " origin: %s>."
+                   "  Please report.\n",
+                   fingerprint, email, (unsigned long) sig_time,
+                   sig_digest, origin);
+      else if (c == 1)
+        {
+          if (DBG_TRUST)
+            log_debug ("Already observed the signature and binding"
+                       " <key: %s, user id: %s, time: 0x%lx, sig: %s,"
+                       " origin: %s>\n",
+                       fingerprint, email, (unsigned long) sig_time,
+                       sig_digest, origin);
+        }
+      else if (opt.dry_run)
+        {
+          log_info ("TOFU database update skipped due to --dry-run\n");
+        }
+      else
+        /* This is the first time that we've seen this signature and
+           binding.  Record it.  */
+        {
+          if (DBG_TRUST)
+            log_debug ("TOFU: Saving signature"
+                       " <key: %s, user id: %s, sig: %s>\n",
+                       fingerprint, email, sig_digest);
+
+          log_assert (c == 0);
+
+          rc = gpgsql_stepx
+            (dbs->db, &dbs->s.register_insert, NULL, NULL, &err,
+             "insert into signatures\n"
+             " (binding, sig_digest, origin, sig_time, time)\n"
+             " values\n"
+             " ((select oid from bindings\n"
+             "    where fingerprint = ? and email = ?),\n"
+             "  ?, ?, ?, strftime('%s', 'now'));",
+             SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+             SQLITE_ARG_STRING, sig_digest, SQLITE_ARG_STRING, origin,
+             SQLITE_ARG_LONG_LONG, (long long) sig_time,
+             SQLITE_ARG_END);
+          if (rc)
+            {
+              log_error (_("error updating TOFU database: %s\n"), err);
+              print_further_info ("insert signatures");
+              sqlite3_free (err);
+            }
+        }
+
+      xfree (email);
+
+      if (rc)
+        break;
     }
 
-  /* It only matters whether we abort or commit the transaction
-     (so long as we do something) if we execute the insert.  */
   if (rc)
-    rc = rollback_transaction (ctrl);
+    rollback_transaction (ctrl);
   else
     rc = end_transaction (ctrl, 0);
-  if (rc)
-    {
-      sqlite3_free (err);
-      goto die;
-    }
 
- die:
-  if (may_ask && trust_level != TRUST_ULTIMATE)
-    /* It's only appropriate to show the statistics in an interactive
-       context.  */
-    show_statistics (dbs, fingerprint, email, user_id,
-		     already_verified ? NULL : sig_digest, NULL);
-
-  xfree (email);
   xfree (fingerprint);
   xfree (sig_digest);
 
-  return trust_level;
+  return rc;
 }
 
 /* Combine a trust level returned from the TOFU trust model with a
@@ -2431,8 +2425,9 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
 }
 
 
-/* Return the validity (TRUST_NEVER, etc.) of the binding
-   <FINGERPRINT, USER_ID>.
+/* Return the validity (TRUST_NEVER, etc.) of the bindings
+   <FINGERPRINT, USER_ID>, for each USER_ID in USER_ID_LIST.  If
+   USER_ID_LIST->FLAG is set, then the id is considered to be expired.
 
    PK is the primary key packet.
 
@@ -2442,43 +2437,80 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
 
    Returns TRUST_UNDEFINED if an error occurs.  */
 int
-tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
+tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
 		   int may_ask)
 {
   tofu_dbs_t dbs;
   char *fingerprint = NULL;
-  char *email = NULL;
-  int trust_level = TRUST_UNDEFINED;
+  strlist_t user_id;
+  int trust_level = TRUST_UNKNOWN;
 
   dbs = opendbs (ctrl);
   if (! dbs)
     {
       log_error (_("error opening TOFU database: %s\n"),
                  gpg_strerror (GPG_ERR_GENERAL));
-      goto die;
+      return TRUST_UNDEFINED;
     }
 
   fingerprint = hexfingerprint (pk, NULL, 0);
 
-  if (! *user_id)
+  begin_transaction (ctrl, 0);
+
+  for (user_id = user_id_list; user_id; user_id = user_id->next)
     {
-      log_debug ("user id is empty."
-                 "  Can't get TOFU validity for this binding.\n");
-      goto die;
-    }
+      char *email = email_from_user_id (user_id->d);
 
-  email = email_from_user_id (user_id);
+      /* Always call get_trust to make sure the binding is
+         registered.  */
+      int tl = get_trust (dbs, pk, fingerprint, email, user_id->d, may_ask);
+      if (tl == _tofu_GET_TRUST_ERROR)
+        {
+          /* An error.  */
+          trust_level = TRUST_UNDEFINED;
+          xfree (email);
+          goto die;
+        }
 
-  trust_level = get_trust (dbs, pk, fingerprint, email, user_id, may_ask);
-  if (trust_level == _tofu_GET_TRUST_ERROR)
-    /* An error.  */
-    trust_level = TRUST_UNDEFINED;
+      if (DBG_TRUST)
+	log_debug ("TOFU: validity for <key: %s, user id: %s>: %s%s.\n",
+		   fingerprint, email,
+                   trust_value_to_string (tl),
+                   user_id->flags ? " (but expired)" : "");
+
+      if (user_id->flags)
+        tl = TRUST_EXPIRED;
 
-  if (may_ask && trust_level != TRUST_ULTIMATE)
-    show_statistics (dbs, fingerprint, email, user_id, NULL, NULL);
+      if (may_ask && tl != TRUST_ULTIMATE && tl != TRUST_EXPIRED)
+        show_statistics (dbs, fingerprint, email, user_id->d, NULL, NULL);
+
+      if (tl == TRUST_NEVER)
+        trust_level = TRUST_NEVER;
+      else if (tl == TRUST_EXPIRED)
+        /* Ignore expired bindings in the trust calculation.  */
+        ;
+      else if (tl > trust_level)
+        {
+          /* The expected values: */
+          log_assert (tl == TRUST_UNKNOWN || tl == TRUST_UNDEFINED
+                      || tl == TRUST_MARGINAL || tl == TRUST_FULLY
+                      || tl == TRUST_ULTIMATE);
+
+          /* We assume the following ordering:  */
+          log_assert (TRUST_UNKNOWN < TRUST_UNDEFINED);
+          log_assert (TRUST_UNDEFINED < TRUST_MARGINAL);
+          log_assert (TRUST_MARGINAL < TRUST_FULLY);
+          log_assert (TRUST_FULLY < TRUST_ULTIMATE);
+
+          trust_level = tl;
+        }
+
+      xfree (email);
+    }
 
  die:
-  xfree (email);
+  end_transaction (ctrl, 0);
+
   xfree (fingerprint);
   return trust_level;
 }
diff --git a/g10/tofu.h b/g10/tofu.h
index d6854e9..b9826c9 100644
--- a/g10/tofu.h
+++ b/g10/tofu.h
@@ -59,7 +59,7 @@ enum tofu_policy
     TOFU_POLICY_ASK = 5,
 
 
-    /* Privat evalue used only within tofu.c.  */
+    /* Private value used only within tofu.c.  */
     _tofu_GET_POLICY_ERROR = 100
   };
 
@@ -72,16 +72,19 @@ const char *tofu_policy_str (enum tofu_policy policy);
    (e.g., TRUST_BAD) in light of the current configuration.  */
 int tofu_policy_to_trust_level (enum tofu_policy policy);
 
-/* Register the binding <PK, USER_ID> and the signature
-   described by SIGS_DIGEST and SIG_TIME, which it generated.  Origin
-   describes where the signed data came from, e.g., "email:claws"
-   (default: "unknown").  If MAY_ASK is 1, then this function may
-   interact with the user in the case of a conflict or if the
-   binding's policy is ask.  This function returns the binding's trust
-   level.  If an error occurs, it returns TRUST_UNKNOWN.  */
-int tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
-		   const byte *sigs_digest, int sigs_digest_len,
-		   time_t sig_time, const char *origin, int may_ask);
+/* Register the bindings <PK, USER_ID>, for each USER_ID in
+   USER_ID_LIST, and the signature described by SIGS_DIGEST and
+   SIG_TIME, which it generated.  Origin describes where the signed
+   data came from, e.g., "email:claws" (default: "unknown").  Note:
+   this function does not interact with the user, If there is a
+   conflict, or if the binding's policy is ask, the actual interaction
+   is deferred until tofu_get_validity is called..  Set the string
+   list FLAG to indicate that a specified user id is expired.  This
+   function returns 0 on success and an error code on failure.  */
+gpg_error_t tofu_register (ctrl_t ctrl, PKT_public_key *pk,
+                           strlist_t user_id_list,
+                           const byte *sigs_digest, int sigs_digest_len,
+                           time_t sig_time, const char *origin);
 
 /* Combine a trust level returned from the TOFU trust model with a
    trust level returned by the PGP trust model.  This is primarily of
@@ -92,12 +95,15 @@ int tofu_wot_trust_combine (int tofu, int wot);
 gpg_error_t tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
                                    PKT_public_key *pk, const char *user_id);
 
-/* Determine the validity (TRUST_NEVER, etc.) of the binding
-   <PK, USER_ID>.  If MAY_ASK is 1, then this function may
-   interact with the user.  If not, TRUST_UNKNOWN is returned.  If an
-   error occurs, TRUST_UNDEFINED is returned.  */
+/* Determine the validity (TRUST_NEVER, etc.) of the binding <PK,
+   USER_ID>.  If MAY_ASK is 1, then this function may interact with
+   the user.  If not, TRUST_UNKNOWN is returned if an interaction is
+   required.  Set the string list FLAGS to indicate that a specified
+   user id is expired.  If an error occurs, TRUST_UNDEFINED is
+   returned.  */
 int tofu_get_validity (ctrl_t ctrl,
-                       PKT_public_key *pk, const char *user_id, int may_ask);
+                       PKT_public_key *pk, strlist_t user_id_list,
+                       int may_ask);
 
 /* Set the policy for all non-revoked user ids in the keyblock KB to
    POLICY.  */
diff --git a/g10/trustdb.c b/g10/trustdb.c
index dd74d18..4181240 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -988,7 +988,7 @@ tdb_get_validity_core (ctrl_t ctrl,
 		       int may_ask)
 {
   TRUSTREC trec, vrec;
-  gpg_error_t err;
+  gpg_error_t err = 0;
   ulong recno;
 #ifdef USE_TOFU
   unsigned int tofu_validity = TRUST_UNKNOWN;
@@ -1022,21 +1022,18 @@ tdb_get_validity_core (ctrl_t ctrl,
 #ifdef USE_TOFU
   if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
     {
-      kbnode_t user_id_node = NULL;
-      kbnode_t n = NULL;	/* Silence -Wmaybe-uninitialized.  */
-      int user_ids = 0;
-      int user_ids_expired = 0;
+      kbnode_t kb = NULL;
+      kbnode_t n = NULL;
+      strlist_t user_id_list = NULL;
 
-      /* If the caller didn't supply a user id then iterate over all
-	 uids.  */
+      /* If the caller didn't supply a user id then use all uids.  */
       if (! uid)
-	user_id_node = n = get_pubkeyblock (main_pk->keyid);
+	kb = n = get_pubkeyblock (main_pk->keyid);
 
-      while (uid
-	     || (n = find_next_kbnode (n, PKT_USER_ID)))
+      while (uid || (n = find_next_kbnode (n, PKT_USER_ID)))
 	{
-	  unsigned int tl;
 	  PKT_user_id *user_id;
+          int expired = 0;
 
 	  if (uid)
 	    user_id = uid;
@@ -1044,8 +1041,8 @@ tdb_get_validity_core (ctrl_t ctrl,
 	    user_id = n->pkt->pkt.user_id;
 
           /* If the user id is revoked or expired, then skip it.  */
-	  if (user_id->is_revoked || user_id->is_expired)
-	    {
+          if (user_id->is_revoked || user_id->is_expired)
+            {
               if (DBG_TRUST)
                 {
                   char *s;
@@ -1060,42 +1057,48 @@ tdb_get_validity_core (ctrl_t ctrl,
                              s, user_id->name);
                 }
 
-	      continue;
-	    }
+              if (user_id->is_revoked)
+                continue;
 
-	  user_ids ++;
+              expired = 1;
+            }
 
-	  if (sig)
-	    tl = tofu_register (ctrl, main_pk, user_id->name,
-				sig->digest, sig->digest_len,
-				sig->timestamp, "unknown",
-				may_ask);
-	  else
-	    tl = tofu_get_validity (ctrl, main_pk, user_id->name, may_ask);
-
-	  if (tl == TRUST_EXPIRED)
-	    user_ids_expired ++;
-	  else if (tl == TRUST_UNDEFINED || tl == TRUST_UNKNOWN)
-	    ;
-	  else if (tl == TRUST_NEVER)
-	    tofu_validity = TRUST_NEVER;
-	  else
-	    {
-	      log_assert (tl == TRUST_MARGINAL
-                          || tl == TRUST_FULLY
-                          || tl == TRUST_ULTIMATE);
+          add_to_strlist (&user_id_list, user_id->name);
+          user_id_list->flags = expired;
 
-	      if (tl > tofu_validity)
-		/* XXX: We we really want the max?  */
-		tofu_validity = tl;
-	    }
+          if (uid)
+            /* If the caller specified a user id, then we stop
+               now.  */
+            break;
+        }
 
-	  if (uid)
-	    /* If the caller specified a user id, then we stop
-	       now.  */
-	    break;
-	}
-      release_kbnode (user_id_node);
+      /* Process the user ids in the order they appear in the key
+         block.  */
+      strlist_rev (&user_id_list);
+
+      /* It only makes sense to observe any signature before getting
+         the validity.  This is because if the current signature
+         results in a conflict, then we damn well want to take that
+         into account.  */
+      if (sig)
+        {
+          err = tofu_register (ctrl, main_pk, user_id_list,
+                               sig->digest, sig->digest_len,
+                               sig->timestamp, "unknown");
+          if (err)
+            {
+              log_error ("TOFU: error registering signature: %s\n",
+                         gpg_strerror (err));
+
+              tofu_validity = TRUST_UNKNOWN;
+            }
+        }
+      if (! err)
+        tofu_validity = tofu_get_validity (ctrl, main_pk, user_id_list,
+                                           may_ask);
+
+      free_strlist (user_id_list);
+      release_kbnode (kb);
     }
 #endif /*USE_TOFU*/
 

commit 33e97813d72996d22a295773c64261f5588ce9dd
Author: Neal H. Walfield <neal at g10code.com>
Date:   Mon Aug 29 15:13:45 2016 +0200

    g10: Support nested transactions on the TOFU DB.
    
    * g10/gpg.h (struct server_control_s): New field in_transaction.
    * g10/tofu.c (struct tofu_dbs_s): Remove fields savepoint_inner and
    savepoint_inner_commit.
    (begin_transaction): Increment CTRL->TOFU.IN_TRANSACTION.  Name the
    savepoint according to the nesting level.
    (end_transaction): Name the savepoint according to the nesting level.
    Decrement CTRL->TOFU.IN_TRANSACTION.
    (rollback_transaction): Likewise.  Only ever rollback a non-batch
    transaction.
    (opendbs): Assert that there are no outstanding transactions.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/gpg.h b/g10/gpg.h
index 1aaff2f..154da0d 100644
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -82,6 +82,7 @@ struct server_control_s
   /* Local data for tofu.c  */
   struct {
     tofu_dbs_t dbs;
+    int    in_transaction;
     int    batch_update_ref;
     time_t batch_update_started;
   } tofu;
diff --git a/g10/tofu.c b/g10/tofu.c
index e15b564..809dac9 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -70,9 +70,6 @@ struct tofu_dbs_s
     sqlite3_stmt *savepoint_batch;
     sqlite3_stmt *savepoint_batch_commit;
 
-    sqlite3_stmt *savepoint_inner;
-    sqlite3_stmt *savepoint_inner_commit;
-
     sqlite3_stmt *record_binding_get_old_policy;
     sqlite3_stmt *record_binding_update;
     sqlite3_stmt *record_binding_update2;
@@ -209,9 +206,12 @@ begin_transaction (ctrl_t ctrl, int only_batch)
   if (only_batch)
     return 0;
 
-  rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_inner,
-                      NULL, NULL, &err,
-                      "savepoint inner;", SQLITE_ARG_END);
+  log_assert(ctrl->tofu.in_transaction >= 0);
+  ctrl->tofu.in_transaction ++;
+
+  rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
+                           "savepoint inner%d;",
+                           ctrl->tofu.in_transaction);
   if (rc)
     {
       log_error (_("error beginning transaction on TOFU database: %s\n"),
@@ -263,9 +263,9 @@ end_transaction (ctrl_t ctrl, int only_batch)
   if (only_batch)
     return 0;
 
-  rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_inner_commit,
-                      NULL, NULL, &err,
-                      "release inner;", SQLITE_ARG_END);
+  log_assert (ctrl->tofu.in_transaction > 0);
+  rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
+                           "release inner%d;", ctrl->tofu.in_transaction);
   if (rc)
     {
       log_error (_("error committing transaction on TOFU database: %s\n"),
@@ -274,6 +274,8 @@ end_transaction (ctrl_t ctrl, int only_batch)
       return gpg_error (GPG_ERR_GENERAL);
     }
 
+  ctrl->tofu.in_transaction --;
+
   return 0;
 }
 
@@ -287,18 +289,15 @@ rollback_transaction (ctrl_t ctrl)
 
   if (!dbs)
     return 0;  /* Shortcut to allow for easier cleanup code.  */
+  log_assert (ctrl->tofu.in_transaction > 0);
 
-  if (dbs->batch_update)
-    {
-      /* Just undo the most recent update; don't revert any progress
-         made by the batch transaction.  */
-      rc = sqlite3_exec (dbs->db, "rollback to inner;", NULL, NULL, &err);
-    }
-  else
-    {
-      /* Rollback the whole she-bang.  */
-      rc = sqlite3_exec (dbs->db, "rollback;", NULL, NULL, &err);
-    }
+  /* Be careful to not any progress made by closed transactions in
+     batch mode.  */
+  rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
+                           "rollback to inner%d;",
+                           ctrl->tofu.in_transaction);
+
+  ctrl->tofu.in_transaction --;
 
   if (rc)
     {
@@ -694,6 +693,8 @@ tofu_closedbs (ctrl_t ctrl)
   tofu_dbs_t dbs;
   sqlite3_stmt **statements;
 
+  log_assert(ctrl->tofu.in_transaction == 0);
+
   dbs = ctrl->tofu.dbs;
   if (!dbs)
     return;  /* Not initialized.  */

commit 4c2abb221b29c9e8e0876fe986472b562ee1c99f
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Aug 30 11:29:52 2016 +0200

    g10: Print the info text in more situations.
    
    * g10/tofu.c (ask_about_binding): Print the info text when the policy
    is ask and there are multiple bindings with the email address.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/tofu.c b/g10/tofu.c
index e433f79..e15b564 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -1372,7 +1372,8 @@ ask_about_binding (tofu_dbs_t dbs,
 
 
   if ((*policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0)
-      || (*policy == TOFU_POLICY_ASK && conflict))
+      || (*policy == TOFU_POLICY_ASK
+          && (conflict || bindings_with_this_email_count > 0)))
     {
       /* This is a conflict.  */
 

commit 0858f141a8b8d0c098a0c6097176b7225c4a9db8
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Aug 30 11:28:17 2016 +0200

    g10: Print the formatted text.
    
    * g10/tofu.c (ask_about_binding): Print the formatted text, not the
    unformatted text.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/tofu.c b/g10/tofu.c
index 9d562c2..e433f79 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -1393,7 +1393,7 @@ ask_about_binding (tofu_dbs_t dbs,
             "call the person to make sure this new key is legitimate.";
         }
       textbuf = format_text (text, 0, 72, 80);
-      es_fprintf (fp, "\n%s\n", text);
+      es_fprintf (fp, "\n%s\n", textbuf);
       xfree (textbuf);
     }
 

commit 8dda861ad80228da76cd5c97467008c87b8b6eee
Author: Neal H. Walfield <neal at g10code.com>
Date:   Mon Aug 29 14:05:16 2016 +0200

    g10: When showing a user id's trust, pass the current signature.
    
    * g10/mainproc.c (check_sig_and_print): Consistently pass SIG to
    get_validity.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/mainproc.c b/g10/mainproc.c
index 3d3f88b..2626189 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -1943,7 +1943,7 @@ check_sig_and_print (CTX c, kbnode_t node)
 	     does not print a LF we need to compute the validity
 	     before calling that function.  */
           if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY))
-            valid = get_validity (c->ctrl, pk, un->pkt->pkt.user_id, NULL, 0);
+            valid = get_validity (c->ctrl, pk, un->pkt->pkt.user_id, sig, 0);
           else
             valid = 0; /* Not used.  */
 

-----------------------------------------------------------------------

Summary of changes:
 g10/gpg.h      |   3 +-
 g10/mainproc.c |   2 +-
 g10/tofu.c     | 513 ++++++++++++++++++++++++++++++++-------------------------
 g10/tofu.h     |  38 +++--
 g10/trustdb.c  |  93 ++++++-----
 5 files changed, 364 insertions(+), 285 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list