16
16
* You should have received a copy of the GNU General Public License
17
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21
22
#include <config.h>
23
24
#include <string.h>
25
25
#include <stdlib.h>
27
27
#include <unistd.h>
28
28
#ifdef HAVE_GETOPT_H
29
29
#include <getopt.h>
31
#define INCLUDED_BY_MAIN_MODULE 1
32
#include "curl-shim.h"
34
#include <curl/curl.h>
34
36
#include "keyserver.h"
35
37
#include "ksutil.h"
37
39
extern char *optarg;
40
static int verbose=0,include_revoked=0,include_disabled=0;
41
static unsigned int http_flags=0;
42
static char host[MAX_HOST+1]={'\0'},proxy[MAX_PROXY+1]={'\0'},port[MAX_PORT+1]={'\0'};
43
static FILE *input=NULL,*output=NULL,*console=NULL;
46
#define HTTP_PROXY_ENV "GnuPG$HttpProxy"
48
#define HTTP_PROXY_ENV "http_proxy"
52
urlencode_filter( void *opaque, int control,
53
IOBUF a, byte *buf, size_t *ret_len)
42
static FILE *input,*output,*console;
44
static struct ks_options *opt;
45
static char errorbuffer[CURL_ERROR_SIZE];
48
curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
55
size_t size = *ret_len;
58
if( control == IOBUFCTRL_FLUSH ) {
60
for(p=buf; size; p++, size-- ) {
61
if( isalnum(*p) || *p == '-' )
67
sprintf(numbuf, "%%%02X", *p );
68
iobuf_writestr(a, numbuf );
50
static int checked=0,swallow=0;
54
/* If the document begins with a '<', assume it's a HTML
55
response, which we don't support. Discard the whole message
56
body. GPG can handle it, but this is an optimization to deal
57
with it on this side of the pipe. */
72
else if( control == IOBUFCTRL_DESC )
73
*(char**)buf = "urlencode_filter";
65
if(swallow || fwrite(ptr,size,nmemb,stream)==nmemb)
71
/* Append but avoid creating a double slash // in the path. */
73
append_path(char *dest,const char *src)
75
size_t n=strlen(dest);
77
if(src[0]=='/' && n>0 && dest[n-1]=='/')
80
return strcat(dest,src);
80
int rc,begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
87
char request[MAX_URL+15];
88
int begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
83
struct http_context hd;
85
IOBUF temp = iobuf_temp();
86
90
char line[MAX_LINE];
88
memset(&hd,0,sizeof(hd));
90
request=malloc(strlen(host)+100);
91
char *key,*encoded_key=NULL;
92
size_t keylen=8,keymax=8;
93
97
fprintf(console,"gpgkeys: out of memory\n");
94
return KEYSERVER_NO_MEMORY;
98
ret=KEYSERVER_NO_MEMORY;
97
iobuf_push_filter(temp,urlencode_filter,NULL);
102
strcpy(key,"keytext=");
99
104
/* Read and throw away input until we see the BEGIN */
140
iobuf_flush_temp(temp);
142
sprintf(request,"hkp://%s%s%s/pks/add",host,port[0]?":":"",port[0]?port:"");
161
encoded_key=curl_escape(key,keylen);
164
fprintf(console,"gpgkeys: out of memory\n");
165
ret=KEYSERVER_NO_MEMORY;
169
strcpy(request,"http://");
170
strcat(request,opt->host);
173
strcat(request,opt->port);
175
strcat(request,"11371");
176
strcat(request,opt->path);
177
/* request is MAX_URL+15 bytes long - MAX_URL covers the whole URL,
178
including any supplied path. The 15 covers /pks/add. */
179
append_path(request,"/pks/add");
145
182
fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
147
rc=http_open(&hd,HTTP_REQ_POST,request,http_flags,proxy[0]?proxy:NULL);
150
fprintf(console,"gpgkeys: unable to connect to `%s'\n",host);
154
/* Some keyservers require this Content-Type (e.g. CryptoEx). */
155
iobuf_writestr(hd.fp_write,
156
"Content-Type: application/x-www-form-urlencoded\r\n");
158
sprintf(request,"Content-Length: %u\r\n",
159
(unsigned)iobuf_get_temp_length(temp)+9);
160
iobuf_writestr(hd.fp_write,request);
162
http_start_data(&hd);
164
iobuf_writestr(hd.fp_write,"keytext=");
165
iobuf_write(hd.fp_write,
166
iobuf_get_temp_buffer(temp),iobuf_get_temp_length(temp));
167
iobuf_put(hd.fp_write,'\n');
169
rc=http_wait_response(&hd,&status);
172
fprintf(console,"gpgkeys: error sending to `%s': %s\n",
173
host,g10_errstr(rc));
179
fprintf(console,"gpgkeys: remote server returned error %d\n",status);
183
fprintf(output,"KEY %s SENT\n",keyid);
184
curl_easy_setopt(curl,CURLOPT_URL,request);
185
curl_easy_setopt(curl,CURLOPT_POST,1);
186
curl_easy_setopt(curl,CURLOPT_POSTFIELDS,encoded_key);
187
curl_easy_setopt(curl,CURLOPT_FAILONERROR,1);
189
res=curl_easy_perform(curl);
192
fprintf(console,"gpgkeys: HTTP post error %d: %s\n",res,errorbuffer);
193
ret=curl_err_to_gpg_err(res);
196
fprintf(output,"\nKEY %s SENT\n",keyid);
185
198
ret=KEYSERVER_OK;
202
curl_free(encoded_key);
192
204
if(ret!=0 && begin)
193
205
fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
199
211
get_key(char *getkey)
204
struct http_context hd;
214
char request[MAX_URL+60];
216
struct curl_writer_ctx ctx;
218
memset(&ctx,0,sizeof(ctx));
206
220
/* Build the search string. HKP only uses the short key IDs. */
208
222
if(strncmp(getkey,"0x",2)==0)
225
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
211
227
if(strlen(getkey)==32)
214
230
"gpgkeys: HKP keyservers do not support v3 fingerprints\n");
215
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
216
231
fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
217
232
return KEYSERVER_NOT_SUPPORTED;
222
char *offset=&getkey[strlen(getkey)-8];
224
/* fingerprint or long key id. Take the last 8 characters and
225
treat it like a short key id */
227
sprintf(search,"0x%.8s",offset);
233
sprintf(search,"0x%.8s",getkey);
236
fprintf(output,"KEY 0x%s BEGIN\n",getkey);
238
request=malloc(strlen(host)+100);
241
fprintf(console,"gpgkeys: out of memory\n");
242
return KEYSERVER_NO_MEMORY;
245
sprintf(request,"hkp://%s%s%s/pks/lookup?op=get&options=mr&search=%s",
246
host,port[0]?":":"",port[0]?port:"", search);
235
strcpy(request,"http://");
236
strcat(request,opt->host);
239
strcat(request,opt->port);
241
strcat(request,"11371");
242
strcat(request,opt->path);
243
/* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
244
including any supplied path. The 60 overcovers this /pks/... etc
245
string plus the 8 bytes of key id */
246
append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
248
/* fingerprint or long key id. Take the last 8 characters and treat
249
it like a short key id */
251
offset=&getkey[strlen(getkey)-8];
255
strcat(request,offset);
249
258
fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
251
rc=http_open_document(&hd,request,http_flags,proxy[0]?proxy:NULL);
260
curl_easy_setopt(curl,CURLOPT_URL,request);
261
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
263
curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
265
res=curl_easy_perform(curl);
254
fprintf(console,"gpgkeys: HKP fetch error: %s\n",
255
rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
256
fprintf(output,"KEY 0x%s FAILED %d\n",getkey,
257
rc==G10ERR_NETWORK?KEYSERVER_UNREACHABLE:KEYSERVER_INTERNAL_ERROR);
268
fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
269
fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res));
261
unsigned int maxlen=1024,buflen;
264
while(iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen))
270
fputs (line, output);
271
if(strncmp(line,END,strlen(END))==0)
275
if(strncmp(line,BEGIN,strlen(BEGIN))==0)
283
fprintf(output,"KEY 0x%s END\n",getkey);
274
fprintf(output,"\nKEY 0x%s END\n",getkey);
286
277
fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
287
278
fprintf(output,"KEY 0x%s FAILED %d\n",
288
279
getkey,KEYSERVER_KEY_NOT_FOUND);
297
283
return KEYSERVER_OK;
300
/* Remove anything <between brackets> and de-urlencode in place. Note
301
that this requires all brackets to be closed on the same line. It
302
also means that the result is never larger than the input. */
304
dehtmlize(char *line)
314
while(*line!='>' && *line!='\0')
322
if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='l') &&
323
(*(line+2)!='\0' && ascii_tolower(*(line+2))=='t') &&
324
(*(line+3)!='\0' && *(line+3)==';'))
326
parsed[parsedindex++]='<';
330
else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='g') &&
331
(*(line+2)!='\0' && ascii_tolower(*(line+2))=='t') &&
332
(*(line+3)!='\0' && *(line+3)==';'))
334
parsed[parsedindex++]='>';
338
else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='a') &&
339
(*(line+2)!='\0' && ascii_tolower(*(line+2))=='m') &&
340
(*(line+3)!='\0' && ascii_tolower(*(line+3))=='p') &&
341
(*(line+4)!='\0' && *(line+4)==';'))
343
parsed[parsedindex++]='&';
347
else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='q') &&
348
(*(line+2)!='\0' && ascii_tolower(*(line+2))=='u') &&
349
(*(line+3)!='\0' && ascii_tolower(*(line+3))=='o') &&
350
(*(line+4)!='\0' && ascii_tolower(*(line+4))=='t') &&
351
(*(line+5)!='\0' && *(line+5)==';'))
353
parsed[parsedindex++]='"';
359
parsed[parsedindex++]=*line;
365
parsed[parsedindex]='\0';
367
/* Chop off any trailing whitespace. Note that the HKP servers have
368
\r\n as line endings, and the NAI HKP servers have just \n. */
373
while(isspace(((unsigned char *)parsed)[parsedindex]))
375
parsed[parsedindex]='\0';
384
write_quoted(IOBUF a, const char *buf, char delim)
391
sprintf(quoted,"%%%02X",delim);
392
if(iobuf_writestr(a,quoted))
397
if(iobuf_writestr(a,"%25"))
402
if(iobuf_writebyte(a,*buf))
412
/* 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>> */
414
/* Luckily enough, both the HKP server and NAI HKP interface to their
415
LDAP server are close enough in output so the same function can
419
parse_hkp_index(IOBUF buffer,char *line)
423
/* printf("Open %d, LINE: `%s'\n",open,line); */
427
/* printf("Now open %d, LINE: `%s'\n",open,line); */
431
else if(ascii_strncasecmp(line,"pub",3)==0)
433
char *tok,*keyid,*uid=NULL,number[15];
434
int bits=0,type=0,disabled=0,revoked=0;
442
if(!include_disabled)
448
tok=strsep(&line,"/");
449
if(tok==NULL || strlen(tok)==0)
452
if(tok[strlen(tok)-1]=='R')
454
else if(tok[strlen(tok)-1]=='D')
459
keyid=strsep(&line," ");
461
tok=strsep(&line," ");
466
/* The date parser wants '-' instead of '/', so... */
475
createtime=scan_isodatestr(tok);
480
while(*line==' ' && *line!='\0')
485
if(strncmp(line,"*** KEY REVOKED ***",19)==0)
498
iobuf_writestr(buffer,"pub:");
500
write_quoted(buffer,keyid,':');
502
iobuf_writestr(buffer,":");
506
sprintf(number,"%d",type);
507
write_quoted(buffer,number,':');
510
iobuf_writestr(buffer,":");
514
sprintf(number,"%d",bits);
515
write_quoted(buffer,number,':');
518
iobuf_writestr(buffer,":");
522
sprintf(number,"%d",createtime);
523
write_quoted(buffer,number,':');
526
iobuf_writestr(buffer,"::");
529
write_quoted(buffer,"r",':');
532
write_quoted(buffer,"d",':');
536
iobuf_writestr(buffer,"\nuid:");
537
write_quoted(buffer,uid,':');
540
iobuf_writestr(buffer,"\n");
545
else if(ascii_strncasecmp(line," ",3)==0)
547
while(*line==' ' && *line!='\0')
552
iobuf_writestr(buffer,"uid:");
553
write_quoted(buffer,line,':');
554
iobuf_writestr(buffer,"\n");
561
/* Try and catch some bastardization of HKP. If we don't have
562
certain unchanging landmarks, we can't reliably parse the
563
response. This only complains about problems within the key
564
section itself. Headers and footers should not matter. */
566
fprintf(console,"gpgkeys: this keyserver does not support searching\n");
575
handle_old_hkp_index(IOBUF inp)
580
IOBUF buffer=iobuf_temp();
584
unsigned int maxlen=1024;
586
/* This is a judgement call. Is it better to slurp up all the
587
results before prompting the user? On the one hand, it
588
probably makes the keyserver happier to not be blocked on
589
sending for a long time while the user picks a key. On the
590
other hand, it might be nice for the server to be able to
591
stop sending before a large search result page is
594
rc=iobuf_read_line(inp,&line,&buflen,&maxlen);
596
ret=parse_hkp_index(buffer,line);
608
fprintf(output,"info:1:%d\n%s",count,iobuf_get_temp_buffer(buffer));
614
287
search_key(char *searchkey)
616
int max=0,len=0,ret=KEYSERVER_INTERNAL_ERROR,rc;
617
struct http_context hd;
618
char *search=NULL,*request=NULL;
619
unsigned char *skey=(unsigned char*) searchkey;
291
char *searchkey_encoded;
292
int ret=KEYSERVER_INTERNAL_ERROR;
294
searchkey_encoded=curl_escape(searchkey,0);
296
request=malloc(MAX_URL+50+strlen(searchkey_encoded));
299
fprintf(console,"gpgkeys: out of memory\n");
300
ret=KEYSERVER_NO_MEMORY;
621
304
fprintf(output,"SEARCH %s BEGIN\n",searchkey);
623
/* Build the search string. It's going to need url-encoding. */
630
search=realloc(search,max+1); /* Note +1 for \0 */
633
fprintf(console,"gpgkeys: out of memory\n");
634
ret=KEYSERVER_NO_MEMORY;
639
if(isalnum(*skey) || *skey=='-')
645
sprintf(&search[len],"%%%02X",*skey);
654
fprintf(console,"gpgkeys: corrupt input?\n");
660
request=malloc(strlen(host)+100+strlen(search));
663
fprintf(console,"gpgkeys: out of memory\n");
664
ret=KEYSERVER_NO_MEMORY;
668
sprintf(request,"hkp://%s%s%s/pks/lookup?op=index&options=mr&search=%s",
669
host,port[0]?":":"",port[0]?port:"",search);
306
strcpy(request,"http://");
307
strcat(request,opt->host);
310
strcat(request,opt->port);
312
strcat(request,"11371");
313
strcat(request,opt->path);
314
append_path(request,"/pks/lookup?op=index&options=mr&search=");
315
strcat(request,searchkey_encoded);
672
318
fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
674
rc=http_open_document(&hd,request,http_flags,proxy[0]?proxy:NULL);
320
curl_easy_setopt(curl,CURLOPT_URL,request);
321
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
322
curl_easy_setopt(curl,CURLOPT_FILE,output);
324
res=curl_easy_perform(curl);
677
fprintf(console,"gpgkeys: can't search keyserver `%s': %s\n",
678
host,rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
327
fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
328
ret=curl_err_to_gpg_err(res);
682
unsigned int maxlen=1024,buflen;
685
/* Is it a pksd that knows how to handle machine-readable
688
rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
690
handle_old_hkp_index(hd.fp_read);
694
fprintf(output,"%s",line);
696
rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
704
fprintf(output,"SEARCH %s END\n",searchkey);
332
fprintf(output,"\nSEARCH %s END\n",searchkey);
706
333
ret=KEYSERVER_OK;
338
curl_free(searchkey_encoded);
714
341
if(ret!=KEYSERVER_OK)
715
fprintf(output,"SEARCH %s FAILED %d\n",searchkey,ret);
342
fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
721
fail_all(struct keylist *keylist,int action,int err)
348
fail_all(struct keylist *keylist,int err)
353
if(opt->action==KS_SEARCH)
728
355
fprintf(output,"SEARCH ");