doc: Replace "conventional encryption" by "symmetric encryption".
[gnupg.git] / g10 / free-packet.c
index d998ce2..670f256 100644 (file)
@@ -1,21 +1,21 @@
 /* free-packet.c - cleanup stuff for packets
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
+ *               2005, 2010  Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * 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,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 )
 {
-    m_free(enc);
+    xfree(enc);
 }
 
 void
 free_pubkey_enc( PKT_pubkey_enc *enc )
 {
-    if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       mpi_free( enc->d.elg.a );
-       mpi_free( enc->d.elg.b );
-    }
-    else if( enc->pubkey_algo == PUBKEY_ALGO_RSA )
-       mpi_free( enc->d.rsa.rsa_integer );
-    m_free(enc);
+    int n, i;
+    n = pubkey_get_nenc( enc->pubkey_algo );
+    if( !n )
+       mpi_release(enc->data[0]);
+    for(i=0; i < n; i++ )
+       mpi_release( enc->data[i] );
+    xfree(enc);
 }
 
 void
 free_seckey_enc( PKT_signature *sig )
 {
-    if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       mpi_free( sig->d.elg.a );
-       mpi_free( sig->d.elg.b );
+  int n, i;
+
+  n = pubkey_get_nsig( sig->pubkey_algo );
+  if( !n )
+    mpi_release(sig->data[0]);
+  for(i=0; i < n; i++ )
+    mpi_release( sig->data[i] );
+
+  xfree(sig->revkey);
+  xfree(sig->hashed);
+  xfree(sig->unhashed);
+
+  if (sig->pka_info)
+    {
+      xfree (sig->pka_info->uri);
+      xfree (sig->pka_info);
     }
-    else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) {
-       mpi_free( sig->d.dsa.r );
-       mpi_free( sig->d.dsa.s );
-    }
-    else if( sig->pubkey_algo == PUBKEY_ALGO_RSA )
-       mpi_free( sig->d.rsa.rsa_integer );
-    m_free(sig->hashed_data);
-    m_free(sig->unhashed_data);
-    m_free(sig);
-}
-
 
-/****************
- * Return the digest algorithm from the signature packet.
- * We need this function because the digest algo depends on the
- * used pubkey algorithm.
- */
-int
-digest_algo_from_sig( PKT_signature *sig )
-{
-  #if 0 /* not used anymore */
-    switch( sig->pubkey_algo ) {
-      case PUBKEY_ALGO_ELGAMAL: return sig->d.elg.digest_algo;
-      case PUBKEY_ALGO_DSA:    return sig->d.dsa.digest_algo;
-      case PUBKEY_ALGO_RSA:    return sig->d.rsa.digest_algo;
-      default: return 0;
-    }
-  #endif
-    return sig->digest_algo;
+  xfree(sig);
 }
 
 
-
-
 void
-release_public_cert_parts( PKT_public_cert *cert )
+release_public_key_parts (PKT_public_key *pk)
 {
-    if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       mpi_free( cert->d.elg.p ); cert->d.elg.p = NULL;
-       mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL;
-       mpi_free( cert->d.elg.y ); cert->d.elg.y = 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->seckey_info)
+    {
+      xfree (pk->seckey_info);
+      pk->seckey_info = NULL;
+    }
+  if (pk->prefs)
+    {
+      xfree (pk->prefs);
+      pk->prefs = NULL;
     }
