* gpg.c (print_mds), armor.c (armor_filter, parse_hash_header): Add
[gnupg.git] / g10 / import.c
index c1110bf..3b7fa5e 100644 (file)
@@ -1,6 +1,6 @@
-/* import.c
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- *               2004 Free Software Foundation, Inc.
+/* import.c - import a key into our key storage.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -16,7 +16,8 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
@@ -54,15 +55,18 @@ struct stats_s {
     ulong secret_dups;
     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,
@@ -88,13 +92,28 @@ parse_import_options(char *str,unsigned int *options,int noisy)
 {
   struct parse_options import_opts[]=
     {
-      {"allow-local-sigs",IMPORT_ALLOW_LOCAL_SIGS,NULL},
-      {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL},
-      {"repair-pks-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL},
-      {"fast-import",IMPORT_FAST_IMPORT,NULL},
-      {"convert-sk-to-pk",IMPORT_SK2PK,NULL},
-      {"merge-only",IMPORT_MERGE_ONLY,NULL},
-      {NULL,0,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,NULL},
+      {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
+      /* dummy */
+      {"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);
@@ -103,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);
 }
 
 /****************
@@ -145,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;
@@ -154,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 )
@@ -165,17 +185,24 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
            IOBUF inp2 = iobuf_open(fname);
            if( !fname )
                fname = "[stdin]";
+            if (inp2 && is_secured_file (iobuf_get_fd (inp2)))
+              {
+                iobuf_close (inp2);
+                inp2 = NULL;
+                errno = EPERM;
+              }
            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;
        }
@@ -184,18 +211,15 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
         import_print_stats (stats);
         import_release_stats_handle (stats);
     }
+
     /* If no fast import and the trustdb is dirty (i.e. we added a key
        or userID that had something other than a selfsig, a signature
        that was other than a selfsig, or any revocation), then
        update/check the trustdb if the user specified by setting
        interactive or by not setting no-auto-check-trustdb */
-    if (!(options&IMPORT_FAST_IMPORT) && trustdb_pending_check())
-      {
-       if (opt.interactive)
-         update_trustdb();
-       else if (!opt.no_auto_check_trustdb)
-         check_trustdb();
-      }
+
+    if(!(options&IMPORT_FAST))
+      trustdb_check_or_update();
 
     return rc;
 }
@@ -204,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;
@@ -224,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
@@ -294,6 +319,10 @@ import_print_stats (void *hd)
            log_info(_(" secret keys unchanged: %lu\n"), stats->secret_dups );
        if( stats->not_imported )
            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() ) {
@@ -339,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 */
@@ -372,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);
              }
@@ -400,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;
@@ -415,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;
 }
 
@@ -517,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;
@@ -528,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
@@ -604,7 +632,7 @@ check_prefs(KBNODE keyblock)
                }
            }
 
-         m_free(user);
+         xfree(user);
        }
     }
 
@@ -648,8 +676,8 @@ check_prefs(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;
@@ -667,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 );
 
