gpg: Don't forget to free some memory.
[gnupg.git] / g10 / keyring.c
index 04f6eeb..81d2174 100644 (file)
@@ -1,5 +1,6 @@
 /* keyring.c - keyring file handling
- * Copyright (C) 2001, 2004, 2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2010 Free Software Foundation, Inc.
+ * Copyright (C) 1997-2015 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -83,7 +84,7 @@ struct keyring_handle
     size_t pk_no;
     size_t uid_no;
     unsigned int n_packets; /*used for delete and update*/
-  } found;
+  } found, saved_found;
   struct {
     char *name;
     char *pattern;
@@ -279,6 +280,25 @@ keyring_release (KEYRING_HANDLE hd)
 }
 
 
+/* Save the current found state in HD for later retrieval by
+   keybox_pop_found_state.  Only one state may be saved.  */
+void
+keyring_push_found_state (KEYRING_HANDLE hd)
+{
+  hd->saved_found = hd->found;
+  hd->found.kr = NULL;
+}
+
+
+/* Restore the saved found state in HD.  */
+void
+keyring_pop_found_state (KEYRING_HANDLE hd)
+{
+  hd->found = hd->saved_found;
+  hd->saved_found.kr = NULL;
+}
+
+
 const char *
 keyring_get_resource_name (KEYRING_HANDLE hd)
 {
@@ -309,7 +329,7 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
                 kr->lockhd = dotlock_create (kr->fname, 0);
                 if (!kr->lockhd) {
                     log_info ("can't allocate lock for '%s'\n", kr->fname );
-                    rc = G10ERR_GENERAL;
+                    rc = GPG_ERR_GENERAL;
                 }
             }
         }
@@ -324,7 +344,7 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
                 ;
             else if (dotlock_take (kr->lockhd, -1) ) {
                 log_info ("can't lock '%s'\n", kr->fname );
-                rc = G10ERR_GENERAL;
+                rc = GPG_ERR_GENERAL;
             }
             else
                 kr->is_locked = 1;
@@ -350,7 +370,7 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
 
 \f
 /*
- * Return the last found keyring.  Caller must free it.
+ * Return the last found keyblock.  Caller must free it.
  * The returned keyblock has the kbode flag bit 0 set for the node with
  * the public key used to locate the keyblock or flag bit 1 set for
  * the user ID node.
@@ -377,13 +397,13 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
     if (!a)
       {
        log_error(_("can't open '%s'\n"), hd->found.kr->fname);
-       return G10ERR_KEYRING_OPEN;
+       return GPG_ERR_KEYRING_OPEN;
       }
 
     if (iobuf_seek (a, hd->found.offset) ) {
         log_error ("can't seek '%s'\n", hd->found.kr->fname);
        iobuf_close(a);
-       return G10ERR_KEYRING_OPEN;
+       return GPG_ERR_KEYRING_OPEN;
     }
 
     pkt = xmalloc (sizeof *pkt);
@@ -393,23 +413,44 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
     save_mode = set_packet_list_mode(0);
     while ((rc=parse_packet (a, pkt)) != -1) {
         hd->found.n_packets++;
-        if (rc == G10ERR_UNKNOWN_PACKET) {
+        if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) {
            free_packet (pkt);
            init_packet (pkt);
            continue;
        }
+        if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+          break;  /* Upper layer needs to handle this.  */
        if (rc) {
             log_error ("keyring_get_keyblock: read error: %s\n",
-                       g10_errstr(rc) );
-            rc = G10ERR_INV_KEYRING;
+                       gpg_strerror (rc) );
+            rc = GPG_ERR_INV_KEYRING;
             break;
         }
