Take care of already existing bogus 0x1f signatures.
[gnupg.git] / g10 / trustdb.c
index c72dc20..c83e169 100644 (file)
@@ -1,12 +1,12 @@
 /* trustdb.c
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ *               2008 Free Software Foundation, Inc.
  *
  * 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 2 of the License, or
+ * 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,
@@ -15,9 +15,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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 
 #ifndef DISABLE_REGEX
 #include <sys/types.h>
-#ifdef USE_GNU_REGEX
-#include "_regex.h"
-#else
 #include <regex.h>
-#endif
 #endif /* !DISABLE_REGEX */
 
-#include "errors.h"
+#include "gpg.h"
+#include "status.h"
 #include "iobuf.h"
 #include "keydb.h"
-#include "memory.h"
 #include "util.h"
 #include "options.h"
 #include "packet.h"
@@ -99,7 +93,7 @@ new_key_item (void)
 {
   struct key_item *k;
   
-  k = m_alloc_clear (sizeof *k);
+  k = xmalloc_clear (sizeof *k);
   return k;
 }
 
@@ -111,8 +105,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 +123,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 +136,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 +183,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,11 +403,32 @@ 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;
 }
 
 void
+how_to_fix_the_trustdb ()
+{
+  const char *name = trustdb_args.dbname;
+
+  if (!name)
+    name = "trustdb.gpg";
+
+  log_info (_("You may try to re-create the trustdb using the commands:\n"));
+  log_info ("  cd %s\n", default_homedir ());
+  log_info ("  gpg2 --export-ownertrust > otrust.tmp\n");
+#ifdef HAVE_W32_SYSTEM
+  log_info ("  del %s\n", name);
+#else
+  log_info ("  rm %s\n", name);
+#endif
+  log_info ("  gpg2 --import-ownertrust < otrust.tmp\n");
+  log_info (_("If that does not work, please consult the manual\n"));
+}
+
+
+void
 init_trustdb()
 {
   int level = trustdb_args.level;
@@ -832,7 +847,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 +1081,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;
        }
@@ -1161,12 +1176,15 @@ get_validity (PKT_public_key *pk, PKT_user_id *uid)
 int
 get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
 {
-    int trustlevel;
-
-    trustlevel = get_validity (pk, uid);
-    if( trustlevel & TRUST_FLAG_REVOKED )
-       return 'r';
-    return trust_letter ( trustlevel );
+  int trustlevel;
+  
+  if (!pk)
+    return '?';  /* Just in case a NULL PK is passed.  */
+  
+  trustlevel = get_validity (pk, uid);
+  if ( (trustlevel & TRUST_FLAG_REVOKED) )
+    return 'r';
+  return trust_letter (trustlevel);
 }
 
 const char *
@@ -1174,6 +1192,9 @@ get_validity_string (PKT_public_key *pk, PKT_user_id *uid)
 {
   int trustlevel;
 
+  if (!pk)
+    return "err";  /* Just in case a NULL PK is passed.  */
+
   trustlevel = get_validity (pk, uid);
   if( trustlevel & TRUST_FLAG_REVOKED )
     return _("revoked");
@@ -1219,6 +1240,7 @@ get_validity_counts (PKT_public_key *pk, PKT_user_id *uid)
 void
 list_trust_path( const char *username )
 {
+  (void)username;
 }
 
 /****************
@@ -1243,7 +1265,11 @@ int
 enum_cert_paths( void **context, ulong *lid,
                 unsigned *ownertrust, unsigned *validity )
 {
-    return -1;
+  (void)context;
+  (void)lid;
+  (void)ownertrust;
+  (void)validity;
+  return -1;
 }
 
 
@@ -1251,10 +1277,13 @@ enum_cert_paths( void **context, ulong *lid,
  * Print the current path
  */
 void
-enum_cert_paths_printvoid **context, FILE *fp,
-                                      int refresh, ulong selected_lid )
+enum_cert_paths_print (void **context, FILE *fp,
+                       int refresh, ulong selected_lid)
 {
-    return;
+  (void)context;
+  (void)fp;
+  (void)refresh;
+  (void)selected_lid;
 }
 
 
@@ -1270,7 +1299,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 +1603,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,28 +1639,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 superseded.  Otherwise, it's
+        invalid. */
 
       if(noisy)
