* gpg.c (print_mds), armor.c (armor_filter, parse_hash_header): Add
[gnupg.git] / g10 / import.c
index 145bee8..3b7fa5e 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 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -56,15 +56,17 @@ struct stats_s {
     ulong skipped_new_keys;
     ulong not_imported;
     ulong n_sigs_cleaned;
+    ulong n_uids_cleaned;
 };
 
 
-static int import( IOBUF inp, const char* fname,
-                   struct stats_s *stats, unsigned int options );
+static int import( IOBUF inp, const char* fname,struct stats_s *stats,
+                  unsigned char **fpr,size_t *fpr_len,unsigned int options );
 static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
 static void revocation_present(KBNODE keyblock);
-static int import_one( const char *fname, KBNODE keyblock,
-                       struct stats_s *stats, unsigned int options);
+static int import_one(const char *fname, KBNODE keyblock,struct stats_s *stats,
+                     unsigned char **fpr,size_t *fpr_len,
+                     unsigned int options);
 static int import_secret_one( const char *fname, KBNODE keyblock,
                               struct stats_s *stats, unsigned int options);
 static int import_revoke_cert( const char *fname, KBNODE node,
@@ -90,19 +92,28 @@ parse_import_options(char *str,unsigned int *options,int noisy)
 {
   struct parse_options import_opts[]=
     {
-      {"import-local-sigs",IMPORT_LOCAL_SIGS,NULL},
-      {"repair-pks-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL},
-      {"fast-import",IMPORT_FAST,NULL},
-      {"convert-sk-to-pk",IMPORT_SK2PK,NULL},
-      {"merge-only",IMPORT_MERGE_ONLY,NULL},
-      {"import-clean",IMPORT_CLEAN_SIGS,NULL},
-      {"import-clean-sigs",IMPORT_CLEAN_SIGS,NULL},
+      {"import-local-sigs",IMPORT_LOCAL_SIGS,NULL,
+       N_("import signatures that are marked as local-only")},
+      {"repair-pks-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,
+       N_("repair damage from the pks keyserver during import")},
+      {"fast-import",IMPORT_FAST,NULL,
+       N_("do not update the trustdb after import")},
+      {"convert-sk-to-pk",IMPORT_SK2PK,NULL,
+       N_("create a public key when importing a secret key")},
+      {"merge-only",IMPORT_MERGE_ONLY,NULL,
+       N_("only accept updates to existing keys")},
+      {"import-clean",IMPORT_CLEAN,NULL,
+       N_("remove unusable parts from key after import")},
+      {"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL,
+       N_("remove as much as possible from key after import")},
       /* Aliases for backward compatibility */
-      {"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL},
-      {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL},
+      {"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
+      {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
       /* dummy */
-      {"import-unusable-sigs",0,NULL},
-      {NULL,0,NULL}
+      {"import-unusable-sigs",0,NULL,NULL},
+      {"import-clean-sigs",0,NULL,NULL},
+      {"import-clean-uids",0,NULL,NULL},
+      {NULL,0,NULL,NULL}
     };
 
   return parse_options(str,options,import_opts,noisy);
@@ -111,13 +122,13 @@ parse_import_options(char *str,unsigned int *options,int noisy)
 void *
 import_new_stats_handle (void)
 {
-    return m_alloc_clear ( sizeof (struct stats_s) );
+    return xmalloc_clear ( sizeof (struct stats_s) );
 }
 
 void
 import_release_stats_handle (void *p)
 {
-    m_free (p);
+    xfree (p);
 }
 
 /****************
@@ -153,7 +164,8 @@ import_release_stats_handle (void *p)
  */
 static int
 import_keys_internal( IOBUF inp, char **fnames, int nnames,
-                     void *stats_handle, unsigned int options )
+                     void *stats_handle, unsigned char **fpr, size_t *fpr_len,
+                     unsigned int options )
 {
     int i, rc = 0;
     struct stats_s *stats = stats_handle;
@@ -162,7 +174,7 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
         stats = import_new_stats_handle ();
 
     if (inp) {
-        rc = import( inp, "[stream]", stats, options);
+        rc = import( inp, "[stream]", stats, fpr, fpr_len, options);
     }
     else {
         if( !fnames && !nnames )
@@ -181,15 +193,16 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
               }
            if( !inp2 )
                log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
-           else {
-               rc = import( inp2, fname, stats, options );
+           else
+             {
+               rc = import( inp2, fname, stats, fpr, fpr_len, options );
                iobuf_close(inp2);
                 /* Must invalidate that ugly cache to actually close it. */
                 iobuf_ioctl (NULL, 2, 0, (char*)fname);
                if( rc )
-                   log_error("import from `%s' failed: %s\n", fname,
-                                     g10_errstr(rc) );
-           }
+                 log_error("import from `%s' failed: %s\n", fname,
+                           g10_errstr(rc) );
+             }
            if( !fname )
                break;
        }
@@ -215,18 +228,19 @@ void
 import_keys( char **fnames, int nnames,
             void *stats_handle, unsigned int options )
 {
-    import_keys_internal( NULL, fnames, nnames, stats_handle, options);
+  import_keys_internal(NULL,fnames,nnames,stats_handle,NULL,NULL,options);
 }
 
 int
-import_keys_stream( IOBUF inp, void *stats_handle, unsigned int options )
+import_keys_stream( IOBUF inp, void *stats_handle,
+                   unsigned char **fpr, size_t *fpr_len,unsigned int options )
 {
-    return import_keys_internal( inp, NULL, 0, stats_handle, options);
+  return import_keys_internal(inp,NULL,0,stats_handle,fpr,fpr_len,options);
 }
 
 static int
-import( IOBUF inp, const char* fname,
-       struct stats_s *stats, unsigned int options )
+import( IOBUF inp, const char* fname,struct stats_s *stats,
+       unsigned char **fpr,size_t *fpr_len,unsigned int options )
 {
     PACKET *pending_pkt = NULL;
     KBNODE keyblock;
@@ -235,14 +249,14 @@ import( IOBUF inp, const char* fname,
     getkey_disable_caches();
 
     if( !opt.no_armor ) { /* armored reading is not disabled */
-       armor_filter_context_t *afx = m_alloc_clear( sizeof *afx );
+       armor_filter_context_t *afx = xmalloc_clear( sizeof *afx );
        afx->only_keyblocks = 1;
        iobuf_push_filter2( inp, armor_filter, afx, 1 );
     }
 
     while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
        if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
-           rc = import_one( fname, keyblock, stats, options );
+           rc = import_one( fname, keyblock, stats, fpr, fpr_len, options );
        else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) 
                 rc = import_secret_one( fname, keyblock, stats, options );
        else if( keyblock->pkt->pkttype == PKT_SIGNATURE
@@ -307,6 +321,8 @@ import_print_stats (void *hd)
            log_info(_("          not imported: %lu\n"), stats->not_imported );
        if( stats->n_sigs_cleaned)
            log_info(_("    signatures cleaned: %lu\n"),stats->n_sigs_cleaned);
+       if( stats->n_uids_cleaned)
+           log_info(_("      user IDs cleaned: %lu\n"),stats->n_uids_cleaned);
     }
 
     if( is_status_enabled() ) {
@@ -352,7 +368,7 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
     }
     else
        in_cert = 0;
-    pkt = m_alloc( sizeof *pkt );
+    pkt = xmalloc( sizeof *pkt );
     init_packet(pkt);
     while( (rc=parse_packet(a, pkt)) != -1 ) {
        if( rc ) {  /* ignore errors */
@@ -385,7 +401,7 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
              }
            else
              {
-               compress_filter_context_t *cfx = m_alloc_clear( sizeof *cfx );
+               compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
                pkt->pkt.compressed->buf = NULL;
                push_compress_filter2(a,cfx,pkt->pkt.compressed->algorithm,1);
              }
@@ -413,7 +429,7 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
                    root = new_kbnode( pkt );
                else
                    add_kbnode( root, new_kbnode( pkt ) );
-               pkt = m_alloc( sizeof *pkt );
+               pkt = xmalloc( sizeof *pkt );
            }
            init_packet(pkt);
            break;
@@ -428,7 +444,7 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
     else
        *ret_root = root;
     free_packet( pkt );
-    m_free( pkt );
+    xfree( pkt );
     return rc;
 }
 
@@ -530,7 +546,7 @@ print_import_check (PKT_public_key * pk, PKT_user_id * id)
     u32 keyid[2];
     size_t i, pos = 0, n;
 
-    buf = m_alloc (17+41+id->len+32);
+    buf = xmalloc (17+41+id->len+32);
     keyid_from_pk (pk, keyid);
     sprintf (buf, "%08X%08X ", keyid[0], keyid[1]);
     pos = 17;
@@ -541,15 +557,14 @@ print_import_check (PKT_public_key * pk, PKT_user_id * id)
     pos += 1;
     strcat (buf, id->name);
     write_status_text (STATUS_IMPORT_CHECK, buf);
-    m_free (buf);
+    xfree (buf);
 }
 
 static void
 check_prefs_warning(PKT_public_key *pk)
 {
-  log_info(_("WARNING: key %s contains preferences for unavailable\n"),
-          keystr_from_pk(pk));
-  log_info(_("algorithms on these user IDs:\n"));
+  log_info(_("WARNING: key %s contains preferences for unavailable\n"
+             "algorithms on these user IDs:\n"), keystr_from_pk(pk));
 }
 
 static void
@@ -617,7 +632,7 @@ check_prefs(KBNODE keyblock)
                }
            }
 
-         m_free(user);
+         xfree(user);
        }
     }
 
