Add readcert command.
[gnupg.git] / g10 / import.c
index a3d0fec..88eb24e 100644 (file)
@@ -1,6 +1,6 @@
 /* import.c - import a key into our key storage.
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- *               2006 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ *               2007 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -28,7 +28,7 @@
 #include "gpg.h"
 #include "options.h"
 #include "packet.h"
-#include "errors.h"
+#include "status.h"
 #include "keydb.h"
 #include "util.h"
 #include "trustdb.h"
@@ -602,9 +602,9 @@ check_prefs(KBNODE keyblock)
                  if (openpgp_cipher_test_algo (prefs->value))
                    {
                      const char *algo = 
-                        (gcry_cipher_test_algo (prefs->value)
+                        (openpgp_cipher_test_algo (prefs->value)
                          ? num 
-                         : gcry_cipher_algo_name (prefs->value));
+                         : openpgp_cipher_algo_name (prefs->value));
                      if(!problem)
                        check_prefs_warning(pk);
                      log_info(_("         \"%s\": preference for cipher"
@@ -682,7 +682,7 @@ check_prefs(KBNODE keyblock)
  * Try to import one keyblock. Return an error only in serious cases, but
  * never for an invalid keyblock.  It uses log_error to increase the
  * internal errorcount, so that invalid input can be detected by programs
- * which called g10.
+ * which called gpg.
  */
 static int
 import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
@@ -697,6 +697,7 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
     int rc = 0;
     int new_key = 0;
     int mod_key = 0;
+    int same_key = 0;
     int non_self = 0;
 
     /* get the key and print some info about it */
@@ -715,12 +716,14 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
                  nbits_from_pk( pk ),
                  pubkey_letter( pk->pubkey_algo ),
                  keystr_from_pk(pk), datestr_from_pk(pk) );
-       if( uidnode )
-         print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name,
+       if (uidnode)
+         print_utf8_string (log_get_stream (),
+                             uidnode->pkt->pkt.user_id->name,
                             uidnode->pkt->pkt.user_id->len );
        log_printf ("\n");
       }
 
+
     if( !uidnode )
       {
        log_error( _("key %s: no user ID\n"), keystr_from_pk(pk));
@@ -958,7 +961,8 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
        }
        else
          {
-           if (is_status_enabled ()) 
+            same_key = 1;
+            if (is_status_enabled ()) 
              print_import_ok (pk, NULL, 0);
 
            if( !opt.quiet )
@@ -975,6 +979,33 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
     }
 
   leave:
+    if (mod_key || new_key || same_key)
+      {
+       /* A little explanation for this: we fill in the fingerprint
+          when importing keys as it can be useful to know the
+          fingerprint in certain keyserver-related cases (a keyserver
+          asked for a particular name, but the key doesn't have that
+          name).  However, in cases where we're importing more than
+          one key at a time, we cannot know which key to fingerprint.
+          In these cases, rather than guessing, we do not
+          fingerprinting at all, and we must hope the user ID on the
+          keys are useful.  Note that we need to do this for new
+          keys, merged keys and even for unchanged keys.  This is
+          required because for example the --auto-key-locate feature
+          may import an already imported key and needs to know the
+          fingerprint of the key in all cases.  */
+       if (fpr)
+         {
+           xfree (*fpr);
+            /* Note that we need to compare against 0 here because
+               COUNT gets only incremented after returning form this
+               function.  */
+           if (stats->count == 0)
+             *fpr = fingerprint_from_pk (pk, NULL, fpr_len);
+           else
+             *fpr = NULL;
+         }
+      }
 
     /* Now that the key is definitely incorporated into the keydb, we
        need to check if a designated revocation is present or if the
@@ -988,24 +1019,6 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
       }
     else if(new_key)
       {
-       /* A little explanation for this: we fill in the fingerprint
-          when importing keys as it can be useful to know the
-          fingerprint in certain keyserver-related cases (a keyserver
-          asked for a particular name, but the key doesn't have that
-          name).  However, in cases where we're importing more than
-          one key at a time, we cannot know which key to fingerprint.
-          In these cases, rather than guessing, we do not fingerpring
-          at all, and we must hope the user ID on the keys are
-          useful. */
-       if(fpr)
-         {
-           xfree(*fpr);
-           if(stats->imported==1)
-             *fpr=fingerprint_from_pk(pk,NULL,fpr_len);
-           else
-             *fpr=NULL;
-         }
-
        revocation_present(keyblock);
        if(!from_sk && seckey_available(keyid)==0)
          check_prefs(keyblock);
@@ -1225,6 +1238,8 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
     u32 keyid[2];
     int rc = 0;
 
+    (void)fname;
+
     assert( !node->next );
     assert( node->pkt->pkttype == PKT_SIGNATURE );
     assert( node->pkt->pkt.signature->sig_class == 0x20 );
@@ -1352,6 +1367,9 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
     u32 bsdate=0,rsdate=0;
     KBNODE bsnode=NULL,rsnode=NULL;
 