-       log_info("removing signature from %s on uid \"%s\": %s\n",
+       log_info("removing signature from key %s on user ID \"%s\": %s\n",
                 keystr(node->pkt->pkt.signature->keyid),
                 uidnode->pkt->pkt.user_id->name,
-                node->flag&(1<<9)?"superceded":"invalid");
+                node->flag&(1<<12)?"key unavailable":
+                node->flag&(1<<9)?"signature superseded":"invalid signature");
 
       delete_kbnode(node);
       deleted++;
@@ -1641,98 +1682,168 @@ 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.  To "remove" a user ID, we simply remove ALL signatures
+   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.
+   be ressurected in a later merge.  Note that this function requires
+   that the caller has already done a merge_keys_and_selfsig().
 
-   If this self-sig is a revocation, we also include the most recent
-   valid regular sig since it is hard to import the user ID otherwise.
    TODO: change the import code to allow importing a uid with only a
    revocation if the uid already exists on the keyring. */
-int
-clean_uids_from_key(KBNODE keyblock,int noisy)
+
+static int
+clean_uid_from_key(KBNODE keyblock,KBNODE uidnode,int noisy)
 {
-  int delete_until_next=0,deleted=0;
-  KBNODE node,signode=NULL;
-  u32 keyid[2],sigdate=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);
 
-  keyid_from_pk(keyblock->pkt->pkt.public_key,keyid);
-
-  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;
 
-  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->pkt.signature->flags.chosen_selfsig)
+      {
+       delete_kbnode(node);
+       deleted=1;
+       uidnode->pkt->pkt.user_id->flags.compacted=1;
+      }
+
+  if(noisy)
     {
-      if(node->pkt->pkttype==PKT_USER_ID)
-       {
-         PKT_user_id *uid=node->pkt->pkt.user_id;
+      const char *reason;
+      char *user=utf8_to_native(uid->name,uid->len,0);
 
-         if(signode && !signode->pkt->pkt.signature->flags.chosen_selfsig)
-           undelete_kbnode(signode);
+      if(uid->is_revoked)
+       reason=_("revoked");
+      else if(uid->is_expired)
+       reason=_("expired");
+      else
+       reason=_("invalid");
 
-         sigdate=0;
-         signode=NULL;
+      log_info("compacting user ID \"%s\" on key %s: %s\n",
+              user,keystr_from_pk(keyblock->pkt->pkt.public_key),
+              reason);
 
-         /* 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++;
+      xfree(user);
+    }
 
-             if(noisy)
-               {
-                 const char *reason;
-                 char *user=utf8_to_native(uid->name,uid->len,0);
+  return deleted;
+}
 
-                 if(uid->is_revoked)
-                   reason=_("revoked");
-                 else if(uid->is_expired)
-                   reason=_("expired");
-                 else
-                   reason=_("invalid");
+/* 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 dummy;
 
-                 log_info("compacting user ID \"%s\" on key %s: %s\n",
-                          user,keystr(keyblock->pkt->pkt.public_key->keyid),
-                          reason);
+  assert(keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  assert(uidnode->pkt->pkttype==PKT_USER_ID);
 
-                 m_free(user);
-               }
-           }
-       }
-      else if(node->pkt->pkttype==PKT_SIGNATURE)
-       {
-         PKT_signature *sig=node->pkt->pkt.signature;
+  if(!uids_cleaned)
+    uids_cleaned=&dummy;
 
-         /* This isn't actually slow - the key signature validation
-            is cached from merge_keys_and_selfsig() */
-         if(IS_UID_SIG(sig) && sig->timestamp>sigdate
-            && keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1]
-            && check_key_signature(keyblock,node,NULL)==0)
-           {
-             sigdate=sig->timestamp;
-             signode=node;
-           }
+  if(!sigs_cleaned)
+    sigs_cleaned=&dummy;
 
-         if(delete_until_next && !sig->flags.chosen_selfsig)
-           delete_kbnode(node);
-       }
+  /* 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);
+}
+
+void
+clean_key(KBNODE keyblock,int noisy,int self_only,
+         int *uids_cleaned,int *sigs_cleaned)
+{
+  KBNODE uidnode;
+
+  merge_keys_and_selfsig(keyblock);
+
+  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);
+}
+
+/* Returns a sanitized copy of the regexp (which might be "", but not
+   NULL). */
+#ifndef DISABLE_REGEX
+static char *
+sanitize_regexp(const char *old)
+{
+  size_t start=0,len=strlen(old),idx=0;
+  int escaped=0,standard_bracket=0;
+  char *new=xmalloc((len*2)+1); /* enough to \-escape everything if we
+                                  have to */
+
+  /* There are basically two commonly-used regexps here.  GPG and most
+     versions of PGP use "<[^>]+[@.]example\.com>$" and PGP (9)
+     command line uses "example.com" (i.e. whatever the user specfies,
+     and we can't expect users know to use "\." instead of ".").  So
+     here are the rules: we're allowed to start with "<[^>]+[@.]" and
+     end with ">$" or start and end with nothing.  In between, the
+     only legal regex character is ".", and everything else gets
+     escaped.  Part of the gotcha here is that some regex packages
+     allow more than RFC-4880 requires.  For example, 4880 has no "{}"
+     operator, but GNU regex does.  Commenting removes these operators
+     from consideration.  A possible future enhancement is to use
+     commenting to effectively back off a given regex to the Henry
+     Spencer syntax in 4880. -dshaw */
+
+  /* Are we bracketed between "<[^>]+[@.]" and ">$" ? */
+  if(len>=12 && strncmp(old,"<[^>]+[@.]",10)==0
+     && old[len-2]=='>' && old[len-1]=='$')
+    {
+      strcpy(new,"<[^>]+[@.]");
+      idx=strlen(new);
+      standard_bracket=1;
+      start+=10;
+      len-=2;
+    }
+
+  /* Walk the remaining characters and ensure that everything that is
+     left is not an operational regex character. */
+  for(;start<len;start++)
+    {
+      if(!escaped && old[start]=='\\')
+       escaped=1;
+      else if(!escaped && old[start]!='.')
+       new[idx++]='\\';
+      else
+       escaped=0;
+
+      new[idx++]=old[start];
     }
 
-  if(signode && !signode->pkt->pkt.signature->flags.chosen_selfsig)
-    undelete_kbnode(signode);
+  new[idx]='\0';
 
-  return deleted;
+  /* Note that the (sub)string we look at might end with a bare "\".
+     If it does, leave it that way.  If the regexp actually ended with
+     ">$", then it was escaping the ">" and is fine.  If the regexp
+     actually ended with the bare "\", then it's an illegal regexp and
+     regcomp should kick it out. */
+
+  if(standard_bracket)
+    strcat(new,">$");
+
+  return new;
 }