@@ -700,6 +732,15 @@ 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)
+      clean_key(keyblock,opt.verbose,options&IMPORT_MINIMAL,NULL,NULL);
+
     clear_kbnode_flags( keyblock );
 
     if((options&IMPORT_REPAIR_PKS_SUBKEY_BUG) && fix_pks_corruption(keyblock)
@@ -719,9 +760,9 @@ import_one( const char *fname, KBNODE keyblock,
            char *user=utf8_to_native(node->pkt->pkt.user_id->name,
                                      node->pkt->pkt.user_id->len,0);
            node->flag |= 1;
-           log_info( _("key %s: accepted non self-signed user ID '%s'\n"),
+           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 ) ) {
@@ -733,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 )
       {
@@ -759,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"),
@@ -781,16 +820,16 @@ import_one( const char *fname, KBNODE keyblock,
        /* we are ready */
        if( !opt.quiet )
          {
-           char *p=get_user_id_printable (keyid);
+           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++;
@@ -800,7 +839,7 @@ import_one( const char *fname, KBNODE keyblock,
     }
     else { /* merge */
         KEYDB_HANDLE hd;
-       int n_uids, n_sigs, n_subk;
+       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 */
@@ -837,18 +876,23 @@ 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 = 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 ) {
+                          keyid, &n_uids, &n_sigs, &n_subk );
+       if( rc )
+         {
             keydb_release (hd);
            goto leave;
-        }
-       if( n_uids || n_sigs || n_subk ) {
+         }
+
+       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 || n_uids_cleaned) {
            mod_key = 1;
            /* keyblock_orig has been updated; write */
            rc = keydb_update_keyblock (hd, keyblock_orig);
@@ -861,7 +905,7 @@ import_one( const char *fname, KBNODE keyblock,
            /* we are ready */
            if( !opt.quiet )
              {
-               char *p=get_user_id_printable(keyid);
+               char *p=get_user_id_native(keyid);
                if( n_uids == 1 )
                  log_info( _("key %s: \"%s\" 1 new user ID\n"),
                           keystr(keyid),p);
@@ -880,12 +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 );
-               m_free(p);
+               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);
+               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,
@@ -898,9 +956,9 @@ import_one( const char *fname, KBNODE keyblock,
 
            if( !opt.quiet )
              {
-               char *p=get_user_id_printable(keyid);
+               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++;
@@ -951,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)
@@ -1049,6 +1107,17 @@ import_secret_one( const char *fname, KBNODE keyblock,
        return 0;
       }
 
+#ifdef ENABLE_SELINUX_HACKS
+    if (1)
+      {
+        /* We don't allow to import secret keys because that may be used
+           to put a secret key into the keyring and the user might later
+           be tricked into signing stuff with that key.  */
+        log_error (_("importing secret keys not allowed\n"));
+        return 0;
+      }
+#endif 
+    
     clear_kbnode_flags( keyblock );
 
     /* do we have this key already in one of our secrings ? */
@@ -1084,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);
              }
          }
@@ -1137,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 )
       {
@@ -1215,10 +1285,10 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
     /* we are ready */
     if( !opt.quiet )
       {
-        char *p=get_user_id_printable (keyid);
+        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++;
 
@@ -1272,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 )
                  {
@@ -1297,17 +1368,17 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                                      strlen(unode->pkt->pkt.user_id->name),0);
                          log_info( rc == G10ERR_PUBKEY_ALGO ?
                                    _("key %s: unsupported public key "
-                                     "algorithm on user id \"%s\"\n"):
+                                     "algorithm on user ID \"%s\"\n"):
                                    _("key %s: invalid self-signature "
-                                     "on user id \"%s\"\n"),
+                                     "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
@@ -1436,9 +1507,9 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
                  {
                    char *p=utf8_to_native(node->pkt->pkt.user_id->name,
                                           node->pkt->pkt.user_id->len,0);
-                   log_info( _("key %s: skipped user ID '%s'\n"),
+                   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 */
@@ -1476,7 +1547,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
            delete_kbnode( node ); /* build_packet() can't handle this */
        else if( node->pkt->pkttype == PKT_SIGNATURE &&
                 !node->pkt->pkt.signature->flags.exportable &&
-                !(options&IMPORT_ALLOW_LOCAL_SIGS) &&
+                !(options&IMPORT_LOCAL_SIGS) &&
                 seckey_available( node->pkt->pkt.signature->keyid ) )
          {
            /* here we violate the rfc a bit by still allowing
@@ -1485,7 +1556,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
             * seems that this makes sense */
            if(opt.verbose)
              log_info( _("key %s: non exportable signature"
-                         " (class %02x) - skipped\n"),
+                         " (class 0x%02X) - skipped\n"),
                        keystr(keyid), node->pkt->pkt.signature->sig_class );
            delete_kbnode( node );
          }
@@ -1539,7 +1610,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
            delete_kbnode(node);
          }
        else if( (node->flag & 4) ) /* marked for deletion */
-           delete_kbnode( node );
+         delete_kbnode( node );
     }
 
     /* note: because keyblock is the public key, it is never marked
@@ -1688,17 +1759,19 @@ 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_scheme &&
-                            opt.keyserver_options.auto_key_retrieve)
+                         if(opt.keyserver
+                            && (opt.keyserver_options.options
+                                & KEYSERVER_AUTO_KEY_RETRIEVE))
                            {
                              log_info(_("WARNING: key %s may be revoked:"
                                         " fetching revocation key %s\n"),
                                       tempkeystr,keystr(keyid));
                              keyserver_import_fprint(sig->revkey[idx]->fpr,
-                                                     MAX_FINGERPRINT_LEN);
+                                                     MAX_FINGERPRINT_LEN,
+                                                     opt.keyserver);
 
                              /* Do we have it now? */
                              rc=get_pubkey_byfprint_fast (NULL,
@@ -1711,7 +1784,7 @@ revocation_present(KBNODE keyblock)
                                       " revocation key %s not present.\n"),
                                     tempkeystr,keystr(keyid));
 