+    (void)fname;
+    (void)pk;
+
     for( n=keyblock; (n = find_next_kbnode(n, 0)); ) {
       if(n->pkt->pkttype==PKT_PUBLIC_SUBKEY)
        {
@@ -1524,6 +1542,8 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
     KBNODE node;
     int nvalid=0, uid_seen=0, subkey_seen=0;
 
+    (void)fname;
+
     for(node=keyblock->next; node; node = node->next ) {
        if( node->pkt->pkttype == PKT_USER_ID ) {
            uid_seen = 1;
@@ -1649,90 +1669,119 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
  * It may happen that the imported keyblock has duplicated user IDs.
  * We check this here and collapse those user IDs together with their
  * sigs into one.
- * Returns: True if the keyblock hash changed.
+ * Returns: True if the keyblock has changed.
  */
 int
 collapse_uids( KBNODE *keyblock )
 {
-    KBNODE n, n2;
-    int in_uid;
-    int any=0;
+  KBNODE uid1;
+  int any=0;
+
+  for(uid1=*keyblock;uid1;uid1=uid1->next)
+    {
+      KBNODE uid2;
+
+      if(is_deleted_kbnode(uid1))
+       continue;
+
+      if(uid1->pkt->pkttype!=PKT_USER_ID)
+       continue;
 
-  restart:
-    for( n = *keyblock; n; n = n->next ) {
-       if( n->pkt->pkttype != PKT_USER_ID )
+      for(uid2=uid1->next;uid2;uid2=uid2->next)
+       {
+         if(is_deleted_kbnode(uid2))
            continue;
-       for( n2 = n->next; n2; n2 = n2->next ) {
-           if( n2->pkt->pkttype == PKT_USER_ID
-               && !cmp_user_ids( n->pkt->pkt.user_id,
-                                 n2->pkt->pkt.user_id ) ) {
-               /* found a duplicate */
-               any = 1;
-               if( !n2->next
-                   || n2->next->pkt->pkttype == PKT_USER_ID
-                   || n2->next->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                   || n2->next->pkt->pkttype == PKT_SECRET_SUBKEY  ) {
-                   /* no more signatures: delete the user ID
-                    * and start over */
-                   remove_kbnode( keyblock, n2 );
-               }
-               else {
-                   /* The simple approach: Move one signature and
-                    * then start over to delete the next one :-( */
-                   move_kbnode( keyblock, n2->next, n->next );
+
+         if(uid2->pkt->pkttype!=PKT_USER_ID)
+           continue;
+
+         if(cmp_user_ids(uid1->pkt->pkt.user_id,
+                         uid2->pkt->pkt.user_id)==0)
+           {
+             /* We have a duplicated uid */
+             KBNODE sig1,last;
+
+             any=1;
+
+             /* Now take uid2's signatures, and attach them to
+                uid1 */
+             for(last=uid2;last->next;last=last->next)
+               {
+                 if(is_deleted_kbnode(last))
+                   continue;
+
+                 if(last->next->pkt->pkttype==PKT_USER_ID
+                    || last->next->pkt->pkttype==PKT_PUBLIC_SUBKEY
+                    || last->next->pkt->pkttype==PKT_SECRET_SUBKEY)
+                   break;
                }
-               goto restart;
-           }
-       }
-    }
-    if( !any )
-       return 0;
 
-  restart_sig:
-    /* now we may have duplicate signatures on one user ID: fix this */
-    for( in_uid = 0, n = *keyblock; n; n = n->next ) {
-       if( n->pkt->pkttype == PKT_USER_ID )
-           in_uid = 1;
-       else if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                || n->pkt->pkttype == PKT_SECRET_SUBKEY )
-           in_uid = 0;
-       else if( in_uid ) {
-           n2 = n;
-           do {
-               KBNODE ncmp = NULL;
-               for( ; n2; n2 = n2->next ) {
-                   if(    n2->pkt->pkttype == PKT_USER_ID
-                       || n2->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                       || n2->pkt->pkttype == PKT_SECRET_SUBKEY )
+             /* Snip out uid2 */
+             (find_prev_kbnode(*keyblock,uid2,0))->next=last->next;
+
+             /* Now put uid2 in place as part of uid1 */
+             last->next=uid1->next;
+             uid1->next=uid2;
+             delete_kbnode(uid2);
+
+             /* Now dedupe uid1 */
+             for(sig1=uid1->next;sig1;sig1=sig1->next)
+               {
+                 KBNODE sig2;
+
+                 if(is_deleted_kbnode(sig1))
+                   continue;
+
+                 if(sig1->pkt->pkttype==PKT_USER_ID
+                    || sig1->pkt->pkttype==PKT_PUBLIC_SUBKEY
+                    || sig1->pkt->pkttype==PKT_SECRET_SUBKEY)
+                   break;
+
+                 if(sig1->pkt->pkttype!=PKT_SIGNATURE)
+                   continue;
+
+                 for(sig2=sig1->next,last=sig1;sig2;last=sig2,sig2=sig2->next)
+                   {
+                     if(is_deleted_kbnode(sig2))
+                       continue;
+
+                     if(sig2->pkt->pkttype==PKT_USER_ID
+                        || sig2->pkt->pkttype==PKT_PUBLIC_SUBKEY
+                        || sig2->pkt->pkttype==PKT_SECRET_SUBKEY)
                        break;
-                   if( n2->pkt->pkttype != PKT_SIGNATURE )
-                       ;
-                   else if( !ncmp )
-                       ncmp = n2;
-                   else if( !cmp_signatures( ncmp->pkt->pkt.signature,
-                                               n2->pkt->pkt.signature )) {
-                       remove_kbnode( keyblock, n2 );
-                       goto restart_sig;
+
+                     if(sig2->pkt->pkttype!=PKT_SIGNATURE)
+                       continue;
+
+                     if(cmp_signatures(sig1->pkt->pkt.signature,
+                                       sig2->pkt->pkt.signature)==0)
+                       {
+                         /* We have a match, so delete the second
+                            signature */
+                         delete_kbnode(sig2);
+                         sig2=last;
+                       }
                    }
                }
-               n2 = ncmp? ncmp->next : NULL;
-           } while( n2 );
+           }
        }
     }
 
-    if(!opt.quiet)
-      {
-       const char *key="???";
+  commit_kbnode(keyblock);
+
+  if(any && !opt.quiet)
+    {
+      const char *key="???";
 
-       if( (n = find_kbnode( *keyblock, PKT_PUBLIC_KEY )) )
-         key=keystr_from_pk(n->pkt->pkt.public_key);
-       else if( (n = find_kbnode( *keyblock, PKT_SECRET_KEY )) )
-         key=keystr_from_sk(n->pkt->pkt.secret_key);
+      if( (uid1=find_kbnode( *keyblock, PKT_PUBLIC_KEY )) )
+       key=keystr_from_pk(uid1->pkt->pkt.public_key);
+      else if( (uid1 = find_kbnode( *keyblock, PKT_SECRET_KEY )) )
+       key=keystr_from_sk(uid1->pkt->pkt.secret_key);
 
-       log_info(_("key %s: duplicated user ID detected - merged\n"),key);
-      }
+      log_info(_("key %s: duplicated user ID detected - merged\n"),key);
+    }
 
-    return 1;
+  return any;
 }
 
 /* Check for a 0x20 revocation from a revocation key that is not
@@ -2005,11 +2054,14 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
  * append the userid starting with NODE and all signatures to KEYBLOCK.
  */
 static int
-append_uidKBNODE keyblock, KBNODE node, int *n_sigs,
-                                         const char *fname, u32 *keyid )
+append_uid (KBNODE keyblock, KBNODE node, int *n_sigs,
+            const char *fname, u32 *keyid )
 {
     KBNODE n, n_where=NULL;
 
+    (void)fname;
+    (void)keyid;
+
     assert(node->pkt->pkttype == PKT_USER_ID );
 
     /* find the position */
@@ -2057,6 +2109,9 @@ merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
     KBNODE n, n2;
     int found=0;
 
+    (void)fname;
+    (void)keyid;
+
     assert(dst->pkt->pkttype == PKT_USER_ID );
     assert(src->pkt->pkttype == PKT_USER_ID );
 
@@ -2092,12 +2147,15 @@ merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
  * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY.
  */
 static int
-merge_keysigsKBNODE dst, KBNODE src, int *n_sigs,
-                                   const char *fname, u32 *keyid )
+merge_keysigs (KBNODE dst, KBNODE src, int *n_sigs,
+               const char *fname, u32 *keyid)
 {
     KBNODE n, n2;
     int found=0;
 
+    (void)fname;
+    (void)keyid;
+
     assert(   dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
           || dst->pkt->pkttype == PKT_SECRET_SUBKEY );
 
@@ -2145,11 +2203,14 @@ merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs,
  * Mark all new and copied packets by setting flag bit 0.
  */
 static int
-append_keyKBNODE keyblock, KBNODE node, int *n_sigs,
-                                         const char *fname, u32 *keyid )
+append_key (KBNODE keyblock, KBNODE node, int *n_sigs,
+            const char *fname, u32 *keyid)
 {
     KBNODE n;
 
+    (void)fname;
+    (void)keyid;
+
     assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
           || node->pkt->pkttype == PKT_SECRET_SUBKEY );
 
@@ -2343,7 +2404,8 @@ auto_create_card_key_stub ( const char *serialnostr,
     size_t an;
 
     fingerprint_from_pk (pk, afp, &an);
-    memset (afp, 0, MAX_FINGERPRINT_LEN);
+    if (an < MAX_FINGERPRINT_LEN)
+      memset (afp+an, 0, MAX_FINGERPRINT_LEN-an);
     rc = keydb_search_fpr (hd, afp);
   }
 
@@ -2398,4 +2460,3 @@ auto_create_card_key_stub ( const char *serialnostr,
   keydb_release (hd);
   return rc;
 }
-