-    else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) {
-       mpi_free( cert->d.dsa.p ); cert->d.dsa.p = NULL;
-       mpi_free( cert->d.dsa.q ); cert->d.dsa.q = NULL;
-       mpi_free( cert->d.dsa.g ); cert->d.dsa.g = NULL;
-       mpi_free( cert->d.dsa.y ); cert->d.dsa.y = NULL;
+  if (pk->user_id)
+    {
+      free_user_id (pk->user_id);
+      pk->user_id = NULL;
     }
-    else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) {
-       mpi_free( cert->d.rsa.n ); cert->d.rsa.n = NULL;
-       mpi_free( cert->d.rsa.e ); cert->d.rsa.e = NULL;
+  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_cert( PKT_public_cert *cert )
+free_public_key (PKT_public_key *pk)
 {
-    release_public_cert_parts( cert );
-    m_free(cert);
+  if (pk)
+    {
+      release_public_key_parts (pk);
+      xfree(pk);
+    }
 }
 
-PKT_public_cert *
-copy_public_cert( PKT_public_cert *d, PKT_public_cert *s )
+
+static subpktarea_t *
+cp_subpktarea (subpktarea_t *s )
 {
-    if( !d )
-       d = m_alloc(sizeof *d);
-    memcpy( d, s, sizeof *d );
-    if( s->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       d->d.elg.p = mpi_copy( s->d.elg.p );
-       d->d.elg.g = mpi_copy( s->d.elg.g );
-       d->d.elg.y = mpi_copy( s->d.elg.y );
-    }
-    else if( s->pubkey_algo == PUBKEY_ALGO_DSA ) {
-       d->d.dsa.p = mpi_copy( s->d.dsa.p );
-       d->d.dsa.q = mpi_copy( s->d.dsa.q );
-       d->d.dsa.g = mpi_copy( s->d.dsa.g );
-       d->d.dsa.y = mpi_copy( s->d.dsa.y );
-    }
-    else if( s->pubkey_algo == PUBKEY_ALGO_RSA ) {
-       d->d.rsa.n = mpi_copy( s->d.rsa.n );
-       d->d.rsa.e = mpi_copy( s->d.rsa.e );
-    }
+    subpktarea_t *d;
+
+    if( !s )
+       return NULL;
+    d = xmalloc (sizeof (*d) + s->size - 1 );
+    d->size = s->size;
+    d->len = s->len;
+    memcpy (d->data, s->data, s->len);
     return d;
 }
 
-void
-release_secret_cert_parts( PKT_secret_cert *cert )
+/*
+ * Return a copy of the preferences
+ */
+prefitem_t *
+copy_prefs (const prefitem_t *prefs)
 {
-    if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       mpi_free( cert->d.elg.p ); cert->d.elg.p = NULL;
-       mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL;
-       mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL;
-       mpi_free( cert->d.elg.x ); cert->d.elg.x = NULL;
+    size_t n;
+    prefitem_t *new;
+
+    if (!prefs)
+        return NULL;
+
+    for (n=0; prefs[n].type; n++)
+        ;
+    new = xmalloc ( sizeof (*new) * (n+1));
+    for (n=0; prefs[n].type; n++) {
+        new[n].type = prefs[n].type;
+        new[n].value = prefs[n].value;
     }
-    else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) {
-       mpi_free( cert->d.dsa.p ); cert->d.dsa.p = NULL;
-       mpi_free( cert->d.dsa.q ); cert->d.dsa.q = NULL;
-       mpi_free( cert->d.dsa.g ); cert->d.dsa.g = NULL;
-       mpi_free( cert->d.dsa.y ); cert->d.dsa.y = NULL;
-       mpi_free( cert->d.dsa.x ); cert->d.dsa.x = NULL;
+    new[n].type = PREFTYPE_NONE;
+    new[n].value = 0;
+
+    return new;
+}
+
+
+/* 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)
+{
+  int n, 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]);
     }
-    else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) {
-       mpi_free( cert->d.rsa.n ); cert->d.rsa.n = NULL;
-       mpi_free( cert->d.rsa.e ); cert->d.rsa.e = NULL;
-       mpi_free( cert->d.rsa.d ); cert->d.rsa.d = NULL;
-       mpi_free( cert->d.rsa.p ); cert->d.rsa.p = NULL;
-       mpi_free( cert->d.rsa.q ); cert->d.rsa.q = NULL;
-       mpi_free( cert->d.rsa.u ); cert->d.rsa.u = NULL;
+  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;
 }
 
-void
-free_secret_cert( PKT_secret_cert *cert )
+
+
+static pka_info_t *
+cp_pka_info (const pka_info_t *s)
 {
-    release_secret_cert_parts( cert );
-    m_free(cert);
+  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;
+  memcpy (d->fpr, s->fpr, sizeof s->fpr);
+  strcpy (d->email, s->email);
+  return d;
 }
 
-PKT_secret_cert *
-copy_secret_cert( PKT_secret_cert *d, PKT_secret_cert *s )
+
+PKT_signature *
+copy_signature( PKT_signature *d, PKT_signature *s )
 {
+    int n, i;
+
     if( !d )
-       d = m_alloc(sizeof *d);
+       d = xmalloc(sizeof *d);
     memcpy( d, s, sizeof *d );
-    if( s->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       d->d.elg.p = mpi_copy( s->d.elg.p );
-       d->d.elg.g = mpi_copy( s->d.elg.g );
-       d->d.elg.y = mpi_copy( s->d.elg.y );
-       d->d.elg.x = mpi_copy( s->d.elg.x );
-    }
-    else if( s->pubkey_algo == PUBKEY_ALGO_DSA ) {
-       d->d.dsa.p = mpi_copy( s->d.dsa.p );
-       d->d.dsa.q = mpi_copy( s->d.dsa.q );
-       d->d.dsa.g = mpi_copy( s->d.dsa.g );
-       d->d.dsa.y = mpi_copy( s->d.dsa.y );
-       d->d.dsa.x = mpi_copy( s->d.dsa.x );
-    }
-    else if( s->pubkey_algo == PUBKEY_ALGO_RSA ) {
-       d->d.rsa.n = mpi_copy( s->d.rsa.n );
-       d->d.rsa.e = mpi_copy( s->d.rsa.e );
-       d->d.rsa.d = mpi_copy( s->d.rsa.d );
-       d->d.rsa.p = mpi_copy( s->d.rsa.p );
-       d->d.rsa.q = mpi_copy( s->d.rsa.q );
-       d->d.rsa.u = mpi_copy( s->d.rsa.u );
+    n = pubkey_get_nsig( s->pubkey_algo );
+    if( !n )
+       d->data[0] = my_mpi_copy(s->data[0]);
+    else {
+       for(i=0; i < n; 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->numrevkeys)
+      {
+       d->revkey=NULL;
+       d->numrevkeys=0;
+       parse_revkeys(d);
+      }
     return d;
 }
 
+
+/*
+ * shallow copy of the user ID
+ */
+PKT_user_id *
+scopy_user_id (PKT_user_id *s)
+{
+    if (s)
+        s->ref++;
+    return s;
+}
+
+
+
 void
 free_comment( PKT_comment *rem )
 {
-    m_free(rem);
+    xfree(rem);
+}
+
+void
+free_attributes(PKT_user_id *uid)
+{
+  xfree(uid->attribs);
+  xfree(uid->attrib_data);
+
+  uid->attribs=NULL;
+  uid->attrib_data=NULL;
+  uid->attrib_len=0;
 }
 
 void
-free_user_id( PKT_user_id *uid )
+free_user_id (PKT_user_id *uid)
 {
-    m_free(uid);
+    assert (uid->ref > 0);
+    if (--uid->ref)
+        return;
+
+    free_attributes(uid);
+    xfree (uid->prefs);
+    xfree (uid->namehash);
+    xfree (uid);
 }
 
 void
@@ -222,27 +318,31 @@ 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_get(zd->buf) != -1 )
+       while( iobuf_read( zd->buf, NULL, 1<<30 ) != -1 )
            ;
     }
