indent: Fix indentation of read_block in g10/import.c
[gnupg.git] / g10 / free-packet.c
index 47d89ee..e15ad3f 100644 (file)
  * 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, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
+#include "../common/util.h"
 #include "packet.h"
 #include "../common/iobuf.h"
-#include "util.h"
-#include "cipher.h"
-#include "options.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
@@ -70,6 +82,7 @@ free_seckey_enc( PKT_signature *sig )
       xfree (sig->pka_info->uri);
       xfree (sig->pka_info);
     }
+  xfree (sig->signers_uid);
 
   xfree(sig);
 }
@@ -79,7 +92,7 @@ void
 release_public_key_parts (PKT_public_key *pk)
 {
   int n, i;
-  
+
   if (pk->seckey_info)
     n = pubkey_get_nskey (pk->pubkey_algo);
   else
@@ -101,26 +114,37 @@ release_public_key_parts (PKT_public_key *pk)
       xfree (pk->prefs);
       pk->prefs = NULL;
     }
-  if (pk->user_id)
-    {
-      free_user_id (pk->user_id);
-      pk->user_id = NULL;
-    }
+  free_user_id (pk->user_id);
+  pk->user_id = NULL;
   if (pk->revkey)
     {
       xfree(pk->revkey);
       pk->revkey=NULL;
       pk->numrevkeys=0;
     }
-
+  if (pk->serialno)
+    {
+      xfree (pk->serialno);
+      pk->serialno = NULL;
+    }
+  if (pk->updateurl)
+    {
+      xfree (pk->updateurl);
+      pk->updateurl = NULL;
+    }
 }
 
 
+/* Free an allocated public key structure including all parts.
+   Passing NULL is allowed.  */
 void
 free_public_key (PKT_public_key *pk)
 {
-  release_public_key_parts (pk);
-  xfree(pk);
+  if (pk)
+    {
+      release_public_key_parts (pk);
+      xfree(pk);
+    }
 }
 
 
@@ -139,7 +163,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)
@@ -149,7 +173,7 @@ copy_prefs (const prefitem_t *prefs)
 
     if (!prefs)
         return NULL;
-    
+
     for (n=0; prefs[n].type; n++)
         ;
     new = xmalloc ( sizeof (*new) * (n+1));
@@ -171,22 +195,22 @@ PKT_public_key *
 copy_public_key (PKT_public_key *d, PKT_public_key *s)
 {
   int n, i;
-  
+
   if (!d)
     d = xmalloc (sizeof *d);
   memcpy (d, s, sizeof *d);
-  d->seckey_info = NULL; 
+  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++] = mpi_copy (s->pkey[0]);
-  else 
+    d->pkey[i++] = my_mpi_copy (s->pkey[0]);
+  else
     {
       for (; i < n; i++ )
-        d->pkey[i] = mpi_copy( s->pkey[i] );
+        d->pkey[i] = my_mpi_copy (s->pkey[i]);
     }
   for (; i < PUBKEY_MAX_NSKEY; i++)
     d->pkey[i] = NULL;
@@ -200,6 +224,12 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
     }
   else
     d->revkey = NULL;
+
+  if (s->serialno)
+    d->serialno = xstrdup (s->serialno);
+  if (s->updateurl)
+    d->updateurl = xstrdup (s->updateurl);
+
   return d;
 }
 
@@ -209,7 +239,7 @@ 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;
@@ -229,14 +259,16 @@ 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);
     d->unhashed = cp_subpktarea (s->unhashed);
