gpg: Make function mk_datestr public.
[gnupg.git] / g10 / tofu.c
index 449e921..c183fc6 100644 (file)
 #include <time.h>
 
 #include "gpg.h"
-#include "types.h"
-#include "logging.h"
-#include "stringhelp.h"
+#include "../common/types.h"
+#include "../common/logging.h"
+#include "../common/stringhelp.h"
 #include "options.h"
-#include "mbox-util.h"
-#include "i18n.h"
-#include "ttyio.h"
+#include "../common/mbox-util.h"
+#include "../common/i18n.h"
+#include "../common/ttyio.h"
 #include "trustdb.h"
-#include "mkdir_p.h"
+#include "../common/mkdir_p.h"
 #include "gpgsql.h"
-#include "status.h"
-#include "sqrtu32.h"
+#include "../common/status.h"
 
 #include "tofu.h"
 
@@ -1305,7 +1304,7 @@ signature_stats_collect_cb (void *cookie, int argc, char **argv,
 }
 
 /* Format the first part of a conflict message and return that as a
- * malloced string.  */
+ * malloced string. Returns NULL on error. */
 static char *
 format_conflict_msg_part1 (int policy, strlist_t conflict_set,
                            const char *email)
@@ -1355,7 +1354,7 @@ format_conflict_msg_part1 (int policy, strlist_t conflict_set,
   es_fputc (0, fp);
   if (es_fclose_snatch (fp, (void **)&tmpstr, NULL))
     log_fatal ("error snatching memory stream\n");
-  text = format_text (tmpstr, 0, 72, 80);
+  text = format_text (tmpstr, 72, 80);
   es_free (tmpstr);
 
   return text;
@@ -1573,7 +1572,7 @@ ask_about_binding (ctrl_t ctrl,
   struct signature_stats *stats = NULL;
   struct signature_stats *stats_iter = NULL;
   char *prompt = NULL;
-  char *choices;
+  const char *choices;
 
   dbs = ctrl->tofu.dbs;
   log_assert (dbs);
@@ -1586,6 +1585,10 @@ ask_about_binding (ctrl_t ctrl,
 
   {
     char *text = format_conflict_msg_part1 (*policy, conflict_set, email);
+    if (!text) /* FIXME: Return the error all the way up.  */
+      log_fatal ("format failed: %s\n",
+                 gpg_strerror (gpg_error_from_syserror()));
+
     es_fputs (text, fp);
     es_fputc ('\n', fp);
     xfree (text);
@@ -1782,12 +1785,12 @@ ask_about_binding (ctrl_t ctrl,
               if ((binding->flags & BINDING_REVOKED))
                 {
                   es_fprintf (fp, _("revoked"));
-                  es_fprintf (fp, _(", "));
+                  es_fprintf (fp, ", ");
                 }
               else if ((binding->flags & BINDING_EXPIRED))
                 {
                   es_fprintf (fp, _("expired"));
-                  es_fprintf (fp, _(", "));
+                  es_fprintf (fp, ", ");
                 }
 
               if (this_key)
@@ -1913,7 +1916,7 @@ ask_about_binding (ctrl_t ctrl,
       /* TRANSLATORS: Please translate the text found in the source
        * file below.  We don't directly internationalize that text so
        * that we can tweak it without breaking translations.  */
-      char *text = _("TOFU detected a binding conflict");
+      const char *text = _("TOFU detected a binding conflict");
       char *textbuf;
       if (!strcmp (text, "TOFU detected a binding conflict"))
         {
@@ -1926,8 +1929,8 @@ ask_about_binding (ctrl_t ctrl,
             "attack!  Before accepting this association, you should talk to or "
             "call the person to make sure this new key is legitimate.";
         }
-      textbuf = format_text (text, 0, 72, 80);
-      es_fprintf (fp, "\n%s\n", textbuf);
+      textbuf = format_text (text, 72, 80);
+      es_fprintf (fp, "\n%s\n", textbuf? textbuf : "[OUT OF CORE!]");
       xfree (textbuf);
     }
 
@@ -1941,7 +1944,7 @@ ask_about_binding (ctrl_t ctrl,
   /* I think showing the large message once is sufficient.  If we
    * would move it right before the cpr_get many lines will scroll
    * away and the user might not realize that he merely entered a
-   * wrong choise (because he does not see that either).  As a small
+   * wrong choice (because he does not see that either).  As a small
    * benefit we allow C-L to redisplay everything.  */
   tty_printf ("%s", prompt);
 
@@ -2031,7 +2034,7 @@ ask_about_binding (ctrl_t ctrl,
    email> (including the binding itself, which will be first in the
    list).  For each returned key also sets BINDING_NEW, etc.  */
 static strlist_t
-build_conflict_set (tofu_dbs_t dbs,
+build_conflict_set (ctrl_t ctrl, tofu_dbs_t dbs,
                     PKT_public_key *pk, const char *fingerprint,
                     const char *email)
 {
@@ -2174,7 +2177,7 @@ build_conflict_set (tofu_dbs_t dbs,
           continue;
         }
 
-      merge_keys_and_selfsig (kb);
+      merge_keys_and_selfsig (ctrl, kb);
 
       log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
 
@@ -2209,9 +2212,9 @@ build_conflict_set (tofu_dbs_t dbs,
             {
               found_user_id = 1;
 
-              if (user_id2->is_revoked)
+              if (user_id2->flags.revoked)
                 iter->flags |= BINDING_REVOKED;
-              if (user_id2->is_expired)
+              if (user_id2->flags.expired)
                 iter->flags |= BINDING_EXPIRED;
             }
 
@@ -2239,7 +2242,7 @@ build_conflict_set (tofu_dbs_t dbs,
     if (!die)
       {
         /*err = gpg_error_from_syserror ();*/
-        xoutofcore (); /* Fixme: Let the fucntion return an error.  */
+        xoutofcore (); /* Fixme: Let the function return an error.  */
       }
 
     for (i = 0; i < conflict_set_count; i ++)
@@ -2304,15 +2307,20 @@ build_conflict_set (tofu_dbs_t dbs,
 
 
 /* Return the effective policy for the binding <FINGERPRINT, EMAIL>
- * (email has already been normalized) and any conflict information in
- * *CONFLICT_SETP, if CONFLICT_SETP is not NULL.  Returns
- * _tofu_GET_POLICY_ERROR if an error occurs.
+ * (email has already been normalized).  Returns
+ * _tofu_GET_POLICY_ERROR if an error occurs.  Returns any conflict
+ * information in *CONFLICT_SETP if CONFLICT_SETP is not NULL and the
+ * returned policy is TOFU_POLICY_ASK (consequently, if there is a
+ * conflict, but the user set the policy to good *CONFLICT_SETP will
+ * empty).  Note: as per build_conflict_set, which is used to build
+ * the conflict information, the conflict information includes the
+ * current user id as the first element of the linked list.
  *
  * This function registers the binding in the bindings table if it has
  * not yet been registered.
  */
 static enum tofu_policy
-get_policy (tofu_dbs_t dbs, PKT_public_key *pk,
+get_policy (ctrl_t ctrl, tofu_dbs_t dbs, PKT_public_key *pk,
             const char *fingerprint, const char *user_id, const char *email,
            strlist_t *conflict_setp, time_t now)
 {
@@ -2478,7 +2486,7 @@ get_policy (tofu_dbs_t dbs, PKT_public_key *pk,
         int lookup_err;
         kbnode_t kb;
 
-        lookup_err = get_pubkey_byfprint (NULL, &kb,
+        lookup_err = get_pubkey_byfprint (ctrl, NULL, &kb,
                                           fingerprint_raw,
                                           fingerprint_raw_len);
         if (lookup_err)
@@ -2504,7 +2512,7 @@ get_policy (tofu_dbs_t dbs, PKT_public_key *pk,
    * disappeared.  The latter can happen if the conflicting bindings
    * are now cross signed, for instance.  */
 
-  conflict_set = build_conflict_set (dbs, pk, fingerprint, email);
+  conflict_set = build_conflict_set (ctrl, dbs, pk, fingerprint, email);
   conflict_set_count = strlist_length (conflict_set);
   if (conflict_set_count == 0)
     {
@@ -2610,7 +2618,7 @@ get_policy (tofu_dbs_t dbs, PKT_public_key *pk,
   if (effective_policy == TOFU_POLICY_ASK && conflict_setp)
     {
       if (! conflict_set)
-        conflict_set = build_conflict_set (dbs, pk, fingerprint, email);
+        conflict_set = build_conflict_set (ctrl, dbs, pk, fingerprint, email);
       *conflict_setp = conflict_set;
     }
   else
@@ -2686,9 +2694,18 @@ get_trust (ctrl_t ctrl, PKT_public_key *pk,
 
   /* We need to call get_policy even if the key is ultimately trusted
    * to make sure the binding has been registered.  */
-  policy = get_policy (dbs, pk, fingerprint, user_id, email,
+  policy = get_policy (ctrl, dbs, pk, fingerprint, user_id, email,
                        &conflict_set, now);
 
+  if (policy == TOFU_POLICY_ASK)
+    /* The conflict set should always contain at least one element:
+     * the current key.  */
+    log_assert (conflict_set);
+  else
+    /* If the policy is not TOFU_POLICY_ASK, then conflict_set will be
+     * NULL.  */
+    log_assert (! conflict_set);
+
   /* If the key is ultimately trusted, there is nothing to do.  */
   {
     u32 kid[2];
@@ -2710,6 +2727,14 @@ get_trust (ctrl_t ctrl, PKT_public_key *pk,
                    " auto (default: %s).\n",
                   fingerprint, email,
                   tofu_policy_str (opt.tofu_default_policy));
+
+      if (policy == TOFU_POLICY_ASK)
+        /* The default policy is ASK, but there is no conflict (policy
+         * was 'auto').  In this case, we need to make sure the
+         * conflict set includes at least the current user id.  */
+        {
+          add_to_strlist (&conflict_set, fingerprint);
+        }
     }
   switch (policy)
     {
@@ -2896,19 +2921,18 @@ write_stats_status (estream_t fp,
 {
   int summary;
   int validity;
-  unsigned long days;
+  unsigned long days_sq;
 
   /* Use the euclidean distance (m = sqrt(a^2 + b^2)) rather then the
      sum of the magnitudes (m = a + b) to ensure a balance between
      verified signatures and encrypted messages.  */
-  days = sqrtu32 (signature_days * signature_days
-                  + encryption_days * encryption_days);
+  days_sq = signature_days * signature_days + encryption_days * encryption_days;
 
-  if (days < 1)
+  if (days_sq < 1)
     validity = 1; /* Key without history.  */
-  else if (days < 2 * BASIC_TRUST_THRESHOLD)
+  else if (days_sq < (2 * BASIC_TRUST_THRESHOLD) * (2 * BASIC_TRUST_THRESHOLD))
     validity = 2; /* Key with too little history.  */
-  else if (days < 2 * FULL_TRUST_THRESHOLD)
+  else if (days_sq < (2 * FULL_TRUST_THRESHOLD) * (2 * FULL_TRUST_THRESHOLD))
     validity = 3; /* Key with enough history for basic trust.  */
   else
     validity = 4; /* Key with a lot of history.  */
@@ -2949,7 +2973,7 @@ write_stats_status (estream_t fp,
  *
  * POLICY is the key's policy (as returned by get_policy).
  *
- * Returns 0 if if ONLY_STATUS_FD is set.  Otherwise, returns whether
+ * Returns 0 if ONLY_STATUS_FD is set.  Otherwise, returns whether
  * the caller should call show_warning after iterating over all user
  * ids.
  */
@@ -3168,7 +3192,10 @@ show_statistics (tofu_dbs_t dbs,
         es_fputc (0, fp);
         if (es_fclose_snatch (fp, (void **) &tmpmsg, NULL))
           log_fatal ("error snatching memory stream\n");
-        msg = format_text (tmpmsg, 0, 72, 80);
+        msg = format_text (tmpmsg, 72, 80);
+        if (!msg) /* FIXME: Return the error all the way up.  */
+          log_fatal ("format failed: %s\n",
+                     gpg_strerror (gpg_error_from_syserror()));
         es_free (tmpmsg);
 
         /* Print a status line but suppress the trailing LF.
@@ -3203,9 +3230,9 @@ show_statistics (tofu_dbs_t dbs,
                         " one message to this key!\n"));
 
           /* Cf. write_stats_status  */
-          if (sqrtu32 (encryption_count * encryption_count
-                       + signature_count * signature_count)
-              < 2 * BASIC_TRUST_THRESHOLD)
+          if ((encryption_count * encryption_count
+              + signature_count * signature_count)
+             < ((2 * BASIC_TRUST_THRESHOLD) * (2 * BASIC_TRUST_THRESHOLD)))
             show_warning = 1;
         }
     }
@@ -3243,7 +3270,10 @@ show_warning (const char *fingerprint, strlist_t user_id_list)
       strlist_length (user_id_list)),
      set_policy_command);
 
-  text = format_text (tmpmsg, 0, 72, 80);
+  text = format_text (tmpmsg, 72, 80);
+  if (!text) /* FIXME: Return the error all the way up.  */
+    log_fatal ("format failed: %s\n",
+               gpg_strerror (gpg_error_from_syserror()));
   xfree (tmpmsg);
   log_string (GPGRT_LOG_INFO, text);
   xfree (text);
@@ -3471,7 +3501,7 @@ tofu_register_encryption (ctrl_t ctrl,
       ! pk_is_primary (pk)
       /* We need the key block to find all user ids.  */
       || ! user_id_list)
-    kb = get_pubkeyblock (pk->keyid);
+    kb = get_pubkeyblock (ctrl, pk->keyid);
 
   /* Make sure PK is a primary key.  */
   if (! pk_is_primary (pk))
@@ -3486,7 +3516,7 @@ tofu_register_encryption (ctrl_t ctrl,
         {
          PKT_user_id *uid = n->pkt->pkt.user_id;
 
-          if (uid->is_revoked)
+          if (uid->flags.revoked)
             continue;
 
           add_to_strlist (&user_id_list, uid->name);
@@ -3670,7 +3700,7 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
 
   fingerprint = hexfingerprint (pk, NULL, 0);
   email = email_from_user_id (user_id);
-  policy = get_policy (dbs, pk, fingerprint, user_id, email, NULL, now);
+  policy = get_policy (ctrl, dbs, pk, fingerprint, user_id, email, NULL, now);
 
   show_statistics (dbs, fingerprint, email, policy, fp, 0, now);
 
@@ -3835,7 +3865,7 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
 gpg_error_t
 tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy)
 {
-  gpg_error_t err;
+  gpg_error_t err = 0;
   time_t now = gnupg_get_time ();
   tofu_dbs_t dbs;
   PKT_public_key *pk;
@@ -3871,7 +3901,7 @@ tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy)
        continue;
 
       user_id = kb->pkt->pkt.user_id;
-      if (user_id->is_revoked)
+      if (user_id->flags.revoked)
        /* Skip revoked user ids.  (Don't skip expired user ids, the
           expiry can be changed.)  */
        continue;
@@ -3931,7 +3961,8 @@ tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id,
 
   email = email_from_user_id (user_id->name);
 
-  *policy = get_policy (dbs, pk, fingerprint, user_id->name, email, NULL, now);
+  *policy = get_policy (ctrl, dbs, pk, fingerprint,
+                        user_id->name, email, NULL, now);
 
   xfree (email);
   xfree (fingerprint);