From 070f1cba5d3f0b8206377eb5ca7602405208f8d8 Mon Sep 17 00:00:00 2001 From: David Shaw Date: Sat, 23 Feb 2002 15:42:15 +0000 Subject: [PATCH] Clarify the notion of a partial failure. This is possible if more than one key is being handled in a batch, and one fails while the other succeeds. Note that a search that comes up with no results is not a failure - that is a valid response of "no answer". Allow GnuPG to send us full v4 fingerprints, long key ids, or short key ids while fetching. Since the LDAP server doesn't actually handle fingerprints, chop them down to long key ids for actual use. When searching for a keyid, search for subkeys as well as primary keys. This is mostly significant when automatically fetching the key based on the id in a header (i.e. "signature made by...."). "no-include-subkeys" disables. --- keyserver/ChangeLog | 19 ++ keyserver/gpgkeys_ldap.c | 371 ++++++++++++++++++++++----------------- 2 files changed, 227 insertions(+), 163 deletions(-) diff --git a/keyserver/ChangeLog b/keyserver/ChangeLog index fb3c3345b..47a711ef6 100644 --- a/keyserver/ChangeLog +++ b/keyserver/ChangeLog @@ -1,3 +1,22 @@ +2002-02-23 David Shaw + + * gpgkeys_ldap: Clarify the notion of a partial failure. This is + possible if more than one key is being handled in a batch, and one + fails while the other succeeds. Note that a search that comes up + with no results is not a failure - that is a valid response of "no + answer". + + * gpgkeys_ldap.c (get_key): Allow GnuPG to send us full v4 + fingerprints, long key ids, or short key ids while fetching. + Since the LDAP server doesn't actually handle fingerprints, chop + them down to long key ids for actual use. + + * gpgkeys_ldap.c (main, get_key): When searching for a keyid, + search for subkeys as well as primary keys. This is mostly + significant when automatically fetching the key based on the id in + a header (i.e. "signature made by...."). "no-include-subkeys" + disables. + 2002-02-14 David Shaw * gpgkeys_ldap.c: Fix compiler warning. diff --git a/keyserver/gpgkeys_ldap.c b/keyserver/gpgkeys_ldap.c index 048af8948..e28b18fb3 100644 --- a/keyserver/gpgkeys_ldap.c +++ b/keyserver/gpgkeys_ldap.c @@ -37,10 +37,11 @@ #define SEARCH 2 #define MAX_LINE 80 -int verbose=0,include_disabled=0,include_revoked=0; +int verbose=0,include_disabled=0,include_revoked=0,include_subkeys=1; char *basekeyspacedn=NULL; char host[80]; FILE *input=NULL,*output=NULL,*console=NULL; +LDAP *ldap=NULL; struct keylist { @@ -49,12 +50,13 @@ struct keylist }; /* Returns 0 on success, -1 on failure, and 1 on eof */ -int send_key(LDAP *ldap,char *keyid) +int send_key(void) { int err,gotit=0,keysize=1,ret=-1; char *dn=NULL; char line[MAX_LINE]; char *key[2]={0,0}; + char keyid[17]; #ifndef __riscos__ LDAPMod mod={LDAP_MOD_ADD,"pgpKeyV2",{key}},*attrs[2]={&mod,NULL}; #else @@ -148,31 +150,61 @@ int send_key(LDAP *ldap,char *keyid) free(key[0]); free(dn); + if(ret!=0) + fprintf(output,"KEY %s FAILED\n",keyid); + return ret; } -int get_key(LDAP *ldap,char *getkey) +/* Returns 0 on success and -1 on failure. Note that key-not-found is + not an error! */ +int get_key(char *getkey) { char **vals; LDAPMessage *res,*each; int ret=-1,err,count; struct keylist *dupelist=NULL; - char search[29]; + char search[62]; char *attrs[]={"pgpKeyV2","pgpuserid","pgpkeyid","pgpcertid","pgprevoked", "pgpdisabled","pgpkeycreatetime","modifytimestamp", "pgpkeysize","pgpkeytype",NULL}; /* Build the search string */ - if(strncmp(getkey,"0x00000000",10)==0) + /* GPG can send us a v4 fingerprint, a v3 or v4 long key id, or a v3 + or v4 short key id */ + + if(strncmp(getkey,"0x",2)==0) + getkey+=2; + + if(strlen(getkey)>16) { - getkey+=10; - sprintf(search,"(pgpkeyid=%.8s)",getkey); + char *offset=&getkey[strlen(getkey)-16]; + + /* fingerprint. Take the last 16 characters and treat it like a + long key id */ + + if(include_subkeys) + sprintf(search,"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))", + offset,offset); + else + sprintf(search,"(pgpcertid=%.16s)",offset); + } + else if(strlen(getkey)>8) + { + /* long key id */ + + if(include_subkeys) + sprintf(search,"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))", + getkey,getkey); + else + sprintf(search,"(pgpcertid=%.16s)",getkey); } else { - getkey+=2; - sprintf(search,"(pgpcertid=%.16s)",getkey); + /* short key id */ + + sprintf(search,"(pgpkeyid=%.8s)",getkey); } fprintf(output,"KEY 0x%s BEGIN\n",getkey); @@ -183,7 +215,7 @@ int get_key(LDAP *ldap,char *getkey) if(!verbose) attrs[1]=NULL; - fprintf(console,"gpgkeys: requesting key %s from LDAP keyserver %s\n", + fprintf(console,"gpgkeys: requesting key 0x%s from LDAP keyserver %s\n", getkey,host); err=ldap_search_s(ldap,basekeyspacedn, @@ -200,149 +232,151 @@ int get_key(LDAP *ldap,char *getkey) { fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey); fprintf(output,"KEY 0x%s FAILED\n",getkey); - goto fail; } - - /* There may be more than one unique result for a given keyID, so we - should fetch them all (test this by fetching short key id - 0xDEADBEEF). */ - - each=ldap_first_entry(ldap,res); - while(each!=NULL) + else { - struct keylist *keyptr=dupelist; + /* There may be more than one unique result for a given keyID, + so we should fetch them all (test this by fetching short key + id 0xDEADBEEF). */ - /* Use the long keyid to remove duplicates. The LDAP server - returns the same keyid more than once if there are multiple - user IDs on the key. */ - - vals=ldap_get_values(ldap,each,"pgpcertid"); - if(vals!=NULL) + each=ldap_first_entry(ldap,res); + while(each!=NULL) { - while(keyptr!=NULL) + struct keylist *keyptr=dupelist; + + /* Use the long keyid to remove duplicates. The LDAP server + returns the same keyid more than once if there are + multiple user IDs on the key. */ + + vals=ldap_get_values(ldap,each,"pgpcertid"); + if(vals!=NULL) { - if(strcasecmp(keyptr->str,vals[0])==0) - break; - - keyptr=keyptr->next; - } - - if(!keyptr) - { - /* it's not a duplicate, so add it */ - - keyptr=malloc(sizeof(struct keylist)); - if(keyptr==NULL) + while(keyptr!=NULL) { - fprintf(console,"gpgkeys: out of memory when deduping " - "key list\n"); - goto fail; + if(strcasecmp(keyptr->str,vals[0])==0) + break; + + keyptr=keyptr->next; } - strncpy(keyptr->str,vals[0],MAX_LINE); - keyptr->str[MAX_LINE-1]='\0'; - - keyptr->next=dupelist; - dupelist=keyptr; - keyptr=NULL; - } - - ldap_value_free(vals); - } - - if(!keyptr) /* it's not a duplicate */ - { - if(verbose) - { - vals=ldap_get_values(ldap,each,"pgpuserid"); - if(vals!=NULL) + if(!keyptr) { - /* This is wrong, as the user ID is UTF8. A better way to - handle this would be to send it over to gpg and display - it on that side of the pipe. */ - fprintf(console,"\nUser ID:\t%s\n",vals[0]); - ldap_value_free(vals); + /* it's not a duplicate, so add it */ + + keyptr=malloc(sizeof(struct keylist)); + if(keyptr==NULL) + { + fprintf(console,"gpgkeys: out of memory when deduping " + "key list\n"); + goto fail; + } + + strncpy(keyptr->str,vals[0],MAX_LINE); + keyptr->str[MAX_LINE-1]='\0'; + + keyptr->next=dupelist; + dupelist=keyptr; + keyptr=NULL; } - vals=ldap_get_values(ldap,each,"pgprevoked"); - if(vals!=NULL) - { - if(atoi(vals[0])==1) - fprintf(console,"\t\t** KEY REVOKED **\n"); - ldap_value_free(vals); - } - - vals=ldap_get_values(ldap,each,"pgpdisabled"); - if(vals!=NULL) - { - if(atoi(vals[0])==1) - fprintf(console,"\t\t** KEY DISABLED **\n"); - ldap_value_free(vals); - } - - vals=ldap_get_values(ldap,each,"pgpkeyid"); - if(vals!=NULL) - { - fprintf(console,"Short key ID:\t%s\n",vals[0]); - ldap_value_free(vals); - } - - vals=ldap_get_values(ldap,each,"pgpcertid"); - if(vals!=NULL) - { - fprintf(console,"Long key ID:\t%s\n",vals[0]); - ldap_value_free(vals); - } - - /* YYYYMMDDHHmmssZ */ - - vals=ldap_get_values(ldap,each,"pgpkeycreatetime"); - if(vals!=NULL && strlen(vals[0])==15) - { - fprintf(console,"Key created:\t%.2s/%.2s/%.4s\n", - &vals[0][4],&vals[0][6],vals[0]); - ldap_value_free(vals); - } - - vals=ldap_get_values(ldap,each,"modifytimestamp"); - if(vals!=NULL && strlen(vals[0])==15) - { - fprintf(console,"Key modified:\t%.2s/%.2s/%.4s\n", - &vals[0][4],&vals[0][6],vals[0]); - ldap_value_free(vals); - } - - vals=ldap_get_values(ldap,each,"pgpkeysize"); - if(vals!=NULL) - { - fprintf(console,"Key size:\t%d\n",atoi(vals[0])); - ldap_value_free(vals); - } - - vals=ldap_get_values(ldap,each,"pgpkeytype"); - if(vals!=NULL) - { - fprintf(console,"Key type:\t%s\n",vals[0]); - ldap_value_free(vals); - } - } - - vals=ldap_get_values(ldap,each,"pgpKeyV2"); - if(vals==NULL) - { - fprintf(console,"gpgkeys: unable to retrieve key %s " - "from keyserver\n",getkey); - fprintf(output,"KEY 0x%s FAILED\n",getkey); - } - else - { - fprintf(output,"%sKEY 0x%s END\n",vals[0],getkey); - ldap_value_free(vals); } - } - each=ldap_next_entry(ldap,each); + if(!keyptr) /* it's not a duplicate */ + { + if(verbose) + { + vals=ldap_get_values(ldap,each,"pgpuserid"); + if(vals!=NULL) + { + /* This is wrong, as the user ID is UTF8. A + better way to handle this would be to send it + over to gpg and display it on that side of + the pipe. */ + fprintf(console,"\nUser ID:\t%s\n",vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgprevoked"); + if(vals!=NULL) + { + if(atoi(vals[0])==1) + fprintf(console,"\t\t** KEY REVOKED **\n"); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpdisabled"); + if(vals!=NULL) + { + if(atoi(vals[0])==1) + fprintf(console,"\t\t** KEY DISABLED **\n"); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpkeyid"); + if(vals!=NULL) + { + fprintf(console,"Short key ID:\t%s\n",vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpcertid"); + if(vals!=NULL) + { + fprintf(console,"Long key ID:\t%s\n",vals[0]); + ldap_value_free(vals); + } + + /* YYYYMMDDHHmmssZ */ + + vals=ldap_get_values(ldap,each,"pgpkeycreatetime"); + if(vals!=NULL && strlen(vals[0])==15) + { + fprintf(console,"Key created:\t%.2s/%.2s/%.4s\n", + &vals[0][4],&vals[0][6],vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"modifytimestamp"); + if(vals!=NULL && strlen(vals[0])==15) + { + fprintf(console,"Key modified:\t%.2s/%.2s/%.4s\n", + &vals[0][4],&vals[0][6],vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpkeysize"); + if(vals!=NULL) + { + fprintf(console,"Key size:\t%d\n",atoi(vals[0])); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpkeytype"); + if(vals!=NULL) + { + fprintf(console,"Key type:\t%s\n",vals[0]); + ldap_value_free(vals); + } + } + + vals=ldap_get_values(ldap,each,"pgpKeyV2"); + if(vals==NULL) + { + fprintf(console,"gpgkeys: unable to retrieve key %s " + "from keyserver\n",getkey); + fprintf(output,"KEY 0x%s FAILED\n",getkey); + } + else + { + fprintf(output,"%sKEY 0x%s END\n",vals[0],getkey); + + ldap_value_free(vals); + } + } + + each=ldap_next_entry(ldap,each); + } } ret=0; @@ -398,7 +432,9 @@ void printquoted(FILE *stream,char *string,char delim) } } -int search_key(LDAP *ldap,char *searchkey) +/* Returns 0 on success and -1 on error. Note that key-not-found is + not an error! */ +int search_key(char *searchkey) { char **vals; LDAPMessage *res,*each; @@ -549,10 +585,9 @@ int search_key(LDAP *ldap,char *searchkey) int main(int argc,char *argv[]) { - LDAP *ldap=NULL; int port=0,arg,err,action=-1,ret=KEYSERVER_INTERNAL_ERROR; char line[MAX_LINE],**vals; - int version; + int version,failed=0; char *attrs[]={"basekeyspacedn","version","software",NULL}; LDAPMessage *res; struct keylist *keylist=NULL,*keyptr=NULL; @@ -688,6 +723,13 @@ int main(int argc,char *argv[]) else include_revoked=1; } + else if(strcasecmp(start,"include-subkeys")==0) + { + if(no) + include_subkeys=0; + else + include_subkeys=1; + } continue; } @@ -832,27 +874,24 @@ int main(int argc,char *argv[]) while(keyptr!=NULL) { - struct keylist *current=keyptr; + if(get_key(keyptr->str)==-1) + failed++; - get_key(ldap,current->str); - - keyptr=current->next; - - /* Free it as we go */ - free(current); + keyptr=keyptr->next; } break; case SEND: { - char keyid[17]="????"; int ret; - while((ret=send_key(ldap,keyid))!=1) + do { - if(ret!=0) - fprintf(output,"KEY %s FAILED\n",keyid); + ret=send_key(); + if(ret==-1) + failed++; } + while(ret!=1); } break; @@ -882,21 +921,19 @@ int main(int argc,char *argv[]) keyptr=keylist; while(keyptr!=NULL) { - struct keylist *current=keyptr; - - strcat(searchkey,current->str); + strcat(searchkey,keyptr->str); strcat(searchkey,"*"); - keyptr=current->next; - - /* Free it as we go */ - free(current); + keyptr=keyptr->next; } /* Nail that last "*" */ searchkey[strlen(searchkey)-1]='\0'; - if(search_key(ldap,searchkey)==-1) - fprintf(output,"SEARCH %s FAILED\n",searchkey); + if(search_key(searchkey)==-1) + { + fprintf(output,"SEARCH %s FAILED\n",searchkey); + failed++; + } free(searchkey); } @@ -904,10 +941,18 @@ int main(int argc,char *argv[]) break; } - ret=KEYSERVER_OK; + if(!failed) + ret=KEYSERVER_OK; fail: + while(keylist!=NULL) + { + struct keylist *current=keylist; + keylist=keylist->next; + free(current); + } + if(input!=stdin) fclose(input);