2003-09-28 Timo Schulz <twoaday@freakmail.de>
[gnupg.git] / g10 / export.c
index 5f6eadc..5783f6a 100644 (file)
 #include "i18n.h"
 
 static int do_export( STRLIST users, int secret, unsigned int options );
-static int do_export_stream( IOBUF out, STRLIST users,
-                            int secret, unsigned int options, int *any );
+static int do_export_stream( IOBUF out, STRLIST users, int secret,
+                            KBNODE *keyblock_out, unsigned int options,
+                            int *any );
 
 int
 parse_export_options(char *str,unsigned int *options)
 {
-  char *tok;
-  int hit=0;
-  struct
-  {
-    char *name;
-    unsigned int bit;
-  } export_opts[]=
+  struct parse_options export_opts[]=
     {
       {"include-non-rfc",EXPORT_INCLUDE_NON_RFC},
       {"include-local-sigs",EXPORT_INCLUDE_LOCAL_SIGS},
@@ -57,34 +52,7 @@ parse_export_options(char *str,unsigned int *options)
       /* add tags for include revoked and disabled? */
     };
 
-  while((tok=strsep(&str," ,")))
-    {
-      int i,rev=0;
-
-      if(ascii_strncasecmp("no-",tok,3)==0)
-       {
-         rev=1;
-         tok+=3;
-       }
-
-      for(i=0;export_opts[i].name;i++)
-       {
-         if(ascii_strcasecmp(export_opts[i].name,tok)==0)
-           {
-             if(rev)
-               *options&=~export_opts[i].bit;
-             else
-               *options|=export_opts[i].bit;
-             hit=1;
-             break;
-           }
-       }
-
-      if(!hit && !export_opts[i].name)
-       return 0;
-    }
-
-  return hit;
+  return parse_options(str,options,export_opts);
 }
 
 /****************
@@ -103,11 +71,12 @@ export_pubkeys( STRLIST users, unsigned int options )
  * been exported
  */
 int
-export_pubkeys_stream( IOBUF out, STRLIST users, unsigned int options )
+export_pubkeys_stream( IOBUF out, STRLIST users,
+                      KBNODE *keyblock_out, unsigned int options )
 {
     int any, rc;
 
-    rc = do_export_stream( out, users, 0, options, &any );
+    rc = do_export_stream( out, users, 0, keyblock_out, options, &any );
     if( !rc && !any )
        rc = -1;
     return rc;
@@ -146,7 +115,7 @@ do_export( STRLIST users, int secret, unsigned int options )
     }
     if( opt.compress_keys && opt.compress )
        iobuf_push_filter( out, compress_filter, &zfx );
-    rc = do_export_stream( out, users, secret, options, &any );
+    rc = do_export_stream( out, users, secret, NULL, options, &any );
 
     if( rc || !any )
        iobuf_cancel(out);
@@ -156,15 +125,18 @@ do_export( STRLIST users, int secret, unsigned int options )
 }
 
 