-                         m_free(tempkeystr);
+                         xfree(tempkeystr);
                        }
                    }
                }
@@ -1765,10 +1838,10 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
                 ++*n_sigs;
                if(!opt.quiet)
                  {
-                   char *p=get_user_id_printable (keyid);
+                   char *p=get_user_id_native (keyid);
                    log_info(_("key %s: \"%s\" revocation"
                               " certificate added\n"), keystr(keyid),p);
-                   m_free(p);
+                   xfree(p);
                  }
            }
        }
@@ -2072,3 +2145,232 @@ append_key( KBNODE keyblock, KBNODE node, int *n_sigs,
 
     return 0;
 }
+
+
+
+/* Walk a public keyblock and produce a secret keyblock out of it.
+   Instead of inserting the secret key parameters (which we don't
+   have), we insert a stub.  */
+static KBNODE
+pub_to_sec_keyblock (KBNODE pub_keyblock)
+{
+  KBNODE pubnode, secnode;
+  KBNODE sec_keyblock = NULL;
+  KBNODE walkctx = NULL;
+
+  while((pubnode = walk_kbnode (pub_keyblock,&walkctx,0)))
+    {
+      if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY
+          || pubnode->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+       {
+         /* 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 = xmalloc_clear (sizeof *pkt);
+         PKT_secret_key *sk = xmalloc_clear (sizeof *sk);
+          int i, n;
+          
+          if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY)
+           pkt->pkttype = PKT_SECRET_KEY;
+         else
+           pkt->pkttype = PKT_SECRET_SUBKEY;
+          
+         pkt->pkt.secret_key = sk;
+
+          copy_public_parts_to_secret_key ( pk, sk );
+         sk->version     = pk->version;
+         sk->timestamp   = pk->timestamp;
+        
+          n = pubkey_get_npkey (pk->pubkey_algo);
+          if (!n)
+            n = 1; /* Unknown number of parameters, however the data
+                      is stored in the first mpi. */
+          for (i=0; i < n; i++ )
+            sk->skey[i] = mpi_copy (pk->pkey[i]);
+  
+          sk->is_protected = 1;
+          sk->protect.s2k.mode = 1001;
+  
+         secnode = new_kbnode (pkt);
+        }
+      else
+       {
+         secnode = clone_kbnode (pubnode);
+       }
+      
+      if(!sec_keyblock)
+       sec_keyblock = secnode;
+      else
+       add_kbnode (sec_keyblock, secnode);
+    }
+
+  return sec_keyblock;
+}
+
+
+/* Walk over the secret keyring SEC_KEYBLOCK and update any simple
+   stub keys with the serial number SNNUM of the card if one of the
+   fingerprints FPR1, FPR2 or FPR3 match.  Print a note if the key is
+   a duplicate (may happen in case of backed uped keys). 
+   
+   Returns: True if anything changed.
+*/
+static int
+update_sec_keyblock_with_cardinfo (KBNODE sec_keyblock, 
+                                   const unsigned char *fpr1,
+                                   const unsigned char *fpr2,
+                                   const unsigned char *fpr3,
+                                   const char *serialnostr)
+{
+  KBNODE node;
+  KBNODE walkctx = NULL;
+  PKT_secret_key *sk;
+  byte array[MAX_FINGERPRINT_LEN];
+  size_t n;
+  int result = 0;
+  const char *s;
+
+  while((node = walk_kbnode (sec_keyblock, &walkctx, 0)))
+    {
+      if (node->pkt->pkttype != PKT_SECRET_KEY
+          && node->pkt->pkttype != PKT_SECRET_SUBKEY)
+        continue;
+      sk = node->pkt->pkt.secret_key;
+      
+      fingerprint_from_sk (sk, array, &n);
+      if (n != 20)
+        continue; /* Can't be a card key.  */
+      if ( !((fpr1 && !memcmp (array, fpr1, 20))
+             || (fpr2 && !memcmp (array, fpr2, 20))
+             || (fpr3 && !memcmp (array, fpr3, 20))) )
+        continue;  /* No match.  */
+
+      if (sk->is_protected == 1 && sk->protect.s2k.mode == 1001)
+        {
+          /* Standard case: migrate that stub to a key stub.  */
+          sk->protect.s2k.mode = 1002;
+          s = serialnostr;
+          for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+               sk->protect.ivlen++, s += 2)
+            sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
+          result = 1;
+        }
+      else if (sk->is_protected == 1 && sk->protect.s2k.mode == 1002)
+        {
+          s = serialnostr;
+          for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+               sk->protect.ivlen++, s += 2)
+            if (sk->protect.iv[sk->protect.ivlen] != xtoi_2 (s))
+              {
+                log_info (_("NOTE: a key's S/N does not "
+                            "match the card's one\n"));
+                break;
+              }
+        }
+      else
+        {
+          if (node->pkt->pkttype != PKT_SECRET_KEY)
+            log_info (_("NOTE: primary key is online and stored on card\n"));
+          else
+            log_info (_("NOTE: secondary key is online and stored on card\n"));
+        }
+    }
+
+  return result;
+}
+
+
+
+/* Check whether a secret key stub exists for the public key PK.  If
+   not create such a stub key and store it into the secring.  If it
+   exists, add appropriate subkey stubs and update the secring.
+   Return 0 if the key could be created. */
+int
+auto_create_card_key_stub ( const char *serialnostr, 
+                            const unsigned char *fpr1,
+                            const unsigned char *fpr2,
+                            const unsigned char *fpr3)
+{
+  KBNODE pub_keyblock;
+  KBNODE sec_keyblock;
+  KEYDB_HANDLE hd;
+  int rc;
+
+  /* We only want to do this for an OpenPGP card.  */
+  if (!serialnostr || strncmp (serialnostr, "D27600012401", 12) 
+      || strlen (serialnostr) != 32 )
+    return G10ERR_GENERAL;
+
+  /* First get the public keyring from any of the provided fingerprints. */
+  if ( (fpr1 && !get_keyblock_byfprint (&pub_keyblock, fpr1, 20))
+       || (fpr2 && !get_keyblock_byfprint (&pub_keyblock, fpr2, 20))
+       || (fpr3 && !get_keyblock_byfprint (&pub_keyblock, fpr3, 20)))
+    ;
+  else
+    return G10ERR_GENERAL;
+  hd = keydb_new (1);
+
+  /* Now check whether there is a secret keyring.  */
+  {
+    PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
+    byte afp[MAX_FINGERPRINT_LEN];
+    size_t an;
+
+    fingerprint_from_pk (pk, afp, &an);
+    memset (afp, 0, MAX_FINGERPRINT_LEN);
+    rc = keydb_search_fpr (hd, afp);
+  }
+
+  if (!rc)
+    {
+      rc = keydb_get_keyblock (hd, &sec_keyblock);
+      if (rc)
+        {
+          log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+          rc = G10ERR_GENERAL;
+        }
+      else
+        {
+          merge_keys_and_selfsig (sec_keyblock);
+          
+          /* FIXME: We need to add new subkeys first.  */
+          if (update_sec_keyblock_with_cardinfo (sec_keyblock,
+                                                 fpr1, fpr2, fpr3,
+                                                 serialnostr))
+            {
+              rc = keydb_update_keyblock (hd, sec_keyblock );
+              if (rc)
+                log_error (_("error writing keyring `%s': %s\n"),
+                           keydb_get_resource_name (hd), g10_errstr(rc) );
+            }
+        }
+    }
+  else  /* A secret key does not exists - create it.  */
+    {
+      sec_keyblock = pub_to_sec_keyblock (pub_keyblock);
+      update_sec_keyblock_with_cardinfo (sec_keyblock,
+                                         fpr1, fpr2, fpr3,
+                                         serialnostr);
+
+      rc = keydb_locate_writable (hd, NULL);
+      if (rc)
+        {
+          log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
+          rc = G10ERR_GENERAL;
+        }
+      else
+        {
+          rc = keydb_insert_keyblock (hd, sec_keyblock );
+          if (rc)
+            log_error (_("error writing keyring `%s': %s\n"),
+                       keydb_get_resource_name (hd), g10_errstr(rc) );
+        }
+    }
+    
+  release_kbnode (sec_keyblock);
+  release_kbnode (pub_keyblock);
+  keydb_release (hd);
+  return rc;
+}
+