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);