g10: Don't leak memory if we fail to initialize a new database handle.
[gnupg.git] / g10 / free-packet.c
index be49bb5..670f256 100644 (file)
@@ -1,12 +1,12 @@
 /* free-packet.c - cleanup stuff for packets
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2005  Free Software Foundation, Inc.
+ *               2005, 2010  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>
 #include <string.h>
 #include <assert.h>
 
-#include "packet.h"
-#include "iobuf.h"
-#include "mpi.h"
+#include "gpg.h"
 #include "util.h"
-#include "cipher.h"
-#include "memory.h"
+#include "packet.h"
+#include "../common/iobuf.h"
 #include "options.h"
 
+
+/* This is mpi_copy with a fix for opaque MPIs which store a NULL
+   pointer.  This will also be fixed in Libggcrypt 1.7.0.  */
+static gcry_mpi_t
+my_mpi_copy (gcry_mpi_t a)
+{
+  if (a
+      && gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)
+      && !gcry_mpi_get_opaque (a, NULL))
+    return NULL;
+
+  return gcry_mpi_copy (a);
+}
+
+
 void
 free_symkey_enc( PKT_symkey_enc *enc )
 {
@@ -46,9 +57,9 @@ free_pubkey_enc( PKT_pubkey_enc *enc )
     int n, i;
     n = pubkey_get_nenc( enc->pubkey_algo );
     if( !n )
-       mpi_free(enc->data[0]);
+       mpi_release(enc->data[0]);
     for(i=0; i < n; i++ )
-       mpi_free( enc->data[i] );
+       mpi_release( enc->data[i] );
     xfree(enc);
 }
 
@@ -59,9 +70,9 @@ free_seckey_enc( PKT_signature *sig )
 
   n = pubkey_get_nsig( sig->pubkey_algo );
   if( !n )
-    mpi_free(sig->data[0]);
+    mpi_release(sig->data[0]);
   for(i=0; i < n; i++ )
-    mpi_free( sig->data[i] );
+    mpi_release( sig->data[i] );
 
   xfree(sig->revkey);
   xfree(sig->hashed);
@@ -78,37 +89,60 @@ free_seckey_enc( PKT_signature *sig )
 
 
 void
