aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--g10/ChangeLog21
-rw-r--r--g10/g10.c11
-rw-r--r--g10/keyserver.c238
-rw-r--r--g10/options.h1
4 files changed, 177 insertions, 94 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index b7b986408..a460b97ae 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,24 @@
+2004-04-19 David Shaw <[email protected]>
+
+ * options.h, g10.c (main): Add keyserver-option
+ honor-keyserver-url. parse_keyserver_options now returns a
+ success code.
+
+ * keyserver.c (parse_keyserver_options): Return error on failure
+ to parse. Currently there is no way to fail as any unrecognized
+ options get saved to be sent to the keyserver plugins later.
+ Check length of keyserver option tokens since with =arguments we
+ must only match the prefix.
+ (free_keyserver_spec): Moved code from parse_keyserver_url.
+ (keyserver_work, keyserver_spawn): Pass in a struct keyserver_spec
+ rather than using the global keyserver option.
+ (calculate_keyid_fpr): New. Fills in a KEYDB_SEARCH_DESC for a
+ key.
+ (keyidlist): New implementation using get_pubkey_bynames rather
+ than searching the keydb directly. If honor-keyserver-url is set,
+ make up a keyserver_spec and try and fetch that key directly. Do
+ not include it in the returned keyidlist in that case.
+
2004-04-16 David Shaw <[email protected]>
* plaintext.c (handle_plaintext): Accept 'u' as a plaintext mode
diff --git a/g10/g10.c b/g10/g10.c
index a50251a3b..861d4625d 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -1439,7 +1439,7 @@ main( int argc, char **argv )
opt.keyserver_options.import_options=IMPORT_REPAIR_PKS_SUBKEY_BUG;
opt.keyserver_options.export_options=EXPORT_INCLUDE_ATTRIBUTES;
opt.keyserver_options.options=
- KEYSERVER_INCLUDE_SUBKEYS|KEYSERVER_INCLUDE_REVOKED|KEYSERVER_TRY_DNS_SRV;
+ KEYSERVER_INCLUDE_SUBKEYS|KEYSERVER_INCLUDE_REVOKED|KEYSERVER_TRY_DNS_SRV|KEYSERVER_HONOR_KEYSERVER_URL;
opt.verify_options=
VERIFY_SHOW_POLICY_URLS|VERIFY_SHOW_NOTATIONS|VERIFY_SHOW_KEYSERVER_URLS;
opt.trust_model=TM_AUTO;
@@ -2082,7 +2082,14 @@ main( int argc, char **argv )
log_error(_("could not parse keyserver URI\n"));
break;
case oKeyServerOptions:
- parse_keyserver_options(pargs.r.ret_str);
+ if(!parse_keyserver_options(pargs.r.ret_str))
+ {
+ if(configname)
+ log_error(_("%s:%d: invalid keyserver options\n"),
+ configname,configlineno);
+ else
+ log_error(_("invalid keyserver options\n"));
+ }
break;
case oImportOptions:
if(!parse_import_options(pargs.r.ret_str,&opt.import_options,1))
diff --git a/g10/keyserver.c b/g10/keyserver.c
index e7c4c93a3..3670f6d13 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -64,11 +64,12 @@ static struct parse_options keyserver_opts[]=
{"refresh-add-fake-v3-keyids",KEYSERVER_ADD_FAKE_V3,NULL},
{"auto-key-retrieve",KEYSERVER_AUTO_KEY_RETRIEVE,NULL},
{"try-dns-srv",KEYSERVER_TRY_DNS_SRV,NULL},
+ {"honor-keyserver-url",KEYSERVER_HONOR_KEYSERVER_URL,NULL},
{NULL,0,NULL}
};
-static int keyserver_work(int action,STRLIST list,
- KEYDB_SEARCH_DESC *desc,int count);
+static int keyserver_work(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,
+ int count,struct keyserver_spec *keyserver);
int
parse_keyserver_options(char *options)
@@ -83,21 +84,23 @@ parse_keyserver_options(char *options)
/* We accept quite a few possible options here - some options to
handle specially, the keyserver_options list, and import and
- export options that pertain to keyserver operations. */
+ export options that pertain to keyserver operations. Note
+ that you must use strncasecmp here as there might be an
+ =argument attached which will foil the use of strcasecmp. */
- if(ascii_strcasecmp(tok,"verbose")==0)
+ if(ascii_strncasecmp(tok,"verbose",7)==0)
opt.keyserver_options.verbose++;
- else if(ascii_strcasecmp(tok,"no-verbose")==0)
+ else if(ascii_strncasecmp(tok,"no-verbose",10)==0)
opt.keyserver_options.verbose--;
#ifdef EXEC_TEMPFILE_ONLY
- else if(ascii_strcasecmp(tok,"use-temp-files")==0 ||
- ascii_strcasecmp(tok,"no-use-temp-files")==0)
+ else if(ascii_strncasecmp(tok,"use-temp-files",14)==0 ||
+ ascii_strncasecmp(tok,"no-use-temp-files",17)==0)
log_info(_("WARNING: keyserver option \"%s\" is not used "
"on this platform\n"),tok);
#else
- else if(ascii_strcasecmp(tok,"use-temp-files")==0)
+ else if(ascii_strncasecmp(tok,"use-temp-files",14)==0)
opt.keyserver_options.options|=KEYSERVER_USE_TEMP_FILES;
- else if(ascii_strcasecmp(tok,"no-use-temp-files")==0)
+ else if(ascii_strncasecmp(tok,"no-use-temp-files",17)==0)
opt.keyserver_options.options&=~KEYSERVER_USE_TEMP_FILES;
#endif
else if(!parse_options(tok,&opt.keyserver_options.options,
@@ -132,6 +135,16 @@ parse_keyserver_options(char *options)
return ret;
}
+static void
+free_keyserver_spec(struct keyserver_spec *keyserver)
+{
+ m_free(keyserver->uri);
+ m_free(keyserver->host);
+ m_free(keyserver->port);
+ m_free(keyserver->opaque);
+ m_free(keyserver);
+}
+
struct keyserver_spec *
parse_keyserver_uri(char *uri,const char *configname,unsigned int configlineno)
{
@@ -247,11 +260,7 @@ parse_keyserver_uri(char *uri,const char *configname,unsigned int configlineno)
return keyserver;
fail:
- m_free(keyserver->uri);
- m_free(keyserver->host);
- m_free(keyserver->port);
- m_free(keyserver->opaque);
- m_free(keyserver);
+ free_keyserver_spec(keyserver);
return NULL;
}
@@ -534,7 +543,7 @@ show_prompt(KEYDB_SEARCH_DESC *desc,int numdesc,int count,const char *search)
while((num=strsep(&split," ,"))!=NULL)
if(atoi(num)>=1 && atoi(num)<=numdesc)
- keyserver_work(GET,NULL,&desc[atoi(num)-1],1);
+ keyserver_work(GET,NULL,&desc[atoi(num)-1],1,opt.keyserver);
m_free(answer);
return 1;
@@ -698,8 +707,8 @@ keyserver_search_prompt(IOBUF buffer,const char *searchstr)
#define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\""
static int
-keyserver_spawn(int action,STRLIST list,
- KEYDB_SEARCH_DESC *desc,int count,int *prog)
+keyserver_spawn(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,
+ int count,int *prog,struct keyserver_spec *keyserver)
{
int ret=0,i,gotversion=0,outofband=0;
STRLIST temp;
@@ -709,7 +718,7 @@ keyserver_spawn(int action,STRLIST list,
struct parse_options *kopts;
struct exec_info *spawn;
- assert(opt.keyserver);
+ assert(keyserver);
#ifdef EXEC_TEMPFILE_ONLY
opt.keyserver_options.use_temp_files=1;
@@ -724,9 +733,9 @@ keyserver_spawn(int action,STRLIST list,
#endif
/* Build the filename for the helper to execute */
- command=m_alloc(strlen("gpgkeys_")+strlen(opt.keyserver->scheme)+1);
+ command=m_alloc(strlen("gpgkeys_")+strlen(keyserver->scheme)+1);
strcpy(command,"gpgkeys_");
- strcat(command,opt.keyserver->scheme);
+ strcat(command,keyserver->scheme);
if(opt.keyserver_options.options&KEYSERVER_USE_TEMP_FILES)
{
@@ -754,17 +763,17 @@ keyserver_spawn(int action,STRLIST list,
fprintf(spawn->tochild,"# This is a gpg keyserver communications file\n");
fprintf(spawn->tochild,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
fprintf(spawn->tochild,"PROGRAM %s\n",VERSION);
- fprintf(spawn->tochild,"SCHEME %s\n",opt.keyserver->scheme);
+ fprintf(spawn->tochild,"SCHEME %s\n",keyserver->scheme);
- if(opt.keyserver->opaque)
- fprintf(spawn->tochild,"OPAQUE %s\n",opt.keyserver->opaque);
+ if(keyserver->opaque)
+ fprintf(spawn->tochild,"OPAQUE %s\n",keyserver->opaque);
else
{
- if(opt.keyserver->host)
- fprintf(spawn->tochild,"HOST %s\n",opt.keyserver->host);
+ if(keyserver->host)
+ fprintf(spawn->tochild,"HOST %s\n",keyserver->host);
- if(opt.keyserver->port)
- fprintf(spawn->tochild,"PORT %s\n",opt.keyserver->port);
+ if(keyserver->port)
+ fprintf(spawn->tochild,"PORT %s\n",keyserver->port);
}
/* Write options */
@@ -1112,7 +1121,8 @@ keyserver_spawn(int action,STRLIST list,
}
static int
-keyserver_work(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,int count)
+keyserver_work(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,
+ int count,struct keyserver_spec *keyserver)
{
int rc=0,ret=0;
@@ -1130,7 +1140,7 @@ keyserver_work(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,int count)
#else
/* Spawn a handler */
- rc=keyserver_spawn(action,list,desc,count,&ret);
+ rc=keyserver_spawn(action,list,desc,count,&ret,keyserver);
if(ret)
{
switch(ret)
@@ -1198,7 +1208,7 @@ keyserver_export(STRLIST users)
if(sl)
{
- rc=keyserver_work(SEND,sl,NULL,0);
+ rc=keyserver_work(SEND,sl,NULL,0,opt.keyserver);
free_strlist(sl);
}
@@ -1236,7 +1246,7 @@ keyserver_import(STRLIST users)
}
if(count>0)
- rc=keyserver_work(GET,NULL,desc,count);
+ rc=keyserver_work(GET,NULL,desc,count,opt.keyserver);
m_free(desc);
@@ -1259,7 +1269,7 @@ keyserver_import_fprint(const byte *fprint,size_t fprint_len)
memcpy(desc.u.fpr,fprint,fprint_len);
- return keyserver_work(GET,NULL,&desc,1);
+ return keyserver_work(GET,NULL,&desc,1,opt.keyserver);
}
int
@@ -1273,62 +1283,115 @@ keyserver_import_keyid(u32 *keyid)
desc.u.kid[0]=keyid[0];
desc.u.kid[1]=keyid[1];
- return keyserver_work(GET,NULL,&desc,1);
+ return keyserver_work(GET,NULL,&desc,1,opt.keyserver);
+}
+
+static void
+calculate_keyid_fpr(PKT_public_key *pk,KEYDB_SEARCH_DESC *desc)
+{
+ if(pk->version<4)
+ {
+ desc->mode=KEYDB_SEARCH_MODE_LONG_KID;
+ keyid_from_pk(pk,desc->u.kid);
+ }
+ else
+ {
+ size_t dummy;
+
+ desc->mode=KEYDB_SEARCH_MODE_FPR20;
+ fingerprint_from_pk(pk,desc->u.fpr,&dummy);
+ }
}
-/* code mostly stolen from do_export_stream */
static int
keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
{
- int rc=0,ndesc,num=100;
+ int rc=0,num=100;
KBNODE keyblock=NULL,node;
- KEYDB_HANDLE kdbhd;
- KEYDB_SEARCH_DESC *desc;
- STRLIST sl;
+ GETKEY_CTX ctx;
*count=0;
- *klist=m_alloc(sizeof(KEYDB_SEARCH_DESC)*num);
-
- kdbhd=keydb_new(0);
-
- if(!users)
+ rc=get_pubkey_bynames(&ctx,NULL,users,&keyblock);
+ if(rc)
{
- ndesc = 1;
- desc = m_alloc_clear ( ndesc * sizeof *desc);
- desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
+ log_error("error reading key: %s\n", g10_errstr(rc) );
+ get_pubkey_end( ctx );
+ return rc;
}
- else
+
+ *klist=m_alloc(sizeof(KEYDB_SEARCH_DESC)*num);
+
+ do
{
- for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
- ;
- desc = m_alloc ( ndesc * sizeof *desc);
-
- for (ndesc=0, sl=users; sl; sl = sl->next)
+ if((node=find_kbnode(keyblock,PKT_PUBLIC_KEY)))
{
- if(classify_user_id (sl->d, desc+ndesc))
- ndesc++;
- else
- log_error (_("key `%s' not found: %s\n"),
- sl->d, g10_errstr (G10ERR_INV_USER_ID));
- }
- }
+ PKT_public_key *pk=node->pkt->pkt.public_key;
- while (!(rc = keydb_search (kdbhd, desc, ndesc)))
- {
- if (!users)
- desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
+ /* Check the user ID for a preferred keyserver subpacket. */
+ if(opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)
+ {
+ PKT_user_id *uid=NULL;
+ PKT_signature *sig=NULL;
- /* read the keyblock */
- rc = keydb_get_keyblock (kdbhd, &keyblock );
- if( rc )
- {
- log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
- goto leave;
- }
+ for(node=node->next;node;node=node->next)
+ {
+ if(node->pkt->pkttype==PKT_USER_ID
+ && node->pkt->pkt.user_id->is_primary)
+ uid=node->pkt->pkt.user_id;
+ else if(node->pkt->pkttype==PKT_SIGNATURE
+ && node->pkt->pkt.signature->
+ flags.chosen_selfsig && uid)
+ {
+ sig=node->pkt->pkt.signature;
+ break;
+ }
+ }
+
+ if(uid && sig)
+ {
+ const byte *p;
+ size_t plen;
+ p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&plen);
+ if(p && plen)
+ {
+ struct keyserver_spec *keyserver;
+ byte *dupe=m_alloc(plen+1);
+
+ memcpy(dupe,p,plen);
+ dupe[plen]='\0';
+
+ /* Make up a keyserver structure and do an
+ import for this key. */
+
+ keyserver=parse_keyserver_uri(dupe,NULL,0);
+ m_free(dupe);
+
+ if(keyserver)
+ {
+ KEYDB_SEARCH_DESC desc;
+
+ calculate_keyid_fpr(pk,&desc);
+
+ rc=keyserver_work(GET,NULL,&desc,1,keyserver);
+ if(rc)
+ log_info(_("WARNING: unable to refresh key %s"
+ " via %s: %s\n"),
+ keystr_from_pk(pk),keyserver->uri,
+ g10_errstr(rc));
+ free_keyserver_spec(keyserver);
+
+ continue;
+ }
+ else
+ log_info(_("WARNING: unable to refresh key %s"
+ " via %s: %s\n"),
+ keystr_from_pk(pk),keyserver->uri,
+ g10_errstr(G10ERR_BAD_URI));
+ }
+ }
+ }
- if((node=find_kbnode(keyblock,PKT_PUBLIC_KEY)))
- {
/* This is to work around a bug in some keyservers (pksd and
OKS) that calculate v4 RSA keyids as if they were v3 RSA.
The answer is to refresh both the correct v4 keyid
@@ -1336,12 +1399,10 @@ keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
This only happens for key refresh using the HKP scheme
and if the refresh-add-fake-v3-keyids keyserver option is
set. */
- if(fakev3 && is_RSA(node->pkt->pkt.public_key->pubkey_algo) &&
- node->pkt->pkt.public_key->version>=4)
+ if(fakev3 && is_RSA(pk->pubkey_algo) && pk->version>=4)
{
(*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID;
- mpi_get_keyid(node->pkt->pkt.public_key->pkey[0],
- (*klist)[*count].u.kid);
+ mpi_get_keyid(pk->pkey[0],(*klist)[*count].u.kid);
(*count)++;
if(*count==num)
@@ -1355,19 +1416,17 @@ keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
This is because it's easy to calculate any sort of key id
from a v4 fingerprint, but not a v3 fingerprint. */
- if(node->pkt->pkt.public_key->version<4)
+ if(pk->version<4)
{
(*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID;
- keyid_from_pk(node->pkt->pkt.public_key,
- (*klist)[*count].u.kid);
+ keyid_from_pk(pk,(*klist)[*count].u.kid);
}
else
{
size_t dummy;
(*klist)[*count].mode=KEYDB_SEARCH_MODE_FPR20;
- fingerprint_from_pk(node->pkt->pkt.public_key,
- (*klist)[*count].u.fpr,&dummy);
+ fingerprint_from_pk(pk,(*klist)[*count].u.fpr,&dummy);
}
(*count)++;
@@ -1378,17 +1437,12 @@ keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
*klist=m_realloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num);
}
}
- }
- if(rc==-1)
- rc=0;
-
- leave:
- m_free(desc);
- keydb_release(kdbhd);
- release_kbnode(keyblock);
+ release_kbnode(keyblock);
+ }
+ while(!get_pubkey_next(ctx,NULL,&keyblock));
- return rc;
+ return 0;
}
/* Note this is different than the original HKP refresh. It allows
@@ -1427,7 +1481,7 @@ keyserver_refresh(STRLIST users)
count,opt.keyserver->uri);
}
- rc=keyserver_work(GET,NULL,desc,count);
+ rc=keyserver_work(GET,NULL,desc,count,opt.keyserver);
}
m_free(desc);
@@ -1439,7 +1493,7 @@ int
keyserver_search(STRLIST tokens)
{
if(tokens)
- return keyserver_work(SEARCH,tokens,NULL,0);
+ return keyserver_work(SEARCH,tokens,NULL,0,opt.keyserver);
else
return 0;
}
diff --git a/g10/options.h b/g10/options.h
index a0313b13f..8a93a8014 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -267,5 +267,6 @@ struct
#define KEYSERVER_ADD_FAKE_V3 (1<<5)
#define KEYSERVER_AUTO_KEY_RETRIEVE (1<<6)
#define KEYSERVER_TRY_DNS_SRV (1<<7)
+#define KEYSERVER_HONOR_KEYSERVER_URL (1<<8)
#endif /*G10_OPTIONS_H*/