+#endif /*!DISABLE_REGEX*/
 
 /* Used by validate_one_keyblock to confirm a regexp within a trust
    signature.  Returns 1 for match, and 0 for no match or regex
@@ -1744,23 +1855,35 @@ check_regexp(const char *expr,const char *string)
   /* When DISABLE_REGEX is defined, assume all regexps do not
      match. */
   return 0;
-#elif defined(__riscos__)
-  return riscos_check_regexp(expr, string, DBG_TRUST);
 #else
   int ret;
-  regex_t pat;
+  char *regexp;
 
-  if(regcomp(&pat,expr,REG_ICASE|REG_NOSUB|REG_EXTENDED)!=0)
-    return 0;
+  regexp=sanitize_regexp(expr);
 
-  ret=regexec(&pat,string,0,NULL,0);
+#ifdef __riscos__
+  ret=riscos_check_regexp(expr, string, DBG_TRUST);
+#else
+  {
+    regex_t pat;
 
-  regfree(&pat);
+    ret=regcomp(&pat,regexp,REG_ICASE|REG_NOSUB|REG_EXTENDED);
+    if(ret==0)
+      {
+       ret=regexec(&pat,string,0,NULL,0);
+       regfree(&pat);
+       ret=(ret==0);
+      }
+  }
+#endif
 
   if(DBG_TRUST)
-    log_debug("regexp `%s' on `%s': %s\n",expr,string,ret==0?"YES":"NO");
+    log_debug("regexp `%s' (`%s') on `%s': %s\n",
+             regexp,expr,string,ret==0?"YES":"NO");
 
-  return (ret==0);
+  xfree(regexp);
+
+  return ret;
 #endif
 }
 