-    m_free(zd);
+    xfree(zd);
 }
 
 void
 free_encrypted( PKT_encrypted *ed )
 {
     if( ed->buf ) { /* have to skip some bytes */
-       if( iobuf_in_block_mode(ed->buf) ) {
-           while( iobuf_get(ed->buf) != -1 )
+       if( ed->is_partial ) {
+           while( iobuf_read( ed->buf, NULL, 1<<30 ) != -1 )
                ;
-           iobuf_set_block_mode(ed->buf, 0);
        }
        else {
-           for( ; ed->len; ed->len-- ) /* skip the packet */
-               iobuf_get(ed->buf);
+          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;
+          }
        }
     }
-    m_free(ed);
+    xfree(ed);
 }
 
 
@@ -250,17 +350,21 @@ void
 free_plaintext( PKT_plaintext *pt )
 {
     if( pt->buf ) { /* have to skip some bytes */
-       if( iobuf_in_block_mode(pt->buf) ) {
-           while( iobuf_get(pt->buf) != -1 )
+       if( pt->is_partial ) {
+           while( iobuf_read( pt->buf, NULL, 1<<30 ) != -1 )
                ;
-           iobuf_set_block_mode(pt->buf, 0);
        }
        else {
-           for( ; pt->len; pt->len-- ) /* skip the packet */
-               iobuf_get(pt->buf);
+          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;
+          }
        }
     }
-    m_free(pt);
+    xfree(pt);
 }
 
 /****************
@@ -285,11 +389,11 @@ free_packet( PACKET *pkt )
       case PKT_SYMKEY_ENC:
        free_symkey_enc( pkt->pkt.symkey_enc );
        break;
-      case PKT_PUBLIC_CERT:
-       free_public_cert( pkt->pkt.public_cert );
-       break;
-      case PKT_SECRET_CERT:
-       free_secret_cert( pkt->pkt.secret_cert );
+      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 );
@@ -301,109 +405,96 @@ free_packet( PACKET *pkt )
        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:
-       m_free( pkt->pkt.generic );
+       xfree( pkt->pkt.generic );
        break;
     }
     pkt->pkt.generic = NULL;
 }
 
 /****************
- * Returns 0 if they match.
+ * returns 0 if they match.
  */
 int
