Updated.
[gnupg.git] / g10 / trustdb.c
index 826f83b..e372bf8 100644 (file)
@@ -28,7 +28,7 @@
 
 #ifndef DISABLE_REGEX
 #include <sys/types.h>
-#ifdef USE_GNU_REGEX
+#ifdef USE_INTERNAL_REGEX
 #include "_regex.h"
 #else
 #include <regex.h>
@@ -99,7 +99,7 @@ new_key_item (void)
 {
   struct key_item *k;
   
-  k = m_alloc_clear (sizeof *k);
+  k = xmalloc_clear (sizeof *k);
   return k;
 }
 
@@ -111,8 +111,8 @@ release_key_items (struct key_item *k)
   for (; k; k = k2)
     {
       k2 = k->next;
-      m_free (k->trust_regexp);
-      m_free (k);
+      xfree (k->trust_regexp);
+      xfree (k);
     }
 }
 
@@ -129,7 +129,7 @@ new_key_hash_table (void)
 {
   struct key_item **tbl;
 
-  tbl = m_alloc_clear (1024 * sizeof *tbl);
+  tbl = xmalloc_clear (1024 * sizeof *tbl);
   return tbl;
 }
 
@@ -142,7 +142,7 @@ release_key_hash_table (KeyHashTable tbl)
     return;
   for (i=0; i < 1024; i++)
     release_key_items (tbl[i]);
-  m_free (tbl);
+  xfree (tbl);
 }
 
 /* 
@@ -189,7 +189,7 @@ release_key_array ( struct key_array *keys )
     if (keys) {
         for (k=keys; k->keyblock; k++)
             release_kbnode (k->keyblock);
-        m_free (keys);
+        xfree (keys);
     }
 }
 
@@ -409,7 +409,7 @@ setup_trustdb( int level, const char *dbname )
     if( trustdb_args.init )
        return 0;
     trustdb_args.level = level;
-    trustdb_args.dbname = dbname? m_strdup(dbname): NULL;
+    trustdb_args.dbname = dbname? xstrdup(dbname): NULL;
     return 0;
 }
 
@@ -832,7 +832,7 @@ update_min_ownertrust (u32 *kid, unsigned int new_trust )
   TRUSTREC rec;
   int rc;
 
-  pk = m_alloc_clear (sizeof *pk);
+  pk = xmalloc_clear (sizeof *pk);
   rc = get_pubkey (pk, kid);
   if (rc)
     {
@@ -1066,14 +1066,14 @@ get_validity (PKT_public_key *pk, PKT_user_id *uid)
   keyid_from_pk (pk, kid);
   if (pk->main_keyid[0] != kid[0] || pk->main_keyid[1] != kid[1])
     { /* this is a subkey - get the mainkey */
-      main_pk = m_alloc_clear (sizeof *main_pk);
+      main_pk = xmalloc_clear (sizeof *main_pk);
       rc = get_pubkey (main_pk, pk->main_keyid);
       if (rc)
         {
-         char *tempkeystr=m_strdup(keystr(pk->main_keyid));
+         char *tempkeystr=xstrdup(keystr(pk->main_keyid));
           log_error ("error getting main key %s of subkey %s: %s\n",
                      tempkeystr, keystr(kid), g10_errstr(rc));
-         m_free(tempkeystr);
+         xfree(tempkeystr);
           validity = TRUST_UNKNOWN; 
           goto leave;
        }
@@ -1270,7 +1270,7 @@ ask_ownertrust (u32 *kid,int minimum)
   int rc;
   int ot;
 
-  pk = m_alloc_clear (sizeof *pk);
+  pk = xmalloc_clear (sizeof *pk);
   rc = get_pubkey (pk, kid);
   if (rc)
     {
@@ -1574,14 +1574,17 @@ mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
     }
 }
 
