1
/* gpgkeys_oldhkp.c - talk to an HKP keyserver
2
* Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
4
* This file is part of GnuPG.
6
* GnuPG is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* GnuPG is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22
/* This is the original version that uses the iobuf library for
35
#define INCLUDED_BY_MAIN_MODULE 1
38
#include "keyserver.h"
48
static int verbose=0,include_revoked=0,include_disabled=0;
49
static unsigned int http_flags=0;
50
static char host[MAX_HOST+1]={'\0'},proxy[MAX_PROXY+1]={'\0'},
51
port[MAX_PORT+1]={'\0'},path[URLMAX_PATH+1];
52
static FILE *input=NULL,*output=NULL,*console=NULL;
55
urlencode_filter( void *opaque, int control,
56
IOBUF a, byte *buf, size_t *ret_len)
58
size_t size = *ret_len;
61
if( control == IOBUFCTRL_FLUSH ) {
63
for(p=buf; size; p++, size-- ) {
64
if( isalnum(*p) || *p == '-' )
70
sprintf(numbuf, "%%%02X", *p );
71
iobuf_writestr(a, numbuf );
75
else if( control == IOBUFCTRL_DESC )
76
*(char**)buf = "urlencode_filter";
83
int rc,begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
86
struct http_context hd;
88
IOBUF temp = iobuf_temp();
91
memset(&hd,0,sizeof(hd));
93
request=malloc(strlen(host)+strlen(port)+strlen(path)+100);
96
fprintf(console,"gpgkeys: out of memory\n");
97
return KEYSERVER_NO_MEMORY;
100
iobuf_push_filter(temp,urlencode_filter,NULL);
102
/* Read and throw away input until we see the BEGIN */
104
while(fgets(line,MAX_LINE,input)!=NULL)
105
if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1)
113
/* i.e. eof before the KEY BEGIN was found. This isn't an
120
/* Now slurp up everything until we see the END */
122
while(fgets(line,MAX_LINE,input))
123
if(sscanf(line,"KEY %16s END\n",keyid)==1)
129
if(iobuf_writestr(temp,line))
131
fprintf(console,"gpgkeys: internal iobuf error\n");
137
fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
139
ret=KEYSERVER_KEY_INCOMPLETE;
143
iobuf_flush_temp(temp);
145
sprintf(request,"hkp://%s%s%s%s/pks/add",
146
host,port[0]?":":"",port[0]?port:"",path);
149
fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
151
rc=http_open(&hd,HTTP_REQ_POST,request,NULL,http_flags,
152
proxy[0]?proxy:NULL);
155
fprintf(console,"gpgkeys: unable to connect to `%s'\n",host);
159
/* Some keyservers require this Content-Type (e.g. CryptoEx). */
160
iobuf_writestr(hd.fp_write,
161
"Content-Type: application/x-www-form-urlencoded\r\n");
163
sprintf(request,"Content-Length: %u\r\n",
164
(unsigned)iobuf_get_temp_length(temp)+9);
165
iobuf_writestr(hd.fp_write,request);
167
http_start_data(&hd);
169
iobuf_writestr(hd.fp_write,"keytext=");
170
iobuf_write(hd.fp_write,
171
iobuf_get_temp_buffer(temp),iobuf_get_temp_length(temp));
172
iobuf_put(hd.fp_write,'\n');
174
rc=http_wait_response(&hd,&status);
177
fprintf(console,"gpgkeys: error sending to `%s': %s\n",
178
host,g10_errstr(rc));
184
fprintf(console,"gpgkeys: remote server returned error %d\n",status);
188
fprintf(output,"KEY %s SENT\n",keyid);
198
fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
204
get_key(char *getkey)
209
struct http_context hd;
211
/* Build the search string. HKP only uses the short key IDs. */
213
if(strncmp(getkey,"0x",2)==0)
216
if(strlen(getkey)==32)
219
"gpgkeys: HKP keyservers do not support v3 fingerprints\n");
220
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
221
fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
222
return KEYSERVER_NOT_SUPPORTED;
227
char *offset=&getkey[strlen(getkey)-8];
229
/* fingerprint or long key id. Take the last 8 characters and
230
treat it like a short key id */
232
sprintf(search,"0x%.8s",offset);
238
sprintf(search,"0x%.8s",getkey);
241
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
243
request=malloc(strlen(host)+strlen(port)+strlen(path)+100);
246
fprintf(console,"gpgkeys: out of memory\n");
247
return KEYSERVER_NO_MEMORY;
250
sprintf(request,"hkp://%s%s%s%s/pks/lookup?op=get&options=mr&search=%s",
251
host,port[0]?":":"",port[0]?port:"",path,search);
254
fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
256
rc=http_open_document(&hd,request,NULL,http_flags,proxy[0]?proxy:NULL);
259
fprintf(console,"gpgkeys: HKP fetch error: %s\n",
260
rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
261
fprintf(output,"KEY 0x%s FAILED %d\n",getkey,
262
rc==G10ERR_NETWORK?KEYSERVER_UNREACHABLE:KEYSERVER_INTERNAL_ERROR);
266
unsigned int maxlen=1024,buflen;
269
while(iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen))
275
print_nocr(output,line);
276
if(strncmp(line,END,strlen(END))==0)
280
if(strncmp(line,BEGIN,strlen(BEGIN))==0)
282
print_nocr(output,line);
288
fprintf(output,"KEY 0x%s END\n",getkey);
291
fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
292
fprintf(output,"KEY 0x%s FAILED %d\n",
293
getkey,KEYSERVER_KEY_NOT_FOUND);
305
/* Remove anything <between brackets> and de-urlencode in place. Note
306
that this requires all brackets to be closed on the same line. It
307
also means that the result is never larger than the input. */
309
dehtmlize(char *line)
319
while(*line!='>' && *line!='\0')
327
if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='l') &&
328
(*(line+2)!='\0' && ascii_tolower(*(line+2))=='t') &&
329
(*(line+3)!='\0' && *(line+3)==';'))
331
parsed[parsedindex++]='<';
335
else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='g') &&
336
(*(line+2)!='\0' && ascii_tolower(*(line+2))=='t') &&
337
(*(line+3)!='\0' && *(line+3)==';'))
339
parsed[parsedindex++]='>';
343
else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='a') &&
344
(*(line+2)!='\0' && ascii_tolower(*(line+2))=='m') &&
345
(*(line+3)!='\0' && ascii_tolower(*(line+3))=='p') &&
346
(*(line+4)!='\0' && *(line+4)==';'))
348
parsed[parsedindex++]='&';
352
else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='q') &&
353
(*(line+2)!='\0' && ascii_tolower(*(line+2))=='u') &&
354
(*(line+3)!='\0' && ascii_tolower(*(line+3))=='o') &&
355
(*(line+4)!='\0' && ascii_tolower(*(line+4))=='t') &&
356
(*(line+5)!='\0' && *(line+5)==';'))
358
parsed[parsedindex++]='"';
364
parsed[parsedindex++]=*line;
370
parsed[parsedindex]='\0';
372
/* Chop off any trailing whitespace. Note that the HKP servers have
373
\r\n as line endings, and the NAI HKP servers have just \n. */
378
while(isspace(((unsigned char *)parsed)[parsedindex]))
380
parsed[parsedindex]='\0';
389
write_quoted(IOBUF a, const char *buf, char delim)
396
sprintf(quoted,"%%%02X",delim);
397
if(iobuf_writestr(a,quoted))
402
if(iobuf_writestr(a,"%25"))
407
if(iobuf_writebyte(a,*buf))
417
/* pub 2048/<a href="/pks/lookup?op=get&search=0x3CB3B415">3CB3B415</a> 1998/04/03 David M. Shaw <<a href="/pks/lookup?op=get&search=0x3CB3B415">dshaw@jabberwocky.com</a>> */
419
/* Luckily enough, both the HKP server and NAI HKP interface to their
420
LDAP server are close enough in output so the same function can
424
parse_hkp_index(IOBUF buffer,char *line)
428
/* printf("Open %d, LINE: `%s'\n",open,line); */
432
/* printf("Now open %d, LINE: `%s'\n",open,line); */
436
else if(ascii_strncasecmp(line,"pub",3)==0)
438
char *tok,*keyid,*uid=NULL,number[15];
439
int bits=0,type=0,disabled=0,revoked=0;
447
if(!include_disabled)
453
tok=strsep(&line,"/");
454
if(tok==NULL || strlen(tok)==0)
457
if(tok[strlen(tok)-1]=='R')
459
else if(tok[strlen(tok)-1]=='D')
464
keyid=strsep(&line," ");
466
tok=strsep(&line," ");
471
/* The date parser wants '-' instead of '/', so... */
480
createtime=scan_isodatestr(tok);
485
while(*line==' ' && *line!='\0')
490
if(strncmp(line,"*** KEY REVOKED ***",19)==0)
503
iobuf_writestr(buffer,"pub:");
505
write_quoted(buffer,keyid,':');
507
iobuf_writestr(buffer,":");
511
sprintf(number,"%d",type);
512
write_quoted(buffer,number,':');
515
iobuf_writestr(buffer,":");
519
sprintf(number,"%d",bits);
520
write_quoted(buffer,number,':');
523
iobuf_writestr(buffer,":");
527
sprintf(number,"%d",createtime);
528
write_quoted(buffer,number,':');
531
iobuf_writestr(buffer,"::");
534
write_quoted(buffer,"r",':');
537
write_quoted(buffer,"d",':');
541
iobuf_writestr(buffer,"\nuid:");
542
write_quoted(buffer,uid,':');
545
iobuf_writestr(buffer,"\n");
550
else if(ascii_strncasecmp(line," ",3)==0)
552
while(*line==' ' && *line!='\0')
557
iobuf_writestr(buffer,"uid:");
558
write_quoted(buffer,line,':');
559
iobuf_writestr(buffer,"\n");
566
/* Try and catch some bastardization of HKP. If we don't have
567
certain unchanging landmarks, we can't reliably parse the
568
response. This only complains about problems within the key
569
section itself. Headers and footers should not matter. */
571
fprintf(console,"gpgkeys: this keyserver does not support searching\n");
580
handle_old_hkp_index(IOBUF inp)
585
IOBUF buffer=iobuf_temp();
589
unsigned int maxlen=1024;
591
/* This is a judgement call. Is it better to slurp up all the
592
results before prompting the user? On the one hand, it
593
probably makes the keyserver happier to not be blocked on
594
sending for a long time while the user picks a key. On the
595
other hand, it might be nice for the server to be able to
596
stop sending before a large search result page is
599
rc=iobuf_read_line(inp,&line,&buflen,&maxlen);
601
ret=parse_hkp_index(buffer,line);
613
fprintf(output,"info:1:%d\n%s",count,iobuf_get_temp_buffer(buffer));
619
search_key(char *searchkey)
621
int max=0,len=0,ret=KEYSERVER_INTERNAL_ERROR,rc;
622
struct http_context hd;
623
char *search=NULL,*request=NULL;
624
unsigned char *skey=(unsigned char*) searchkey;
626
fprintf(output,"SEARCH %s BEGIN\n",searchkey);
628
/* Build the search string. It's going to need url-encoding. */
635
search=realloc(search,max+1); /* Note +1 for \0 */
638
fprintf(console,"gpgkeys: out of memory\n");
639
ret=KEYSERVER_NO_MEMORY;
644
if(isalnum(*skey) || *skey=='-')
650
sprintf(&search[len],"%%%02X",*skey);
659
fprintf(console,"gpgkeys: corrupt input?\n");
665
request=malloc(strlen(host)+strlen(port)+strlen(path)+100+strlen(search));
668
fprintf(console,"gpgkeys: out of memory\n");
669
ret=KEYSERVER_NO_MEMORY;
673
sprintf(request,"hkp://%s%s%s%s/pks/lookup?op=index&options=mr&search=%s",
674
host,port[0]?":":"",port[0]?port:"",path,search);
677
fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
679
rc=http_open_document(&hd,request,NULL,http_flags,proxy[0]?proxy:NULL);
682
fprintf(console,"gpgkeys: can't search keyserver `%s': %s\n",
683
host,rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
687
unsigned int maxlen=1024,buflen;
690
/* Is it a pksd that knows how to handle machine-readable
693
rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
695
handle_old_hkp_index(hd.fp_read);
699
fprintf(output,"%s",line);
701
rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
709
fprintf(output,"SEARCH %s END\n",searchkey);
719
if(ret!=KEYSERVER_OK)
720
fprintf(output,"SEARCH %s FAILED %d\n",searchkey,ret);
726
fail_all(struct keylist *keylist,int action,int err)
733
fprintf(output,"SEARCH ");
736
fprintf(output,"%s ",keylist->str);
737
keylist=keylist->next;
739
fprintf(output,"FAILED %d\n",err);
744
fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
745
keylist=keylist->next;
752
fprintf (fp,"-h\thelp\n");
753
fprintf (fp,"-V\tversion\n");
754
fprintf (fp,"-o\toutput to this file\n");
758
main(int argc,char *argv[])
760
int arg,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
763
struct keylist *keylist=NULL,*keyptr=NULL;
764
unsigned int timeout=DEFAULT_KEYSERVER_TIMEOUT;
769
/* Kludge to implement standard GNU options. */
770
if (argc > 1 && !strcmp (argv[1], "--version"))
772
fputs ("gpgkeys_hkp (GnuPG) " VERSION"\n", stdout);
775
else if (argc > 1 && !strcmp (argv[1], "--help"))
781
while((arg=getopt(argc,argv,"hVo:"))!=-1)
790
fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
794
output=fopen(optarg,"w");
797
fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
798
optarg,strerror(errno));
799
return KEYSERVER_INTERNAL_ERROR;
807
input=fopen(argv[optind],"r");
810
fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
811
argv[optind],strerror(errno));
812
return KEYSERVER_INTERNAL_ERROR;
822
/* Get the command and info block */
824
while(fgets(line,MAX_LINE,input)!=NULL)
827
char command[MAX_COMMAND+1];
828
char option[MAX_OPTION+1];
834
if(sscanf(line,"%c",&hash)==1 && hash=='#')
837
if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
839
command[MAX_COMMAND]='\0';
841
if(strcasecmp(command,"get")==0)
843
else if(strcasecmp(command,"send")==0)
845
else if(strcasecmp(command,"search")==0)
851
if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
857
if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
863
if(sscanf(line,"PATH %" MKSTRING(URLMAX_PATH) "s\n",path)==1)
865
path[URLMAX_PATH]='\0';
869
if(sscanf(line,"VERSION %d\n",&version)==1)
871
if(version!=KEYSERVER_PROTO_VERSION)
873
ret=KEYSERVER_VERSION_ERROR;
880
if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
883
char *start=&option[0];
885
option[MAX_OPTION]='\0';
887
if(strncasecmp(option,"no-",3)==0)
893
if(strcasecmp(start,"verbose")==0)
900
else if(strcasecmp(start,"include-revoked")==0)
907
else if(strcasecmp(start,"include-disabled")==0)
914
else if(strncasecmp(start,"http-proxy",10)==0)
918
else if(start[10]=='=')
920
strncpy(proxy,&start[11],MAX_PROXY);
921
proxy[MAX_PROXY]='\0';
923
else if(start[10]=='\0')
925
char *http_proxy=getenv(HTTP_PROXY_ENV);
928
strncpy(proxy,http_proxy,MAX_PROXY);
929
proxy[MAX_PROXY]='\0';
933
else if(strcasecmp(start,"broken-http-proxy")==0)
936
http_flags&=~HTTP_FLAG_NO_SHUTDOWN;
938
http_flags|=HTTP_FLAG_NO_SHUTDOWN;
940
else if(strcasecmp(start,"try-dns-srv")==0)
943
http_flags&=~HTTP_FLAG_TRY_SRV;
945
http_flags|=HTTP_FLAG_TRY_SRV;
947
else if(strncasecmp(start,"timeout",7)==0)
951
else if(start[7]=='=')
952
timeout=atoi(&start[8]);
953
else if(start[7]=='\0')
954
timeout=DEFAULT_KEYSERVER_TIMEOUT;
961
/* Avoid the double slash // in a path */
963
if(n>0 && path[n-1]=='/')
966
if(timeout && register_timeout()==-1)
968
fprintf(console,"gpgkeys: unable to register timeout handler\n");
969
return KEYSERVER_INTERNAL_ERROR;
972
/* By suggested convention, if the user gives a :port, then disable
975
http_flags&=~HTTP_FLAG_TRY_SRV;
977
/* If it's a GET or a SEARCH, the next thing to come in is the
978
keyids. If it's a SEND, then there are no keyids. */
981
while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
982
else if(action==GET || action==SEARCH)
986
struct keylist *work;
988
if(fgets(line,MAX_LINE,input)==NULL)
992
if(line[0]=='\n' || line[0]=='\0')
995
work=malloc(sizeof(struct keylist));
998
fprintf(console,"gpgkeys: out of memory while "
999
"building key list\n");
1000
ret=KEYSERVER_NO_MEMORY;
1004
strcpy(work->str,line);
1006
/* Trim the trailing \n */
1007
work->str[strlen(line)-1]='\0';
1011
/* Always attach at the end to keep the list in proper
1012
order for searching */
1024
fprintf(console,"gpgkeys: no keyserver command specified\n");
1028
/* Send the response */
1030
fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
1031
fprintf(output,"PROGRAM %s\n\n",VERSION);
1035
fprintf(console,"Host:\t\t%s\n",host);
1037
fprintf(console,"Port:\t\t%s\n",port);
1038
if(strcmp(path,"/")!=0)
1039
fprintf(console,"Path:\t\t%s\n",path);
1040
fprintf(console,"Command:\t%s\n",action==GET?"GET":
1041
action==SEND?"SEND":"SEARCH");
1047
vals=ldap_get_values(ldap,res,"software");
1050
fprintf(console,"Server: \t%s\n",vals[0]);
1051
ldap_value_free(vals);
1054
vals=ldap_get_values(ldap,res,"version");
1057
fprintf(console,"Version:\t%s\n",vals[0]);
1058
ldap_value_free(vals);
1070
set_timeout(timeout);
1072
if(get_key(keyptr->str)!=KEYSERVER_OK)
1075
keyptr=keyptr->next;
1085
set_timeout(timeout);
1087
if(send_key(&eof)!=KEYSERVER_OK)
1096
char *searchkey=NULL;
1099
set_timeout(timeout);
1101
/* To search, we stick a space in between each key to search
1107
len+=strlen(keyptr->str)+1;
1108
keyptr=keyptr->next;
1111
searchkey=malloc(len+1);
1114
ret=KEYSERVER_NO_MEMORY;
1115
fail_all(keylist,action,KEYSERVER_NO_MEMORY);
1124
strcat(searchkey,keyptr->str);
1125
strcat(searchkey," ");
1126
keyptr=keyptr->next;
1129
/* Nail that last space */
1131
searchkey[strlen(searchkey)-1]='\0';
1133
if(search_key(searchkey)!=KEYSERVER_OK)
1146
while(keylist!=NULL)
1148
struct keylist *current=keylist;
1149
keylist=keylist->next;