-release_public_key_parts( PKT_public_key *pk )
+release_public_key_parts (PKT_public_key *pk)
 {
-    int n, i;
-    n = pubkey_get_npkey( pk->pubkey_algo );
-    if( !n )
-       mpi_free(pk->pkey[0]);
-    for(i=0; i < n; i++ ) {
-       mpi_free( pk->pkey[i] );
-       pk->pkey[i] = NULL;
+  int n, i;
+
+  if (pk->seckey_info)
+    n = pubkey_get_nskey (pk->pubkey_algo);
+  else
+    n = pubkey_get_npkey (pk->pubkey_algo);
+  if (!n)
+    mpi_release (pk->pkey[0]);
+  for (i=0; i < n; i++ )
+    {
+      mpi_release (pk->pkey[i]);
+      pk->pkey[i] = NULL;
     }
-    if (pk->prefs) {
-        xfree (pk->prefs);
-        pk->prefs = NULL;
+  if (pk->seckey_info)
+    {
+      xfree (pk->seckey_info);
+      pk->seckey_info = NULL;
     }
-    if (pk->user_id) {
-        free_user_id (pk->user_id);
-        pk->user_id = NULL;
+  if (pk->prefs)
+    {
+      xfree (pk->prefs);
+      pk->prefs = NULL;
+    }
+  if (pk->user_id)
+    {
+      free_user_id (pk->user_id);
+      pk->user_id = NULL;
     }
-    if (pk->revkey) {
-        xfree(pk->revkey);
-       pk->revkey=NULL;
-       pk->numrevkeys=0;
+  if (pk->revkey)
+    {
+      xfree(pk->revkey);
+      pk->revkey=NULL;
+      pk->numrevkeys=0;
+    }
+  if (pk->serialno)
+    {
+      xfree (pk->serialno);
+      pk->serialno = NULL;
     }
 }
 
 
+/* Free an allocated public key structure including all parts.
+   Passing NULL is allowed.  */
 void
-free_public_key( PKT_public_key *pk )
+free_public_key (PKT_public_key *pk)
 {
-    release_public_key_parts( pk );
-    xfree(pk);
+  if (pk)
+    {
+      release_public_key_parts (pk);
+      xfree(pk);
+    }
 }
 
 
@@ -127,7 +161,7 @@ cp_subpktarea (subpktarea_t *s )
 }
 
 /*
- * Return a copy of the preferences 
+ * Return a copy of the preferences
  */
 prefitem_t *
 copy_prefs (const prefitem_t *prefs)
@@ -137,7 +171,7 @@ copy_prefs (const prefitem_t *prefs)
 
     if (!prefs)
         return NULL;
-    
+
     for (n=0; prefs[n].type; n++)
         ;
     new = xmalloc ( sizeof (*new) * (n+1));
@@ -152,62 +186,52 @@ copy_prefs (const prefitem_t *prefs)
 }
 
 
+/* Copy the public key S to D.  If D is NULL allocate a new public key
+   structure.  If S has seckret key infos, only the public stuff is
+   copied.  */
 PKT_public_key *
-copy_public_key ( PKT_public_key *d, PKT_public_key *s)
+copy_public_key (PKT_public_key *d, PKT_public_key *s)
 {
-    int n, i;
+  int n, i;
 
-    if( !d )
-       d = xmalloc(sizeof *d);
-    memcpy( d, s, sizeof *d );
-    d->user_id = scopy_user_id (s->user_id);
-    d->prefs = copy_prefs (s->prefs);
-    n = pubkey_get_npkey( s->pubkey_algo );
-    if( !n )
-       d->pkey[0] = mpi_copy(s->pkey[0]);
-    else {
-       for(i=0; i < n; i++ )
-           d->pkey[i] = mpi_copy( s->pkey[i] );
+  if (!d)
+    d = xmalloc (sizeof *d);
+  memcpy (d, s, sizeof *d);
+  d->seckey_info = NULL;
+  d->user_id = scopy_user_id (s->user_id);
+  d->prefs = copy_prefs (s->prefs);
+
+  n = pubkey_get_npkey (s->pubkey_algo);
+  i = 0;
+  if (!n)
+    d->pkey[i++] = my_mpi_copy (s->pkey[0]);
+  else
+    {
+      for (; i < n; i++ )
+        d->pkey[i] = my_mpi_copy (s->pkey[i]);
     }
-    if( !s->revkey && s->numrevkeys )
-        BUG();
-    if( s->numrevkeys ) {
-        d->revkey = xmalloc(sizeof(struct revocation_key)*s->numrevkeys);
-        memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
+  for (; i < PUBKEY_MAX_NSKEY; i++)
+    d->pkey[i] = NULL;
+
+  if (!s->revkey && s->numrevkeys)
+    BUG();
+  if (s->numrevkeys)
+    {
+      d->revkey = xmalloc(sizeof(struct revocation_key)*s->numrevkeys);
+      memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
     }
-    else
-        d->revkey = NULL;
-    return d;
+  else
+    d->revkey = NULL;
+  return d;
 }
 
-/****************
- * Replace all common parts of a sk by the one from the public key.
- * This is a hack and a better solution will be to just store the real secret
- * parts somewhere and don't duplicate all the other stuff.
- */
-void
-copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
-{
-    sk->expiredate  = pk->expiredate;     
-    sk->pubkey_algo = pk->pubkey_algo;    
-    sk->pubkey_usage= pk->pubkey_usage;
-    sk->req_usage   = pk->req_usage;
-    sk->req_algo    = pk->req_algo;
-    sk->has_expired = pk->has_expired;    
-    sk->is_revoked  = pk->is_revoked;     
-    sk->is_valid    = pk->is_valid;    
-    sk->main_keyid[0]= pk->main_keyid[0];
-    sk->main_keyid[1]= pk->main_keyid[1];
-    sk->keyid[0]    = pk->keyid[0];
-    sk->keyid[1]    = pk->keyid[1];
-}
 
 
 static pka_info_t *
 cp_pka_info (const pka_info_t *s)
 {
   pka_info_t *d = xmalloc (sizeof *s + strlen (s->email));
-  
+
   d->valid = s->valid;
   d->checked = s->checked;
   d->uri = s->uri? xstrdup (s->uri):NULL;
@@ -227,10 +251,10 @@ copy_signature( PKT_signature *d, PKT_signature *s )
     memcpy( d, s, sizeof *d );
     n = pubkey_get_nsig( s->pubkey_algo );
     if( !n )
-       d->data[0] = mpi_copy(s->data[0]);
+       d->data[0] = my_mpi_copy(s->data[0]);
     else {
        for(i=0; i < n; i++ )
-           d->data[i] = mpi_copy( s->data[i] );
+           d->data[i] = my_mpi_copy( s->data[i] );
     }
     d->pka_info = s->pka_info? cp_pka_info (s->pka_info) : NULL;
     d->hashed = cp_subpktarea (s->hashed);
@@ -259,48 +283,6 @@ scopy_user_id (PKT_user_id *s)
 
 
 void
-release_secret_key_parts( PKT_secret_key *sk )
-{
-    int n, i;
-
-    n = pubkey_get_nskey( sk->pubkey_algo );
-    if( !n )
-       mpi_free(sk->skey[0]);
-    for(i=0; i < n; i++ ) {
-       mpi_free( sk->skey[i] );
-       sk->skey[i] = NULL;
-    }
-}
-
-void
-free_secret_key( PKT_secret_key *sk )
-{
-    release_secret_key_parts( sk );
-    xfree(sk);
-}
-
-PKT_secret_key *
-copy_secret_key( PKT_secret_key *d, PKT_secret_key *s )
-{
-    int n, i;
-
-    if( !d )
-       d = xmalloc_secure(sizeof *d);
-    else
-        release_secret_key_parts (d);
-    memcpy( d, s, sizeof *d );
-    n = pubkey_get_nskey( s->pubkey_algo );
-    if( !n )
-       d->skey[0] = mpi_copy(s->skey[0]);
-    else {
-       for(i=0; i < n; i++ )
-           d->skey[i] = mpi_copy( s->skey[i] );
-    }
-
-    return d;
-}
-
-void
 free_comment( PKT_comment *rem )
 {
     xfree(rem);
@@ -409,11 +391,9 @@ free_packet( PACKET *pkt )
        break;
       case PKT_PUBLIC_KEY:
       case PKT_PUBLIC_SUBKEY:
-       free_public_key( pkt->pkt.public_key );
-       break;
       case PKT_SECRET_KEY:
       case PKT_SECRET_SUBKEY:
-       free_secret_key( pkt->pkt.secret_key );
+       free_public_key (pkt->pkt.public_key);
        break;
       case PKT_COMMENT:
        free_comment( pkt->pkt.comment );
@@ -454,68 +434,19 @@ cmp_public_keys( PKT_public_key *a, PKT_public_key *b )
        return -1;
 
     n = pubkey_get_npkey( b->pubkey_algo );
-    if( !n )
-       return -1; /* can't compare due to unknown algorithm */
-    for(i=0; i < n; i++ ) {
-       if( mpi_cmp( a->pkey[i], b->pkey[i] ) )
-           return -1;
-    }
-
-    return 0;
-}
-
-/****************
- * Returns 0 if they match.
- * We only compare the public parts.
- */
-int
-cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b )
-{
-    int n, i;
-
-    if( a->timestamp != b->timestamp )
-       return -1;
-    if( a->version < 4 && a->expiredate != b->expiredate )
-       return -1;
-    if( a->pubkey_algo != b->pubkey_algo )
-       return -1;
-
-    n = pubkey_get_npkey( b->pubkey_algo );
-    if( !n )
-       return -1; /* can't compare due to unknown algorithm */
-    for(i=0; i < n; i++ ) {
-       if( mpi_cmp( a->skey[i], b->skey[i] ) )
-           return -1;
+    if( !n ) { /* unknown algorithm, rest is in opaque MPI */
+       if( mpi_cmp( a->pkey[0], b->pkey[0] ) )
+           return -1; /* can't compare due to unknown algorithm */
+    } else {
+       for(i=0; i < n; i++ ) {
+           if( mpi_cmp( a->pkey[i], b->pkey[i] ) )
+               return -1;
+       }
     }
 
     return 0;
 }
 
-/****************
- * Returns 0 if they match.
- */
-int
-cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
-{
-    int n, i;
-
-    if( pk->timestamp != sk->timestamp )
-       return -1;
-    if( pk->version < 4 && pk->expiredate != sk->expiredate )
-       return -1;
-    if( pk->pubkey_algo != sk->pubkey_algo )
-       return -1;
-
-    n = pubkey_get_npkey( pk->pubkey_algo );
-    if( !n )
-       return -1; /* can't compare due to unknown algorithm */
-    for(i=0; i < n; i++ ) {
-       if( mpi_cmp( pk->pkey[i] , sk->skey[i] ) )
-           return -1;
-    }
-    return 0;
-}
-
 
 
 int