-int
-clean_sigs_from_uid(KBNODE keyblock,KBNODE uidnode,int noisy)
+static int
+clean_sigs_from_uid(KBNODE keyblock,KBNODE uidnode,int noisy,int self_only)
 {
   int deleted=0;
   KBNODE node;
+  u32 keyid[2];
 
   assert(keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
 
+  keyid_from_pk(keyblock->pkt->pkt.public_key,keyid);
+
   /* Passing in a 0 for current time here means that we'll never weed
      out an expired sig.  This is correct behavior since we want to
      keep the most recent expired sig in a series. */
@@ -1607,27 +1610,37 @@ clean_sigs_from_uid(KBNODE keyblock,KBNODE uidnode,int noisy)
       node && node->pkt->pkttype==PKT_SIGNATURE;
       node=node->next)
     {
+      int keep=self_only?(node->pkt->pkt.signature->keyid[0]==keyid[0]
+                         && node->pkt->pkt.signature->keyid[1]==keyid[1]):1;
+
       /* Keep usable uid sigs ... */
-      if(node->flag & (1<<8))
+      if((node->flag & (1<<8)) && keep)
        continue;
 
       /* ... and usable revocations... */
-      if(node->flag & (1<<11))
+      if((node->flag & (1<<11)) && keep)
        continue;
 
       /* ... and sigs from unavailable keys. */
-      if(node->flag & (1<<12))
+      /* disabled for now since more people seem to want sigs from
+        unavailable keys removed altogether.  */
+      /*
+       if(node->flag & (1<<12))
        continue;
+      */
 
       /* Everything else we delete */
 
-      /* if 9 or 10 is set, but we get this far, it's superceded,
-        otherwise, it's invalid */
+      /* At this point, if 12 is set, the signing key was unavailable.
+        If 9 or 10 is set, it's superceded.  Otherwise, it's
+        invalid. */
 
       if(noisy)
-       log_info("removing signature issued by key %s: %s\n",
+       log_info("removing signature from key %s on user ID \"%s\": %s\n",
                 keystr(node->pkt->pkt.signature->keyid),
-                node->flag&(1<<9)?"superceded":"invalid");
+                uidnode->pkt->pkt.user_id->name,
+                node->flag&(1<<12)?"key unavailable":
+                node->flag&(1<<9)?"signature superceded":"invalid signature");
 
       delete_kbnode(node);
       deleted++;
@@ -1640,133 +1653,102 @@ clean_sigs_from_uid(KBNODE keyblock,KBNODE uidnode,int noisy)
    have to establish if the uid has a valid self-sig, is not revoked,
    and is not expired.  Note that this does not take into account
    whether the uid has a trust path to it - just whether the keyholder
-   themselves has certified the uid.  Returns how many user IDs were
-   removed. */
-int
-clean_uids_from_key(KBNODE keyblock,int noisy)
+   themselves has certified the uid.  Returns true if the uid was
+   compacted.  To "compact" a user ID, we simply remove ALL signatures
+   except the self-sig that caused the user ID to be remove-worthy.
+   We don't actually remove the user ID packet itself since it might
+   be ressurected in a later merge.  Note that this function requires
+   that the caller has already done a merge_keys_and_selfsig().
+
+   TODO: change the import code to allow importing a uid with only a
+   revocation if the uid already exists on the keyring. */
+
+static int
+clean_uid_from_key(KBNODE keyblock,KBNODE uidnode,int noisy)
 {
-  int uidcount=0,delete_until_next=0,deleted=0;
   KBNODE node;
+  PKT_user_id *uid=uidnode->pkt->pkt.user_id;
+  int deleted=0;
 
   assert(keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  assert(uidnode->pkt->pkttype==PKT_USER_ID);
 
-  merge_keys_and_selfsig(keyblock);
+  /* Skip valid user IDs, compacted user IDs, and non-self-signed user
+     IDs if --allow-non-selfsigned-uid is set. */
+  if(uid->created || uid->flags.compacted
+     || (!uid->is_expired && !uid->is_revoked
+        && opt.allow_non_selfsigned_uid))
+    return 0;
 
-  /* First count how many user IDs we have.  We need to be careful
-     that we don't delete them all as some keys could actually have NO
-     valid user IDs.  2440 requires at least 1 user ID packet, valid
-     or not. */
-  for(node=keyblock->next;
-      node && node->pkt->pkttype!=PKT_PUBLIC_SUBKEY;
+  for(node=uidnode->next;
+      node && node->pkt->pkttype==PKT_SIGNATURE;
       node=node->next)
-    if(node->pkt->pkttype==PKT_USER_ID)
-      uidcount++;
+    if(!node->pkt->pkt.signature->flags.chosen_selfsig)
+      {
+       delete_kbnode(node);
+       deleted=1;
+       uidnode->pkt->pkt.user_id->flags.compacted=1;
+      }
 
-  for(node=keyblock->next;
-      node && node->pkt->pkttype!=PKT_PUBLIC_SUBKEY && uidcount>deleted+1;
-      node=node->next)
+  if(noisy)
     {
-      if(node->pkt->pkttype==PKT_USER_ID)
-       {
-         PKT_user_id *uid=node->pkt->pkt.user_id;
-
-         /* Skip valid user IDs, and non-self-signed user IDs if
-            --allow-non-selfsigned-uid is set. */
-         if(uid->created
-            || (!uid->is_expired && !uid->is_revoked 
-                && opt.allow_non_selfsigned_uid))
-           delete_until_next=0;
-         else
-           {
-             delete_until_next=1;
-             deleted++;
+      const char *reason;
+      char *user=utf8_to_native(uid->name,uid->len,0);
 
-             if(noisy)
-               {
-                 char *reason;
-                 char *user=utf8_to_native(uid->name,uid->len,0);
-
-                 if(uid->is_revoked)
-                   reason=_("revoked");
-                 else if(uid->is_expired)
-                   reason=_("expired");
-                 else
-                   reason=_("invalid");
-
-                 log_info("removing user ID \"%s\" from key %s: %s\n",
-                          user,keystr(keyblock->pkt->pkt.public_key->keyid),
-                          reason);
+      if(uid->is_revoked)
+       reason=_("revoked");
+      else if(uid->is_expired)
+       reason=_("expired");
+      else
+       reason=_("invalid");
 
-                 m_free(user);
-               }
-           }
-       }
+      log_info("compacting user ID \"%s\" on key %s: %s\n",
+              user,keystr_from_pk(keyblock->pkt->pkt.public_key),
+              reason);
 
-      if(delete_until_next)
-       delete_kbnode(node);
+      xfree(user);
     }
-    
+
   return deleted;
 }
 
-/* Another cleaning function.  This only cleans encrypt-only subkeys
-   since an expired/revoked encryption key is basically useless, but
-   an expired/revoked key that can sign is still needed to verify old
-   signatures. */
-int
-clean_subkeys_from_key(KBNODE keyblock,int noisy)
+/* Needs to be called after a merge_keys_and_selfsig() */
+void
+clean_one_uid(KBNODE keyblock,KBNODE uidnode,int noisy,int self_only,
+             int *uids_cleaned,int *sigs_cleaned)
 {
-  int delete_until_next=0,deleted=0;
-  KBNODE node;
-  char *main_key=NULL;
+  int dummy;
 
   assert(keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  assert(uidnode->pkt->pkttype==PKT_USER_ID);
 
-  merge_keys_and_selfsig(keyblock);
-
-  if(noisy)
-    main_key=m_strdup(keystr(keyblock->pkt->pkt.public_key->keyid));
-
-  for(node=keyblock->next;node;node=node->next)
-    {
-      if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
-       {
-         PKT_public_key *pk=node->pkt->pkt.public_key;
-
-         /* If it is valid, not expired, and not revoked, leave it
-            alone.  If a key can make signatures, leave it alone. */
-         if(pk->pubkey_usage!=PUBKEY_USAGE_ENC
-            || (pk->is_valid && !pk->has_expired && !pk->is_revoked))
-           delete_until_next=0;
-         else
-           {
-             delete_until_next=1;
-             deleted++;
-
-             if(noisy)
-               {
-                 char *reason;
+  if(!uids_cleaned)
+    uids_cleaned=&dummy;
 
-                 if(pk->is_revoked)
-                   reason=_("revoked");
-                 else if(pk->has_expired)
-                   reason=_("expired");
-                 else
-                   reason=_("invalid");
+  if(!sigs_cleaned)
+    sigs_cleaned=&dummy;
 
-                 log_info("removing subkey %s from key %s: %s\n",
-                          keystr_from_pk(pk),main_key,reason);
-               }
-           }
-       }
+  /* Do clean_uid_from_key first since if it fires off, we don't
+     have to bother with the other */
+  *uids_cleaned+=clean_uid_from_key(keyblock,uidnode,noisy);
+  if(!uidnode->pkt->pkt.user_id->flags.compacted)
+    *sigs_cleaned+=clean_sigs_from_uid(keyblock,uidnode,noisy,self_only);
+}
 
-      if(delete_until_next)
-       delete_kbnode(node);
-    }
+void
+clean_key(KBNODE keyblock,int noisy,int self_only,
+         int *uids_cleaned,int *sigs_cleaned)
+{
+  KBNODE uidnode;
 
-  m_free(main_key);
+  merge_keys_and_selfsig(keyblock);
 
-  return deleted;
+  for(uidnode=keyblock->next;
+      uidnode && uidnode->pkt->pkttype!=PKT_PUBLIC_SUBKEY;
+      uidnode=uidnode->next)
+    if(uidnode->pkt->pkttype==PKT_USER_ID)
+      clean_one_uid(keyblock,uidnode,noisy,self_only,
+                   uids_cleaned,sigs_cleaned);
 }
 
 /* Used by validate_one_keyblock to confirm a regexp within a trust
@@ -1975,14 +1957,14 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
   KEYDB_SEARCH_DESC desc;
   
   maxkeys = 1000;
-  keys = m_alloc ((maxkeys+1) * sizeof *keys);
+  keys = xmalloc ((maxkeys+1) * sizeof *keys);
   nkeys = 0;
   
   rc = keydb_search_reset (hd);
   if (rc)
     {
       log_error ("keydb_search_reset failed: %s\n", g10_errstr(rc));
-      m_free (keys);
+      xfree (keys);
       return NULL;
     }
 
@@ -1999,7 +1981,7 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
   if (rc)
     {
       log_error ("keydb_search_first failed: %s\n", g10_errstr(rc));
-      m_free (keys);
+      xfree (keys);
       return NULL;
     }
   
@@ -2012,7 +1994,7 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
       if (rc) 
         {
           log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
-          m_free (keys);
+          xfree (keys);
           return NULL;
         }
       
@@ -2044,7 +2026,7 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
 
           if (nkeys == maxkeys) {
             maxkeys += 1000;
-            keys = m_realloc (keys, (maxkeys+1) * sizeof *keys);
+            keys = xrealloc (keys, (maxkeys+1) * sizeof *keys);
           }
           keys[nkeys++].keyblock = keyblock;
 
@@ -2068,7 +2050,7 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
   if (rc && rc != -1) 
     {
       log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
-      m_free (keys);
+      xfree (keys);
       return NULL;
     }
 
@@ -2174,7 +2156,8 @@ validate_keys (int interactive)
    * here when needed */
   if (!utk_list)
     {
-      log_info (_("no ultimately trusted keys found\n"));
+      if (!opt.quiet)
+        log_info (_("no ultimately trusted keys found\n"));
       goto leave;
     }
 
@@ -2337,7 +2320,7 @@ validate_keys (int interactive)
                        kar->keyblock->pkt->pkt.public_key->trust_value;
                      if(kar->keyblock->pkt->pkt.public_key->trust_regexp)
                        k->trust_regexp=
-                         m_strdup(kar->keyblock->pkt->
+                         xstrdup(kar->keyblock->pkt->
                                   pkt.public_key->trust_regexp);
                      k->next = klist;
                      klist = k;