-       if (pkt->pkttype == PKT_COMPRESSED) {
-           log_error ("skipped compressed packet in keyring\n");
+
+        /* Filter allowed packets.  */
+        switch (pkt->pkttype)
+          {
+          case PKT_PUBLIC_KEY:
+          case PKT_PUBLIC_SUBKEY:
+          case PKT_SECRET_KEY:
+          case PKT_SECRET_SUBKEY:
+          case PKT_USER_ID:
+          case PKT_ATTRIBUTE:
+          case PKT_SIGNATURE:
+            break; /* Allowed per RFC.  */
+          case PKT_RING_TRUST:
+          case PKT_OLD_COMMENT:
+          case PKT_COMMENT:
+          case PKT_GPG_CONTROL:
+            break; /* Allowed by us.  */
+
+          default:
+           log_error ("skipped packet of type %d in keyring\n",
+                       (int)pkt->pkttype);
            free_packet(pkt);
            init_packet(pkt);
            continue;
-        }
+          }
 
         if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
                         || pkt->pkttype == PKT_SECRET_KEY)) {
@@ -476,7 +517,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
     if (rc || !ret_kb)
        release_kbnode (keyblock);
     else {
-        /*(duplicated form the loop body)*/
+        /*(duplicated from the loop body)*/
         if ( pkt && pkt->pkttype == PKT_RING_TRUST
              && lastnode
              && lastnode->pkt->pkttype == PKT_SIGNATURE
@@ -494,7 +535,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
     /* Make sure that future search operations fail immediately when
      * we know that we are working on a invalid keyring
      */
-    if (rc == G10ERR_INV_KEYRING)
+    if (gpg_err_code (rc) == GPG_ERR_INV_KEYRING)
         hd->current.error = rc;
 
     return rc;
@@ -515,7 +556,7 @@ keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
         /* need to know the number of packets - do a dummy get_keyblock*/
         rc = keyring_get_keyblock (hd, NULL);
         if (rc) {
-            log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
+            log_error ("re-reading keyblock failed: %s\n", gpg_strerror (rc));
             return rc;
         }
         if (!hd->found.n_packets)
@@ -567,7 +608,7 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
         fname = hd->resource? hd->resource->fname:NULL;
 
     if (!fname)
-        return G10ERR_GENERAL;
+        return GPG_ERR_GENERAL;
 
     /* Close this one otherwise we will lose the position for
      * a next search.  Fixme: it would be better to adjust the position
@@ -602,7 +643,7 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
         /* need to know the number of packets - do a dummy get_keyblock*/
         rc = keyring_get_keyblock (hd, NULL);
         if (rc) {
-            log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
+            log_error ("re-reading keyblock failed: %s\n", gpg_strerror (rc));
             return rc;
         }
         if (!hd->found.n_packets)
@@ -654,12 +695,18 @@ keyring_search_reset (KEYRING_HANDLE hd)
 static int
 prepare_search (KEYRING_HANDLE hd)
 {
-    if (hd->current.error)
-        return hd->current.error; /* still in error state */
+    if (hd->current.error) {
+        /* If the last key was a legacy key, we simply ignore the error so that
+           we can easily use search_next.  */
+        if (gpg_err_code (hd->current.error) == GPG_ERR_LEGACY_KEY)
+            hd->current.error = 0;
+        else
+            return hd->current.error; /* still in error state */
+    }
 
     if (hd->current.kr && !hd->current.eof) {
         if ( !hd->current.iobuf )
-            return G10ERR_GENERAL; /* position invalid after a modify */
+            return GPG_ERR_GENERAL; /* Position invalid after a modify.  */
         return 0; /* okay */
     }
 
@@ -1087,7 +1134,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
               goto found;
             break;
           default:
-            rc = G10ERR_INV_ARG;
+            rc = GPG_ERR_INV_ARG;
             goto found;
           }
        }
@@ -1101,7 +1148,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       for (n=any_skip?0:ndesc; n < ndesc; n++)
         {
           if (desc[n].skipfnc
-              && desc[n].skipfnc (desc[n].skipfncvalue, aki, uid))
+              && desc[n].skipfnc (desc[n].skipfncvalue, aki, uid_no))
             break;
         }
       if (n == ndesc)
@@ -1197,7 +1244,9 @@ create_tmp_file (const char *template,
     strcpy (stpcpy(tmpfname,template), EXTSEP_S "tmp");
 # endif /* Posix filename */
 
-    /* Create the temp file with limited access */
+    /* Create the temp file with limited access.  Note that the umask
+       call is not anymore needed because iobuf_create now takes care
+       of it.  However, it does not harm and thus we keep it.  */
     oldmask=umask(077);
     if (is_secured_filename (tmpfname))
       {
@@ -1205,7 +1254,7 @@ create_tmp_file (const char *template,
         gpg_err_set_errno (EPERM);
       }
     else
-      *r_fp = iobuf_create (tmpfname);
+      *r_fp = iobuf_create (tmpfname, 1);
     umask(oldmask);
     if (!*r_fp)
       {
@@ -1298,7 +1347,7 @@ write_keyblock (IOBUF fp, KBNODE keyblock)
       if ( (rc = build_packet (fp, node->pkt) ))
         {
           log_error ("build_packet(%d) failed: %s\n",
-                     node->pkt->pkttype, g10_errstr(rc) );
+                     node->pkt->pkttype, gpg_strerror (rc) );
           return rc;
         }
       if (node->pkt->pkttype == PKT_SIGNATURE)
@@ -1352,8 +1401,12 @@ keyring_rebuild_cache (void *token,int noisy)
   if(rc)
     goto leave;
 
-  while ( !(rc = keyring_search (hd, &desc, 1, NULL)) )
+  for (;;)
     {
+      rc = keyring_search (hd, &desc, 1, NULL);
+      if (rc && gpg_err_code (rc) != GPG_ERR_LEGACY_KEY)
+        break;  /* ready.  */
+
       desc.mode = KEYDB_SEARCH_MODE_NEXT;
       resname = keyring_get_resource_name (hd);
       if (lastresname != resname )
@@ -1385,11 +1438,16 @@ keyring_rebuild_cache (void *token,int noisy)
             goto leave;
         }
 
+      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+        continue;
+
       release_kbnode (keyblock);
       rc = keyring_get_keyblock (hd, &keyblock);
       if (rc)
         {
-          log_error ("keyring_get_keyblock failed: %s\n", g10_errstr(rc));
+          if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+            continue;  /* Skip legacy keys.  */
+          log_error ("keyring_get_keyblock failed: %s\n", gpg_strerror (rc));
           goto leave;
         }
       if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
@@ -1407,46 +1465,59 @@ keyring_rebuild_cache (void *token,int noisy)
           goto leave;
         }
 
-      /* check all signature to set the signature's cache flags */
-      for (node=keyblock; node; node=node->next)
+      if (keyblock->pkt->pkt.public_key->version < 4)
+        {
+          /* We do not copy/cache v3 keys or any other unknown
+             packets.  It is better to remove them from the keyring.
+             The code required to keep them in the keyring would be
+             too complicated.  Given that we do not touch the old
+             secring.gpg a suitable backup for decryption of v3 stuff
+             using an older gpg version will always be available.
+             Note: This test is actually superfluous because we
+             already acted upon GPG_ERR_LEGACY_KEY.      */
+        }
+      else
         {
-         /* Note that this doesn't cache the result of a revocation
-            issued by a designated revoker.  This is because the pk
-            in question does not carry the revkeys as we haven't
-            merged the key and selfsigs.  It is questionable whether
-            this matters very much since there are very very few
-            designated revoker revocation packets out there. */
-
-          if (node->pkt->pkttype == PKT_SIGNATURE)
+          /* Check all signature to set the signature's cache flags. */
+          for (node=keyblock; node; node=node->next)
             {
-             PKT_signature *sig=node->pkt->pkt.signature;
+              /* Note that this doesn't cache the result of a
+                 revocation issued by a designated revoker.  This is
+                 because the pk in question does not carry the revkeys
+                 as we haven't merged the key and selfsigs.  It is
+                 questionable whether this matters very much since
+                 there are very very few designated revoker revocation
+                 packets out there. */
+              if (node->pkt->pkttype == PKT_SIGNATURE)
+                {
+                  PKT_signature *sig=node->pkt->pkt.signature;
 
-             if(!opt.no_sig_cache && sig->flags.checked && sig->flags.valid
-                && (openpgp_md_test_algo(sig->digest_algo)
-                    || openpgp_pk_test_algo(sig->pubkey_algo)))
-               sig->flags.checked=sig->flags.valid=0;
-             else
-               check_key_signature (keyblock, node, NULL);
+                  if(!opt.no_sig_cache && sig->flags.checked && sig->flags.valid
+                     && (openpgp_md_test_algo(sig->digest_algo)
+                         || openpgp_pk_test_algo(sig->pubkey_algo)))
+                    sig->flags.checked=sig->flags.valid=0;
+                  else
+                    check_key_signature (keyblock, node, NULL);
 
-              sigcount++;
+                  sigcount++;
+                }
             }
-        }
 
-      /* write the keyblock to the temporary file */
-      rc = write_keyblock (tmpfp, keyblock);
-      if (rc)
-        goto leave;
-
-      if ( !(++count % 50) && noisy && !opt.quiet)
-        log_info(_("%lu keys cached so far (%lu signatures)\n"),
-                 count, sigcount );
+          /* Write the keyblock to the temporary file.  */
+          rc = write_keyblock (tmpfp, keyblock);
+          if (rc)
+            goto leave;
 
+          if ( !(++count % 50) && noisy && !opt.quiet)
+            log_info(_("%lu keys cached so far (%lu signatures)\n"),
+                     count, sigcount );
+        }
     } /* end main loop */
   if (rc == -1)
     rc = 0;
   if (rc)
     {
-      log_error ("keyring_search failed: %s\n", g10_errstr(rc));
+      log_error ("keyring_search failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
   if(noisy || opt.verbose)
@@ -1513,7 +1584,7 @@ do_copy (int mode, const char *fname, KBNODE root,
             gpg_err_set_errno (EPERM);
         }
         else
-            newfp = iobuf_create (fname);
+            newfp = iobuf_create (fname, 1);
        umask(oldmask);
        if( !newfp )
          {
@@ -1528,7 +1599,7 @@ do_copy (int mode, const char *fname, KBNODE root,
        while ( (node = walk_kbnode( root, &kbctx, 0 )) ) {
            if( (rc = build_packet( newfp, node->pkt )) ) {
                log_error("build_packet(%d) failed: %s\n",
-                           node->pkt->pkttype, g10_errstr(rc) );
+                           node->pkt->pkttype, gpg_strerror (rc) );
                iobuf_cancel(newfp);
                return rc;
            }
@@ -1560,7 +1631,7 @@ do_copy (int mode, const char *fname, KBNODE root,
        rc = copy_all_packets (fp, newfp);
        if( rc != -1 ) {
            log_error("%s: copy to '%s' failed: %s\n",
-                     fname, tmpfname, g10_errstr(rc) );
+                     fname, tmpfname, gpg_strerror (rc) );
            iobuf_close(fp);
            iobuf_cancel(newfp);
            goto leave;
@@ -1573,7 +1644,7 @@ do_copy (int mode, const char *fname, KBNODE root,
        rc = copy_some_packets( fp, newfp, start_offset );
        if( rc ) { /* should never get EOF here */
            log_error ("%s: copy to '%s' failed: %s\n",
-                       fname, tmpfname, g10_errstr(rc) );
+                       fname, tmpfname, gpg_strerror (rc) );
            iobuf_close(fp);
            iobuf_cancel(newfp);
            goto leave;
@@ -1583,7 +1654,7 @@ do_copy (int mode, const char *fname, KBNODE root,
        rc = skip_some_packets( fp, n_packets );
        if( rc ) {
            log_error("%s: skipping %u packets failed: %s\n",
-                           fname, n_packets, g10_errstr(rc));
+                           fname, n_packets, gpg_strerror (rc));
            iobuf_close(fp);
            iobuf_cancel(newfp);
            goto leave;
@@ -1604,7 +1675,7 @@ do_copy (int mode, const char *fname, KBNODE root,
        rc = copy_all_packets( fp, newfp );
        if( rc != -1 ) {
            log_error("%s: copy to '%s' failed: %s\n",
-                     fname, tmpfname, g10_errstr(rc) );
+                     fname, tmpfname, gpg_strerror (rc) );
            iobuf_close(fp);
            iobuf_cancel(newfp);
            goto leave;