+    if (s->signers_uid)
+      d->signers_uid = xstrdup (s->signers_uid);
     if(s->numrevkeys)
       {
        d->revkey=NULL;
@@ -269,6 +301,9 @@ free_comment( PKT_comment *rem )
 void
 free_attributes(PKT_user_id *uid)
 {
+  if (!uid)
+    return;
+
   xfree(uid->attribs);
   xfree(uid->attrib_data);
 
@@ -280,122 +315,177 @@ free_attributes(PKT_user_id *uid)
 void
 free_user_id (PKT_user_id *uid)
 {
-    assert (uid->ref > 0);
-    if (--uid->ref)
-        return;
-
-    free_attributes(uid);
-    xfree (uid->prefs);
-    xfree (uid->namehash);
-    xfree (uid);
+  if (!uid)
+    return;
+
+  log_assert (uid->ref > 0);
+  if (--uid->ref)
+    return;
+
+  free_attributes(uid);
+  xfree (uid->prefs);
+  xfree (uid->namehash);
+  xfree (uid->updateurl);
+  xfree (uid->mbox);
+  xfree (uid);
 }
 
 void
 free_compressed( PKT_compressed *zd )
 {
-    if( zd->buf ) { /* have to skip some bytes */
-       /* don't have any information about the length, so
-        * we assume this is the last packet */
-       while( iobuf_read( zd->buf, NULL, 1<<30 ) != -1 )
-           ;
+  if (!zd)
+    return;
+
+  if (zd->buf)
+    {
+      /* We need to skip some bytes.  Because don't have any
+       * information about the length, so we assume this is the last
+       * packet */
+      while (iobuf_read( zd->buf, NULL, 1<<30 ) != -1)
+        ;
     }
-    xfree(zd);
+  xfree(zd);
 }
 
 void
 free_encrypted( PKT_encrypted *ed )
 {
-    if( ed->buf ) { /* have to skip some bytes */
-       if( ed->is_partial ) {
-           while( iobuf_read( ed->buf, NULL, 1<<30 ) != -1 )
-               ;
+  if (!ed)
+    return;
+
+  if (ed->buf)
+    {
+      /* We need to skip some bytes. */
+      if (ed->is_partial)
+        {
+          while (iobuf_read( ed->buf, NULL, 1<<30 ) != -1)
+            ;
        }
-       else {
-          while( ed->len ) { /* skip the packet */
-              int n = iobuf_read( ed->buf, NULL, ed->len );
-              if( n == -1 )
-                  ed->len = 0;
-              else
-                  ed->len -= n;
-          }
+      else
+        {
+          while (ed->len)
+            {
+              /* Skip the packet. */
+              int n = iobuf_read( ed->buf, NULL, ed->len );
+              if (n == -1)
+                ed->len = 0;
+              else
+                ed->len -= n;
+            }
        }
     }
-    xfree(ed);
+  xfree (ed);
 }
 
 
 void
 free_plaintext( PKT_plaintext *pt )
 {
-    if( pt->buf ) { /* have to skip some bytes */
-       if( pt->is_partial ) {
-           while( iobuf_read( pt->buf, NULL, 1<<30 ) != -1 )
-               ;
-       }
-       else {
-          while( pt->len ) { /* skip the packet */
-              int n = iobuf_read( pt->buf, NULL, pt->len );
-              if( n == -1 )
-                  pt->len = 0;
-              else
-                  pt->len -= n;
-          }
+  if (!pt)
+    return;
+
+  if (pt->buf)
+    { /* We need to skip some bytes.  */
+      if (pt->is_partial)
+        {
+          while (iobuf_read( pt->buf, NULL, 1<<30 ) != -1)
+            ;
+        }
+      else
+        {
+          while( pt->len )
+            { /* Skip the packet.  */
+              int n = iobuf_read( pt->buf, NULL, pt->len );
+              if (n == -1)
+                pt->len = 0;
+              else
+                pt->len -= n;
+            }
        }
     }
-    xfree(pt);
+  xfree (pt);
 }
 
+
 /****************
- * Free the packet in pkt.
+ * Free the packet in PKT.
  */
 void
-free_packet( PACKET *pkt )
+free_packet (PACKET *pkt, parse_packet_ctx_t parsectx)
 {
-    if( !pkt || !pkt->pkt.generic )
-       return;
-
-    if( DBG_MEMORY )
-       log_debug("free_packet() type=%d\n", pkt->pkttype );
-
-    switch( pkt->pkttype ) {
-      case PKT_SIGNATURE:
-       free_seckey_enc( pkt->pkt.signature );
-       break;
-      case PKT_PUBKEY_ENC:
-       free_pubkey_enc( pkt->pkt.pubkey_enc );
-       break;
-      case PKT_SYMKEY_ENC:
-       free_symkey_enc( pkt->pkt.symkey_enc );
-       break;
-      case PKT_PUBLIC_KEY:
-      case PKT_PUBLIC_SUBKEY:
-      case PKT_SECRET_KEY:
-      case PKT_SECRET_SUBKEY:
-       free_public_key (pkt->pkt.public_key);
-       break;
-      case PKT_COMMENT:
-       free_comment( pkt->pkt.comment );
-       break;
-      case PKT_USER_ID:
-       free_user_id( pkt->pkt.user_id );
-       break;
-      case PKT_COMPRESSED:
-       free_compressed( pkt->pkt.compressed);
-       break;
-      case PKT_ENCRYPTED:
-      case PKT_ENCRYPTED_MDC:
-       free_encrypted( pkt->pkt.encrypted );
-       break;
-      case PKT_PLAINTEXT:
-       free_plaintext( pkt->pkt.plaintext );
-       break;
-      default:
-       xfree( pkt->pkt.generic );
-       break;
+  if (!pkt || !pkt->pkt.generic)
+    {
+      if (parsectx && parsectx->last_pkt.pkt.generic)
+        {
+          if (parsectx->free_last_pkt)
+            {
+              free_packet (&parsectx->last_pkt, NULL);
+              parsectx->free_last_pkt = 0;
+            }
+          parsectx->last_pkt.pkttype = 0;
+          parsectx->last_pkt.pkt.generic = NULL;
+        }
+      return;
+    }
+
+  if (DBG_MEMORY)
+    log_debug ("free_packet() type=%d\n", pkt->pkttype);
+
+  /* If we have a parser context holding PKT then do not free the
+   * packet but set a flag that the packet in the parser context is
+   * now a deep copy.  */
+  if (parsectx && !parsectx->free_last_pkt
+      && parsectx->last_pkt.pkttype == pkt->pkttype
+      && parsectx->last_pkt.pkt.generic == pkt->pkt.generic)
+    {
+      parsectx->last_pkt = *pkt;
+      parsectx->free_last_pkt = 1;
+      pkt->pkt.generic = NULL;
+      return;
+    }
+
+  switch (pkt->pkttype)
+    {
+    case PKT_SIGNATURE:
+      free_seckey_enc (pkt->pkt.signature);
+      break;
+    case PKT_PUBKEY_ENC:
+      free_pubkey_enc (pkt->pkt.pubkey_enc);
+      break;
+    case PKT_SYMKEY_ENC:
+      free_symkey_enc (pkt->pkt.symkey_enc);
+      break;
+    case PKT_PUBLIC_KEY:
+    case PKT_PUBLIC_SUBKEY:
+    case PKT_SECRET_KEY:
+    case PKT_SECRET_SUBKEY:
+      free_public_key (pkt->pkt.public_key);
+      break;
+    case PKT_COMMENT:
+      free_comment (pkt->pkt.comment);
+      break;
+    case PKT_USER_ID:
+      free_user_id (pkt->pkt.user_id);
+      break;
+    case PKT_COMPRESSED:
+      free_compressed (pkt->pkt.compressed);
+      break;
+    case PKT_ENCRYPTED:
+    case PKT_ENCRYPTED_MDC:
+      free_encrypted (pkt->pkt.encrypted);
+      break;
+    case PKT_PLAINTEXT:
+      free_plaintext (pkt->pkt.plaintext);
+      break;
+    default:
+      xfree (pkt->pkt.generic);
+      break;
     }
-    pkt->pkt.generic = NULL;
+
+  pkt->pkt.generic = NULL;
 }
 
+
 /****************
  * returns 0 if they match.
  */
@@ -412,11 +502,14 @@ 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;
+    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;