-cmp_public_certs( PKT_public_cert *a, PKT_public_cert *b )
+cmp_public_keys( PKT_public_key *a, PKT_public_key *b )
 {
+    int n, i;
+
     if( a->timestamp != b->timestamp )
        return -1;
-    if( a->valid_days != b->valid_days )
+    if( a->version < 4 && a->expiredate != b->expiredate )
        return -1;
     if( a->pubkey_algo != b->pubkey_algo )
        return -1;
 
-    if( a->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       if( mpi_cmp( a->d.elg.p , b->d.elg.p ) )
-           return -1;
-       if( mpi_cmp( a->d.elg.g , b->d.elg.g ) )
-           return -1;
-       if( mpi_cmp( a->d.elg.y , b->d.elg.y ) )
-           return -1;
-    }
-    else if( a->pubkey_algo == PUBKEY_ALGO_DSA ) {
-       if( mpi_cmp( a->d.dsa.p , b->d.dsa.p ) )
-           return -1;
-       if( mpi_cmp( a->d.dsa.q , b->d.dsa.q ) )
-           return -1;
-       if( mpi_cmp( a->d.dsa.g , b->d.dsa.g ) )
-           return -1;
-       if( mpi_cmp( a->d.dsa.y , b->d.dsa.y ) )
-           return -1;
-    }
-    else if( a->pubkey_algo == PUBKEY_ALGO_RSA ) {
-       if( mpi_cmp( a->d.rsa.n , b->d.rsa.n ) )
-           return -1;
-       if( mpi_cmp( a->d.rsa.e , b->d.rsa.e ) )
-           return -1;
+    n = pubkey_get_npkey( b->pubkey_algo );
+    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_cert( PKT_public_cert *pkc, PKT_secret_cert *skc )
+cmp_signatures( PKT_signature *a, PKT_signature *b )
 {
-    if( pkc->timestamp != skc->timestamp )
+    int n, i;
+
+    if( a->keyid[0] != b->keyid[0] )
        return -1;
-    if( pkc->valid_days != skc->valid_days )
+    if( a->keyid[1] != b->keyid[1] )
        return -1;
-    if( pkc->pubkey_algo != skc->pubkey_algo )
+    if( a->pubkey_algo != b->pubkey_algo )
        return -1;
 
-    if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
-       if( mpi_cmp( pkc->d.elg.p , skc->d.elg.p ) )
-           return -1;
-       if( mpi_cmp( pkc->d.elg.g , skc->d.elg.g ) )
-           return -1;
-       if( mpi_cmp( pkc->d.elg.y , skc->d.elg.y ) )
+    n = pubkey_get_nsig( a->pubkey_algo );
+    if( !n )
+       return -1; /* can't compare due to unknown algorithm */
+    for(i=0; i < n; i++ ) {
+       if( mpi_cmp( a->data[i] , b->data[i] ) )
            return -1;
     }
-    else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) {
-       if( mpi_cmp( pkc->d.dsa.p , skc->d.dsa.p ) )
-           return -1;
-       if( mpi_cmp( pkc->d.dsa.q , skc->d.dsa.q ) )
-           return -1;
-       if( mpi_cmp( pkc->d.dsa.g , skc->d.dsa.g ) )
-           return -1;
-       if( mpi_cmp( pkc->d.dsa.y , skc->d.dsa.y ) )
-           return -1;
-    }
-    else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
-       if( mpi_cmp( pkc->d.rsa.n , skc->d.rsa.n ) )
-           return -1;
-       if( mpi_cmp( pkc->d.rsa.e , skc->d.rsa.e ) )
-           return -1;
-    }
-
     return 0;
 }
 
+
+/****************
+ * Returns: true if the user ids do not match
+ */
 int
 cmp_user_ids( PKT_user_id *a, PKT_user_id *b )
 {
-    int res;
+    int res=1;
+
+    if( a == b )
+        return 0;
+
+    if( a->attrib_data && b->attrib_data )
+      {
+       res = a->attrib_len - b->attrib_len;
+       if( !res )
+         res = memcmp( a->attrib_data, b->attrib_data, a->attrib_len );
+      }
+    else if( !a->attrib_data && !b->attrib_data )
+      {
+       res = a->len - b->len;
+       if( !res )
+         res = memcmp( a->name, b->name, a->len );
+      }
 
-    res = a->len - b->len;
-    if( !res )
-       res = memcmp( a->name, b->name, a->len );
     return res;
 }
-
-