@@ -1839,54 +1962,78 @@ validate_one_keyblock (KBNODE kb, struct key_item *klist,
              did not exist.  This is safe for non-trust sigs as well
              since we don't accept a regexp on the sig unless it's a
              trust sig. */
-          if (kr && (kr->trust_regexp==NULL || opt.trust_model!=TM_PGP ||
-                    (uidnode && check_regexp(kr->trust_regexp,
-                                           uidnode->pkt->pkt.user_id->name))))
+          if (kr && (!kr->trust_regexp 
+                     || opt.trust_model != TM_PGP 
+                     || (uidnode 
+                         && check_regexp(kr->trust_regexp,
+                                         uidnode->pkt->pkt.user_id->name))))
             {
-             if(DBG_TRUST && opt.trust_model==TM_PGP && sig->trust_depth)
-               log_debug("trust sig on %s, sig depth is %d, kr depth is %d\n",
-                         uidnode->pkt->pkt.user_id->name,sig->trust_depth,
-                         kr->trust_depth);
-
              /* Are we part of a trust sig chain?  We always favor
                  the latest trust sig, rather than the greater or
                  lesser trust sig or value.  I could make a decent
                  argument for any of these cases, but this seems to be
                  what PGP does, and I'd like to be compatible. -dms */
-             if(opt.trust_model==TM_PGP && sig->trust_depth
-                && pk->trust_timestamp<=sig->timestamp
-                && (sig->trust_depth<=kr->trust_depth
-                    || kr->ownertrust==TRUST_ULTIMATE))
+              if (opt.trust_model == TM_PGP
+                  && sig->trust_depth
+                  && pk->trust_timestamp <= sig->timestamp)
                {
-                 /* If we got here, we know that:
-
-                    this is a trust sig.
-
-                    it's a newer trust sig than any previous trust
-                    sig on this key (not uid).
-
-                    it is legal in that it was either generated by an
-                    ultimate key, or a key that was part of a trust
-                    chain, and the depth does not violate the
-                    original trust sig.
-
-                    if there is a regexp attached, it matched
-                    successfully.
-                 */
-
-                 if(DBG_TRUST)
-                   log_debug("replacing trust value %d with %d and "
-                             "depth %d with %d\n",
-                             pk->trust_value,sig->trust_value,
-                             pk->trust_depth,sig->trust_depth);
-
-                 pk->trust_value=sig->trust_value;
-                 pk->trust_depth=sig->trust_depth-1;
+                 unsigned char depth;
+
+                 /* If the depth on the signature is less than the
+                    chain currently has, then use the signature depth
+                    so we don't increase the depth beyond what the
+                    signer wanted.  If the depth on the signature is
+                    more than the chain currently has, then use the
+                    chain depth so we use as much of the signature
+                    depth as the chain will permit.  An ultimately
+                    trusted signature can restart the depth to
+                    whatever level it likes. */
+
+                 if (sig->trust_depth < kr->trust_depth
+                      || kr->ownertrust == TRUST_ULTIMATE)
+                   depth = sig->trust_depth;
+                 else
+                   depth = kr->trust_depth;
 
-                 /* If the trust sig contains a regexp, record it
-                    on the pk for the next round. */
-                 if(sig->trust_regexp)
-                   pk->trust_regexp=sig->trust_regexp;
+                 if (depth)
+                   {
+                     if(DBG_TRUST)
+                       log_debug ("trust sig on %s, sig depth is %d,"
+                                   " kr depth is %d\n",
+                                   uidnode->pkt->pkt.user_id->name,
+                                   sig->trust_depth,
+                                   kr->trust_depth);
+
+                     /* If we got here, we know that:
+
+                        this is a trust sig.
+
+                        it's a newer trust sig than any previous trust
+                        sig on this key (not uid).
+
+                        it is legal in that it was either generated by an
+                        ultimate key, or a key that was part of a trust
+                        chain, and the depth does not violate the
+                        original trust sig.
+
+                        if there is a regexp attached, it matched
+                        successfully.
+                     */
+
+                     if (DBG_TRUST)
+                       log_debug ("replacing trust value %d with %d and "
+                                   "depth %d with %d\n",
+                                   pk->trust_value,sig->trust_value,
+                                   pk->trust_depth,depth);
+
+                     pk->trust_value = sig->trust_value;
+                     pk->trust_depth = depth-1;
+                      
+                     /* If the trust sig contains a regexp, record it
+                        on the pk for the next round. */
+                     if (sig->trust_regexp)
+                       pk->trust_regexp = sig->trust_regexp;
+                   }
                }
 
               if (kr->ownertrust == TRUST_ULTIMATE)
@@ -1918,6 +2065,7 @@ validate_one_keyblock (KBNODE kb, struct key_item *klist,
 static int
 search_skipfnc (void *opaque, u32 *kid, PKT_user_id *dummy)
 {
+  (void)dummy;
   return test_key_hash_table ((KeyHashTable)opaque, kid);
 }
 
@@ -1940,14 +2088,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;
     }
 
@@ -1964,7 +2112,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;
     }
   
@@ -1977,7 +2125,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;
         }
       
@@ -2009,7 +2157,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;
 
@@ -2033,7 +2181,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;
     }
 
@@ -2139,7 +2287,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;
     }
 
@@ -2302,7 +2451,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;