diff --git a/g10/import.c b/g10/import.c index 441dcca9d..e40141e94 100644 --- a/g10/import.c +++ b/g10/import.c @@ -59,14 +59,17 @@ struct stats_s { static int import( IOBUF inp, const char* fname,struct stats_s *stats, - unsigned char **fpr,size_t *fpr_len,unsigned int options ); + unsigned char **fpr,size_t *fpr_len,unsigned int options, + import_filter filter, void *filter_arg ); 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 char **fpr,size_t *fpr_len, - unsigned int options,int from_sk); + unsigned int options,int from_sk, + import_filter filter, void *filter_arg); static int import_secret_one( const char *fname, KBNODE keyblock, - struct stats_s *stats, unsigned int options); + struct stats_s *stats, unsigned int options, + import_filter filter, void *filter_arg); static int import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats); static int chk_self_sigs( const char *fname, KBNODE keyblock, @@ -163,7 +166,8 @@ import_release_stats_handle (void *p) static int import_keys_internal( IOBUF inp, char **fnames, int nnames, void *stats_handle, unsigned char **fpr, size_t *fpr_len, - unsigned int options ) + unsigned int options, + import_filter filter, void *filter_arg) { int i, rc = 0; struct stats_s *stats = stats_handle; @@ -172,7 +176,8 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames, stats = import_new_stats_handle (); if (inp) { - rc = import( inp, "[stream]", stats, fpr, fpr_len, options); + rc = import (inp, "[stream]", stats, fpr, fpr_len, options, + filter, filter_arg); } else { int once = (!fnames && !nnames); @@ -192,7 +197,8 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames, log_error(_("can't open `%s': %s\n"), fname, strerror(errno) ); else { - rc = import( inp2, fname, stats, fpr, fpr_len, options ); + rc = import (inp2, fname, stats, fpr, fpr_len, options, + NULL, NULL); iobuf_close(inp2); /* Must invalidate that ugly cache to actually close it. */ iobuf_ioctl (NULL, 2, 0, (char*)fname); @@ -223,19 +229,23 @@ void import_keys( char **fnames, int nnames, void *stats_handle, unsigned int options ) { - import_keys_internal(NULL,fnames,nnames,stats_handle,NULL,NULL,options); + import_keys_internal (NULL, fnames, nnames, stats_handle, NULL, NULL, + options, NULL, NULL); } int import_keys_stream( IOBUF inp, void *stats_handle, - unsigned char **fpr, size_t *fpr_len,unsigned int options ) + unsigned char **fpr, size_t *fpr_len,unsigned int options, + import_filter filter, void *filter_arg ) { - return import_keys_internal(inp,NULL,0,stats_handle,fpr,fpr_len,options); + return import_keys_internal (inp, NULL, 0, stats_handle, fpr, fpr_len, + options, filter, filter_arg); } static int import( IOBUF inp, const char* fname,struct stats_s *stats, - unsigned char **fpr,size_t *fpr_len,unsigned int options ) + unsigned char **fpr,size_t *fpr_len,unsigned int options, + import_filter filter, void *filter_arg) { PACKET *pending_pkt = NULL; KBNODE keyblock = NULL; @@ -252,9 +262,11 @@ import( IOBUF inp, const char* fname,struct stats_s *stats, while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) { if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY ) - rc = import_one( fname, keyblock, stats, fpr, fpr_len, options, 0); - else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) - rc = import_secret_one( fname, keyblock, stats, options ); + rc = import_one (fname, keyblock, stats, fpr, fpr_len, options, 0, + filter, filter_arg); + else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) + rc = import_secret_one (fname, keyblock, stats, options, + filter, filter_arg); else if( keyblock->pkt->pkttype == PKT_SIGNATURE && keyblock->pkt->pkt.signature->sig_class == 0x20 ) rc = import_revoke_cert( fname, keyblock, stats ); @@ -738,7 +750,7 @@ check_prefs(KBNODE keyblock) static int import_one( const char *fname, KBNODE keyblock, struct stats_s *stats, unsigned char **fpr,size_t *fpr_len,unsigned int options, - int from_sk ) + int from_sk, import_filter filter, void *filter_arg) { PKT_public_key *pk; PKT_public_key *pk_orig; @@ -778,6 +790,13 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats, return 0; } + if (filter && filter (pk, NULL, filter_arg)) + { + log_error (_("key %s: %s\n"), keystr_from_pk(pk), + _("rejected by import filter")); + return 0; + } + if (opt.interactive) { if(is_status_enabled()) print_import_check (pk, uidnode->pkt->pkt.user_id); @@ -1146,7 +1165,8 @@ sec_to_pub_keyblock(KBNODE sec_keyblock) */ static int import_secret_one( const char *fname, KBNODE keyblock, - struct stats_s *stats, unsigned int options) + struct stats_s *stats, unsigned int options, + import_filter filter, void *filter_arg) { PKT_secret_key *sk; KBNODE node, uidnode; @@ -1162,6 +1182,12 @@ import_secret_one( const char *fname, KBNODE keyblock, keyid_from_sk( sk, keyid ); uidnode = find_next_kbnode( keyblock, PKT_USER_ID ); + if (filter && filter (NULL, sk, filter_arg)) { + log_error (_("secret key %s: %s\n"), keystr_from_sk(sk), + _("rejected by import filter")); + return 0; + } + if( opt.verbose ) { log_info( "sec %4u%c/%s %s ", @@ -1240,8 +1266,9 @@ 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, - NULL,NULL,opt.import_options,1); + import_one (fname, pub_keyblock, stats, + NULL, NULL, opt.import_options, 1, + NULL, NULL); release_kbnode(pub_keyblock); } } diff --git a/g10/keyserver.c b/g10/keyserver.c index 7bf983064..dca5e18bf 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -656,7 +656,7 @@ parse_keyrec(char *keystring) case 'R': work->flags|=1; break; - + case 'd': case 'D': work->flags|=2; @@ -910,7 +910,7 @@ keyserver_search_prompt(IOBUF buffer,const char *searchstr) /* Leave this commented out or now, and perhaps for a very long time. All HKPish servers return HTML error messages for no-key-found. */ - /* + /* if(!started) log_info(_("keyserver does not support searching\n")); else @@ -959,7 +959,52 @@ direct_uri_map(const char *scheme,unsigned int is_direct) #define KEYSERVER_ARGS_KEEP " -o \"%O\" \"%I\"" #define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\"" -static int + +/* Check whether a key matches the search description. The filter + returns 0 if the key shall be imported. Note that this kind of + filter is not related to the iobuf filters. */ +static int +keyserver_retrieval_filter (PKT_public_key *pk, PKT_secret_key *sk, void *arg) +{ + KEYDB_SEARCH_DESC *desc = arg; + u32 keyid[2]; + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fpr_len = 0; + + /* Secret keys are not expected from a keyserver. Do not import. */ + if (sk) + return G10ERR_GENERAL; + + fingerprint_from_pk (pk, fpr, &fpr_len); + keyid_from_pk (pk, keyid); + + /* Compare requested and returned fingerprints if available. */ + if (desc->mode == KEYDB_SEARCH_MODE_FPR20) + { + if (fpr_len != 20 || memcmp (fpr, desc->u.fpr, 20)) + return G10ERR_GENERAL; + } + else if (desc->mode == KEYDB_SEARCH_MODE_FPR16) + { + if (fpr_len != 16 || memcmp (fpr, desc->u.fpr, 16)) + return G10ERR_GENERAL; + } + else if (desc->mode == KEYDB_SEARCH_MODE_LONG_KID) + { + if (keyid[0] != desc->u.kid[0] || keyid[1] != desc->u.kid[1]) + return G10ERR_GENERAL; + } + else if (desc->mode == KEYDB_SEARCH_MODE_SHORT_KID) + { + if (keyid[1] != desc->u.kid[1]) + return G10ERR_GENERAL; + } + + return 0; +} + + +static int keyserver_spawn(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, int count,int *prog,unsigned char **fpr,size_t *fpr_len, struct keyserver_spec *keyserver) @@ -999,7 +1044,7 @@ keyserver_spawn(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, the program of this process lives. Fortunately Windows provides a way to retrieve this and our get_libexecdir function has been modified to return just this. Setting the exec-path is not - anymore required. + anymore required. set_exec_path(libexecdir); */ #else @@ -1031,7 +1076,7 @@ keyserver_spawn(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, fetcher that can speak that protocol (this is a problem for LDAP). */ - strcat(command,GPGKEYS_PREFIX); + strcat(command,GPGKEYS_PREFIX); strcat(command,scheme); /* This "_uri" thing is in case we need to call a direct handler @@ -1061,7 +1106,7 @@ keyserver_spawn(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, { command=xrealloc(command,strlen(command)+ strlen(KEYSERVER_ARGS_NOKEEP)+1); - strcat(command,KEYSERVER_ARGS_NOKEEP); + strcat(command,KEYSERVER_ARGS_NOKEEP); } ret=exec_write(&spawn,NULL,command,NULL,0,0); @@ -1509,8 +1554,9 @@ keyserver_spawn(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, but we better protect against rogue keyservers. */ import_keys_stream (spawn->fromchild, stats_handle, fpr, fpr_len, - (opt.keyserver_options.import_options - | IMPORT_NO_SECKEY)); + (opt.keyserver_options.import_options + | IMPORT_NO_SECKEY), + keyserver_retrieval_filter, desc); import_print_stats(stats_handle); import_release_stats_handle(stats_handle); @@ -1541,7 +1587,7 @@ keyserver_spawn(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, return ret; } -static int +static int keyserver_work(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, int count,unsigned char **fpr,size_t *fpr_len, struct keyserver_spec *keyserver) @@ -1611,7 +1657,7 @@ keyserver_work(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, #endif /* ! DISABLE_KEYSERVER_HELPERS*/ } -int +int keyserver_export(STRLIST users) { STRLIST sl=NULL; @@ -1643,7 +1689,7 @@ keyserver_export(STRLIST users) return rc; } -int +int keyserver_import(STRLIST users) { KEYDB_SEARCH_DESC *desc; @@ -1703,7 +1749,7 @@ keyserver_import_fprint(const byte *fprint,size_t fprint_len, return keyserver_work(KS_GET,NULL,&desc,1,NULL,NULL,keyserver); } -int +int keyserver_import_keyid(u32 *keyid,struct keyserver_spec *keyserver) { KEYDB_SEARCH_DESC desc; @@ -1718,7 +1764,7 @@ keyserver_import_keyid(u32 *keyid,struct keyserver_spec *keyserver) } /* code mostly stolen from do_export_stream */ -static int +static int keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3) { int rc=0,ndesc,num=100; @@ -1741,10 +1787,10 @@ keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3) } else { - for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) + for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) ; desc = xmalloc ( ndesc * sizeof *desc); - + for (ndesc=0, sl=users; sl; sl = sl->next) { if(classify_user_id (sl->d, desc+ndesc)) @@ -1757,7 +1803,7 @@ keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3) while (!(rc = keydb_search (kdbhd, desc, ndesc))) { - if (!users) + if (!users) desc[0].mode = KEYDB_SEARCH_MODE_NEXT; /* read the keyblock */ @@ -1860,7 +1906,7 @@ keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3) if(rc==-1) rc=0; - + leave: if(rc) xfree(*klist); @@ -2043,7 +2089,7 @@ keyserver_import_cert(const char *name,unsigned char **fpr,size_t *fpr_len) rc=import_keys_stream (key, NULL, fpr, fpr_len, (opt.keyserver_options.import_options - | IMPORT_NO_SECKEY)); + | IMPORT_NO_SECKEY), NULL, NULL); opt.no_armor=armor_status; @@ -2182,7 +2228,7 @@ keyserver_import_ldap(const char *name,unsigned char **fpr,size_t *fpr_len) snprintf(port,7,":%u",srvlist[i].port); strcat(keyserver->host,port); } - + strcat(keyserver->host," "); } @@ -2198,7 +2244,7 @@ keyserver_import_ldap(const char *name,unsigned char **fpr,size_t *fpr_len) strcat(keyserver->host,domain); append_to_strlist(&list,name); - + rc=keyserver_work(KS_GETNAME,list,NULL,0,fpr,fpr_len,keyserver); free_strlist(list); diff --git a/g10/main.h b/g10/main.h index 784ade06d..e4c4385bf 100644 --- a/g10/main.h +++ b/g10/main.h @@ -207,11 +207,15 @@ MPI encode_md_value( PKT_public_key *pk, PKT_secret_key *sk, MD_HANDLE md, int hash_algo ); /*-- import.c --*/ + +typedef int (*import_filter)(PKT_public_key *pk, PKT_secret_key *sk, void *arg); + int parse_import_options(char *str,unsigned int *options,int noisy); void import_keys( char **fnames, int nnames, void *stats_hd, unsigned int options ); -int import_keys_stream( IOBUF inp,void *stats_hd,unsigned char **fpr, - size_t *fpr_len,unsigned int options ); +int import_keys_stream (IOBUF inp,void *stats_hd,unsigned char **fpr, + size_t *fpr_len,unsigned int options, + import_filter filter, void *filter_arg); void *import_new_stats_handle (void); void import_release_stats_handle (void *p); void import_print_stats (void *hd);