+/* If keyblock_out is non-NULL, AND the exit code is zero, then it
+   contains a pointer to the first keyblock found and exported.  No
+   other keyblocks are exported.  The caller must free it. */
 static int
 do_export_stream( IOBUF out, STRLIST users, int secret,
-                 unsigned int options, int *any )
+                 KBNODE *keyblock_out, unsigned int options, int *any )
 {
     int rc = 0;
     PACKET pkt;
     KBNODE keyblock = NULL;
     KBNODE kbctx, node;
-    int ndesc;
+    size_t ndesc, descindex;
     KEYDB_SEARCH_DESC *desc = NULL;
     KEYDB_HANDLE kdbhd;
     STRLIST sl;
@@ -199,9 +171,8 @@ do_export_stream( IOBUF out, STRLIST users, int secret,
            do this we need an extra flag to enable this feature so */
     }
 
-
-    while (!(rc = keydb_search (kdbhd, desc, ndesc))) {
-        int sha1_warned=0;
+    while (!(rc = keydb_search2 (kdbhd, desc, ndesc, &descindex))) {
+        int sha1_warned=0,skip_until_subkey=0;
        u32 sk_keyid[2];
 
        if (!users) 
@@ -251,14 +222,88 @@ do_export_stream( IOBUF out, STRLIST users, int secret,
 
        /* and write it */
        for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
+           if( skip_until_subkey )
+             {
+               if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY
+                  || node->pkt->pkttype==PKT_SECRET_SUBKEY)
+                 skip_until_subkey=0;
+               else
+                 continue;
+             }
+
            /* don't export any comment packets but those in the
             * secret keyring */
            if( !secret && node->pkt->pkttype == PKT_COMMENT )
                continue;
+
             /* make sure that ring_trust packets never get exported */
             if (node->pkt->pkttype == PKT_RING_TRUST)
               continue;
 
+           /* If exact is set, then we only export what was requested
+              (plus the primary key, if the user didn't specifically
+              request it) */
+           if(desc[descindex].exact
+              && (node->pkt->pkttype==PKT_PUBLIC_SUBKEY
+                  || node->pkt->pkttype==PKT_SECRET_SUBKEY))
+             {
+               u32 kid[2];
+               byte fpr[MAX_FINGERPRINT_LEN];
+               size_t fprlen;
+
+               switch(desc[descindex].mode)
+                 {
+                 case KEYDB_SEARCH_MODE_SHORT_KID:
+                 case KEYDB_SEARCH_MODE_LONG_KID:
+                   if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
+                     keyid_from_pk(node->pkt->pkt.public_key,kid);
+                   else
+                     keyid_from_sk(node->pkt->pkt.secret_key,kid);
+                   break;
+
+                 case KEYDB_SEARCH_MODE_FPR16:
+                 case KEYDB_SEARCH_MODE_FPR20:
+                 case KEYDB_SEARCH_MODE_FPR:
+                   if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
+                     fingerprint_from_pk(node->pkt->pkt.public_key,
+                                         fpr,&fprlen);
+                   else
+                     fingerprint_from_sk(node->pkt->pkt.secret_key,
+                                         fpr,&fprlen);
+                   break;
+
+                 default:
+                   break;
+                 }
+
+               switch(desc[descindex].mode)
+                 {
+                 case KEYDB_SEARCH_MODE_SHORT_KID:
+                   if (desc[descindex].u.kid[1] != kid[1])
+                     skip_until_subkey=1;
+                   break;
+                 case KEYDB_SEARCH_MODE_LONG_KID:
+                   if (desc[descindex].u.kid[0] != kid[0]
+                       || desc[descindex].u.kid[1] != kid[1])
+                     skip_until_subkey=1;
+                   break;
+                 case KEYDB_SEARCH_MODE_FPR16:
+                   if (memcmp (desc[descindex].u.fpr, fpr, 16))
+                     skip_until_subkey=1;
+                   break;
+                 case KEYDB_SEARCH_MODE_FPR20:
+                 case KEYDB_SEARCH_MODE_FPR:
+                   if (memcmp (desc[descindex].u.fpr, fpr, 20))
+                     skip_until_subkey=1;
+                   break;
+                 default:
+                   break;
+                 }
+
+               if(skip_until_subkey)
+                 continue;
+             }
+
            if( node->pkt->pkttype == PKT_SIGNATURE ) {
              /* do not export packets which are marked as not exportable */
              if( !(options&EXPORT_INCLUDE_LOCAL_SIGS) &&
@@ -280,10 +325,6 @@ do_export_stream( IOBUF out, STRLIST users, int secret,
                if(i<node->pkt->pkt.signature->numrevkeys)
                  continue;
              }
-
-             /* delete our verification cache */
-             delete_sig_subpkt (node->pkt->pkt.signature->unhashed,
-                                SIGSUBPKT_PRIV_VERIFY_CACHE);
            }
 
            /* Don't export attribs? */
@@ -318,8 +359,8 @@ do_export_stream( IOBUF out, STRLIST users, int secret,
                 node->pkt->pkt.secret_key->protect.sha1chk)
                {
                  /* I hope this warning doesn't confuse people. */
-                 log_info("WARNING: secret key %08lX does not have a "
-                          "simple SK checksum\n",(ulong)sk_keyid[1]);
+                 log_info(_("WARNING: secret key %08lX does not have a "
+                            "simple SK checksum\n"),(ulong)sk_keyid[1]);
 
                  sha1_warned=1;
                }
@@ -335,6 +376,11 @@ do_export_stream( IOBUF out, STRLIST users, int secret,
            }
        }
        ++*any;
+       if(keyblock_out)
+         {
+           *keyblock_out=keyblock;
+           break;
+         }
     }
     if( rc == -1 )
        rc = 0;
@@ -342,9 +388,9 @@ do_export_stream( IOBUF out, STRLIST users, int secret,
   leave:
     m_free(desc);
     keydb_release (kdbhd);
-    release_kbnode( keyblock );
+    if(rc || keyblock_out==NULL)
+      release_kbnode( keyblock );
     if( !*any )
        log_info(_("WARNING: nothing exported\n"));
     return rc;
 }
-