@@ -654,20 +669,6 @@ check_prefs(KBNODE keyblock)
     }
 }
 
-static int
-clean_sigs_from_all_uids(KBNODE keyblock)
-{
-  KBNODE uidnode;
-  int deleted=0;
-
-  for(uidnode=keyblock->next;uidnode;uidnode=uidnode->next)
-    if(uidnode->pkt->pkttype==PKT_USER_ID)
-      deleted+=clean_sigs_from_uid(keyblock,uidnode,opt.verbose);
-
-  return deleted;
-}
-
-
 /****************
  * 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
@@ -675,8 +676,8 @@ clean_sigs_from_all_uids(KBNODE keyblock)
  * which called g10.
  */
 static int
-import_one( const char *fname, KBNODE keyblock,
-            struct stats_s *stats, unsigned int options )
+import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
+           unsigned char **fpr,size_t *fpr_len,unsigned int options )
 {
     PKT_public_key *pk;
     PKT_public_key *pk_orig;
@@ -694,6 +695,10 @@ import_one( const char *fname, KBNODE keyblock,
        BUG();
 
     pk = node->pkt->pkt.public_key;
+
+    if(fpr)
+      *fpr=fingerprint_from_pk(pk,NULL,fpr_len);
+
     keyid_from_pk( pk, keyid );
     uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
 
@@ -727,12 +732,14 @@ import_one( const char *fname, KBNODE keyblock,
             return 0;
     }
 
+    collapse_uids(&keyblock);
+
     /* Clean the key that we're about to import, to cut down on things
        that we have to clean later.  This has no practical impact on
        the end result, but does result in less logging which might
        confuse the user. */
-    if(options&IMPORT_CLEAN_SIGS)
-      clean_sigs_from_all_uids(keyblock);
+    if(options&IMPORT_CLEAN)
+      clean_key(keyblock,opt.verbose,options&IMPORT_MINIMAL,NULL,NULL);
 
     clear_kbnode_flags( keyblock );
 
@@ -755,7 +762,7 @@ import_one( const char *fname, KBNODE keyblock,
            node->flag |= 1;
            log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"),
                      keystr_from_pk(pk),user);
-           m_free(user);
+           xfree(user);
          }
 
     if( !delete_inv_parts( fname, keyblock, keyid, options ) ) {
@@ -767,7 +774,7 @@ import_one( const char *fname, KBNODE keyblock,
     }
 
     /* do we have this key already in one of our pubrings ? */
-    pk_orig = m_alloc_clear( sizeof *pk_orig );
+    pk_orig = xmalloc_clear( sizeof *pk_orig );
     rc = get_pubkey_fast ( pk_orig, keyid );
     if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY )
       {
@@ -793,8 +800,6 @@ import_one( const char *fname, KBNODE keyblock,
        if( opt.verbose > 1 )
            log_info (_("writing to `%s'\n"), keydb_get_resource_name (hd) );
 
-       collapse_uids(&keyblock);
-
        rc = keydb_insert_keyblock (hd, keyblock );
         if (rc)
           log_error (_("error writing keyring `%s': %s\n"),
@@ -818,13 +823,13 @@ import_one( const char *fname, KBNODE keyblock,
            char *p=get_user_id_native (keyid);
            log_info( _("key %s: public key \"%s\" imported\n"),
                      keystr(keyid),p);
-           m_free(p);
+           xfree(p);
          }
        if( is_status_enabled() )
          {
            char *us = get_long_user_id_string( keyid );
            write_status_text( STATUS_IMPORTED, us );
-           m_free(us);
+           xfree(us);
             print_import_ok (pk,NULL, 1);
          }
        stats->imported++;
@@ -834,7 +839,7 @@ import_one( const char *fname, KBNODE keyblock,
     }
     else { /* merge */
         KEYDB_HANDLE hd;
-       int n_uids, n_sigs, n_subk, n_sigs_cleaned;
+       int n_uids, n_sigs, n_subk, n_sigs_cleaned, n_uids_cleaned;
 
        /* Compare the original against the new key; just to be sure nothing
         * weird is going on */
@@ -871,11 +876,10 @@ import_one( const char *fname, KBNODE keyblock,
            goto leave;
          }
 
-       collapse_uids( &keyblock );
        /* and try to merge the block */
        clear_kbnode_flags( keyblock_orig );
        clear_kbnode_flags( keyblock );
-       n_uids = n_sigs = n_subk = n_sigs_cleaned = 0;
+       n_uids = n_sigs = n_subk = n_sigs_cleaned = n_uids_cleaned = 0;
        rc = merge_blocks( fname, keyblock_orig, keyblock,
                           keyid, &n_uids, &n_sigs, &n_subk );
        if( rc )
@@ -884,10 +888,11 @@ import_one( const char *fname, KBNODE keyblock,
            goto leave;
          }
 
-       if(options&IMPORT_CLEAN_SIGS)
-         n_sigs_cleaned=clean_sigs_from_all_uids(keyblock_orig);
+       if(options&IMPORT_CLEAN)
+         clean_key(keyblock_orig,opt.verbose,options&IMPORT_MINIMAL,
+                   &n_uids_cleaned,&n_sigs_cleaned);
 
-       if( n_uids || n_sigs || n_subk || n_sigs_cleaned) {
+       if( n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned) {
            mod_key = 1;
            /* keyblock_orig has been updated; write */
            rc = keydb_update_keyblock (hd, keyblock_orig);
@@ -919,16 +924,26 @@ import_one( const char *fname, KBNODE keyblock,
                else if( n_subk )
                  log_info( _("key %s: \"%s\" %d new subkeys\n"),
                            keystr(keyid), p, n_subk );
-               if(n_sigs_cleaned)
+               if(n_sigs_cleaned==1)
+                 log_info(_("key %s: \"%s\" %d signature cleaned\n"),
+                          keystr(keyid),p,n_sigs_cleaned);
+               else if(n_sigs_cleaned)
                  log_info(_("key %s: \"%s\" %d signatures cleaned\n"),
                           keystr(keyid),p,n_sigs_cleaned);
-               m_free(p);
+               if(n_uids_cleaned==1)
+                 log_info(_("key %s: \"%s\" %d user ID cleaned\n"),
+                          keystr(keyid),p,n_uids_cleaned);
+               else if(n_uids_cleaned)
+                 log_info(_("key %s: \"%s\" %d user IDs cleaned\n"),
+                          keystr(keyid),p,n_uids_cleaned);
+               xfree(p);
              }
 
            stats->n_uids +=n_uids;
            stats->n_sigs +=n_sigs;
            stats->n_subk +=n_subk;
            stats->n_sigs_cleaned +=n_sigs_cleaned;
+           stats->n_uids_cleaned +=n_uids_cleaned;
 
             if (is_status_enabled ()) 
                  print_import_ok (pk, NULL,
@@ -943,7 +958,7 @@ import_one( const char *fname, KBNODE keyblock,
              {
                char *p=get_user_id_native(keyid);
                log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p);
-               m_free(p);
+               xfree(p);
              }
 
            stats->unchanged++;
@@ -994,8 +1009,8 @@ sec_to_pub_keyblock(KBNODE sec_keyblock)
             write the keyblock out. */
 
          PKT_secret_key *sk=secnode->pkt->pkt.secret_key;
-         PACKET *pkt=m_alloc_clear(sizeof(PACKET));
-         PKT_public_key *pk=m_alloc_clear(sizeof(PKT_public_key));
+         PACKET *pkt=xmalloc_clear(sizeof(PACKET));
+         PKT_public_key *pk=xmalloc_clear(sizeof(PKT_public_key));
          int n;
 
          if(secnode->pkt->pkttype==PKT_SECRET_KEY)
@@ -1138,7 +1153,8 @@ import_secret_one( const char *fname, KBNODE keyblock,
            KBNODE pub_keyblock=sec_to_pub_keyblock(keyblock);
            if(pub_keyblock)
              {
-               import_one(fname,pub_keyblock,stats,opt.import_options);
+               import_one(fname,pub_keyblock,stats,
+                          NULL,NULL,opt.import_options);
                release_kbnode(pub_keyblock);
              }
          }
@@ -1191,7 +1207,7 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
     keyid[0] = node->pkt->pkt.signature->keyid[0];
     keyid[1] = node->pkt->pkt.signature->keyid[1];
 
-    pk = m_alloc_clear( sizeof *pk );
+    pk = xmalloc_clear( sizeof *pk );
     rc = get_pubkey( pk, keyid );
     if( rc == G10ERR_NO_PUBKEY )
       {
@@ -1272,7 +1288,7 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
         char *p=get_user_id_native (keyid);
        log_info( _("key %s: \"%s\" revocation certificate imported\n"),
                  keystr(keyid),p);
-       m_free(p);
+       xfree(p);
       }
     stats->n_revoc++;
 
@@ -1326,12 +1342,13 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
        sig = n->pkt->pkt.signature;
        if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
 
-         /* This just caches the sigs for later use.  That way we
-            import a fully-cached key which speeds things up. */
-         if(!opt.no_sig_cache)
-           check_key_signature(keyblock,n,NULL);
+           /* This just caches the sigs for later use.  That way we
+              import a fully-cached key which speeds things up. */
+           if(!opt.no_sig_cache)
+             check_key_signature(keyblock,n,NULL);
 
-           if( (sig->sig_class&~3) == 0x10 ) {
+           if( IS_UID_SIG(sig) || IS_UID_REV(sig) )
+             {
                KBNODE unode = find_prev_kbnode( keyblock, n, PKT_USER_ID );
                if( !unode )
                  {
@@ -1355,13 +1372,13 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                                    _("key %s: invalid self-signature "
                                      "on user ID \"%s\"\n"),
                                    keystr(keyid),p);
-                         m_free(p);
+                         xfree(p);
                        }
                    }
                  else
                    unode->flag |= 1; /* mark that signature checked */
                }
-           }
+             }
            else if( sig->sig_class == 0x18 ) {
              /* Note that this works based solely on the timestamps
                 like the rest of gpg.  If the standard gets
@@ -1492,7 +1509,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
                                           node->pkt->pkt.user_id->len,0);
                    log_info( _("key %s: skipped user ID \"%s\"\n"),
                              keystr(keyid),p);
-                   m_free(p);
+                   xfree(p);
                  }
                delete_kbnode( node ); /* the user-id */
                /* and all following packets up to the next user-id */
@@ -1742,7 +1759,7 @@ revocation_present(KBNODE keyblock)
                                                    MAX_FINGERPRINT_LEN);
                      if(rc==G10ERR_NO_PUBKEY || rc==G10ERR_UNU_PUBKEY)
                        {
-                         char *tempkeystr=m_strdup(keystr_from_pk(pk));
+                         char *tempkeystr=xstrdup(keystr_from_pk(pk));
 
                          /* No, so try and get it */
                          if(opt.keyserver
@@ -1767,7 +1784,7 @@ revocation_present(KBNODE keyblock)
                                       " revocation key %s not present.\n"),
                                     tempkeystr,keystr(keyid));
 
-                         m_free(tempkeystr);
+                         xfree(tempkeystr);
                        }
                    }
                }
@@ -1824,7 +1841,7 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
                    char *p=get_user_id_native (keyid);
                    log_info(_("key %s: \"%s\" revocation"
                               " certificate added\n"), keystr(keyid),p);
-                   m_free(p);
+                   xfree(p);
                  }
            }
        }
@@ -2149,8 +2166,8 @@ pub_to_sec_keyblock (KBNODE pub_keyblock)
          /* Make a secret key.  We only need to convert enough to
             write the keyblock out. */
          PKT_public_key *pk = pubnode->pkt->pkt.public_key;
-         PACKET *pkt = m_alloc_clear (sizeof *pkt);
-         PKT_secret_key *sk = m_alloc_clear (sizeof *sk);
+         PACKET *pkt = xmalloc_clear (sizeof *pkt);
+         PKT_secret_key *sk = xmalloc_clear (sizeof *sk);
           int i, n;
           
           if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY)