1 /* gpgkeys_hkp.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,
32 #include "curl-shim.h"
34 #include <curl/curl.h>
36 #include "keyserver.h"
42 static char proxy[MAX_PROXY+1];
43 static FILE *input,*output,*console;
45 static struct ks_options *opt;
46 static char errorbuffer[CURL_ERROR_SIZE];
49 curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
51 static int checked=0,swallow=0;
55 /* If the document begins with a '<', assume it's a HTML
56 response, which we don't support. Discard the whole message
57 body. GPG can handle it, but this is an optimization to deal
58 with it on this side of the pipe. */
66 if(swallow || fwrite(ptr,size,nmemb,stream)==nmemb)
72 /* Append but avoid creating a double slash // in the path. */
74 append_path(char *dest,const char *src)
76 size_t n=strlen(dest);
78 if(src[0]=='/' && n>0 && dest[n-1]=='/')
81 return strcat(dest,src);
88 char request[MAX_URL+15];
89 int begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
92 char *key,*encoded_key=NULL;
93 size_t keylen=8,keymax=8;
98 fprintf(console,"gpgkeys: out of memory\n");
99 ret=KEYSERVER_NO_MEMORY;
103 strcpy(key,"keytext=");
105 /* Read and throw away input until we see the BEGIN */
107 while(fgets(line,MAX_LINE,input)!=NULL)
108 if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1)
116 /* i.e. eof before the KEY BEGIN was found. This isn't an
123 /* Now slurp up everything until we see the END */
125 while(fgets(line,MAX_LINE,input))
126 if(sscanf(line,"KEY %16s END\n",keyid)==1)
133 if(strlen(line)+keylen>keymax)
138 tmp=realloc(key,keymax+1);
142 fprintf(console,"gpgkeys: out of memory\n");
143 ret=KEYSERVER_NO_MEMORY;
150 strcpy(&key[keylen],line);
151 keylen+=strlen(line);
156 fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
158 ret=KEYSERVER_KEY_INCOMPLETE;
162 encoded_key=curl_escape(key,keylen);
165 fprintf(console,"gpgkeys: out of memory\n");
166 ret=KEYSERVER_NO_MEMORY;
170 strcpy(request,"http://");
171 strcat(request,opt->host);
174 strcat(request,opt->port);
176 strcat(request,"11371");
177 strcat(request,opt->path);
178 /* request is MAX_URL+15 bytes long - MAX_URL covers the whole URL,
179 including any supplied path. The 15 covers /pks/add. */
180 append_path(request,"/pks/add");
183 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
185 curl_easy_setopt(curl,CURLOPT_URL,request);
186 curl_easy_setopt(curl,CURLOPT_POST,1);
187 curl_easy_setopt(curl,CURLOPT_POSTFIELDS,encoded_key);
188 curl_easy_setopt(curl,CURLOPT_FAILONERROR,1);
190 res=curl_easy_perform(curl);
193 fprintf(console,"gpgkeys: HTTP post error %d: %s\n",res,errorbuffer);
194 ret=curl_err_to_gpg_err(res);
197 fprintf(output,"\nKEY %s SENT\n",keyid);
203 curl_free(encoded_key);
206 fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
212 get_key(char *getkey)
215 char request[MAX_URL+60];
217 struct curl_writer_ctx ctx;
219 memset(&ctx,0,sizeof(ctx));
221 /* Build the search string. HKP only uses the short key IDs. */
223 if(strncmp(getkey,"0x",2)==0)
226 fprintf(output,"KEY 0x%s BEGIN\n",getkey);
228 if(strlen(getkey)==32)
231 "gpgkeys: HKP keyservers do not support v3 fingerprints\n");
232 fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
233 return KEYSERVER_NOT_SUPPORTED;
236 strcpy(request,"http://");
237 strcat(request,opt->host);
240 strcat(request,opt->port);
242 strcat(request,"11371");
243 strcat(request,opt->path);
244 /* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
245 including any supplied path. The 60 overcovers this /pks/... etc
246 string plus the 8 bytes of key id */
247 append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
249 /* fingerprint or long key id. Take the last 8 characters and treat
250 it like a short key id */
252 offset=&getkey[strlen(getkey)-8];
256 strcat(request,offset);
259 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
261 curl_easy_setopt(curl,CURLOPT_URL,request);
262 curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
264 curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
266 res=curl_easy_perform(curl);
269 fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
270 fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res));
275 fprintf(output,"\nKEY 0x%s END\n",getkey);
278 fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
279 fprintf(output,"KEY 0x%s FAILED %d\n",
280 getkey,KEYSERVER_KEY_NOT_FOUND);
288 search_key(char *searchkey)
292 char *searchkey_encoded;
293 int ret=KEYSERVER_INTERNAL_ERROR;
295 searchkey_encoded=curl_escape(searchkey,0);
297 request=malloc(MAX_URL+50+strlen(searchkey_encoded));
300 fprintf(console,"gpgkeys: out of memory\n");
301 ret=KEYSERVER_NO_MEMORY;
305 fprintf(output,"SEARCH %s BEGIN\n",searchkey);
307 strcpy(request,"http://");
308 strcat(request,opt->host);
311 strcat(request,opt->port);
313 strcat(request,"11371");
314 strcat(request,opt->path);
315 append_path(request,"/pks/lookup?op=index&options=mr&search=");
316 strcat(request,searchkey_encoded);
319 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
321 curl_easy_setopt(curl,CURLOPT_URL,request);
322 curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
323 curl_easy_setopt(curl,CURLOPT_FILE,output);
325 res=curl_easy_perform(curl);
328 fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
329 ret=curl_err_to_gpg_err(res);
333 fprintf(output,"\nSEARCH %s END\n",searchkey);
339 curl_free(searchkey_encoded);
342 if(ret!=KEYSERVER_OK)
343 fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
349 fail_all(struct keylist *keylist,int err)
354 if(opt->action==KS_SEARCH)
356 fprintf(output,"SEARCH ");
359 fprintf(output,"%s ",keylist->str);
360 keylist=keylist->next;
362 fprintf(output,"FAILED %d\n",err);
367 fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
368 keylist=keylist->next;
375 fprintf (fp,"-h\thelp\n");
376 fprintf (fp,"-V\tversion\n");
377 fprintf (fp,"-o\toutput to this file\n");
381 main(int argc,char *argv[])
383 int arg,ret=KEYSERVER_INTERNAL_ERROR;
386 struct keylist *keylist=NULL,*keyptr=NULL;
390 /* Kludge to implement standard GNU options. */
391 if (argc > 1 && !strcmp (argv[1], "--version"))
393 fputs ("gpgkeys_hkp (GnuPG) " VERSION"\n", stdout);
396 else if (argc > 1 && !strcmp (argv[1], "--help"))
402 while((arg=getopt(argc,argv,"hVo:"))!=-1)
411 fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
415 output=fopen(optarg,"w");
418 fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
419 optarg,strerror(errno));
420 return KEYSERVER_INTERNAL_ERROR;
428 input=fopen(argv[optind],"r");
431 fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
432 argv[optind],strerror(errno));
433 return KEYSERVER_INTERNAL_ERROR;
443 opt=init_ks_options();
445 return KEYSERVER_NO_MEMORY;
447 /* Get the command and info block */
449 while(fgets(line,MAX_LINE,input)!=NULL)
452 char option[MAX_OPTION+1];
457 err=parse_ks_options(line,opt);
466 if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
469 char *start=&option[0];
471 option[MAX_OPTION]='\0';
473 if(strncasecmp(option,"no-",3)==0)
479 if(strncasecmp(start,"http-proxy",10)==0)
483 else if(start[10]=='=')
485 strncpy(proxy,&start[11],MAX_PROXY);
486 proxy[MAX_PROXY]='\0';
488 else if(start[10]=='\0')
490 char *http_proxy=getenv(HTTP_PROXY_ENV);
493 strncpy(proxy,http_proxy,MAX_PROXY);
494 proxy[MAX_PROXY]='\0';
499 else if(strcasecmp(start,"try-dns-srv")==0)
502 http_flags&=~HTTP_FLAG_TRY_SRV;
504 http_flags|=HTTP_FLAG_TRY_SRV;
513 fprintf(console,"gpgkeys: no keyserver host provided\n");
517 if(opt->timeout && register_timeout()==-1)
519 fprintf(console,"gpgkeys: unable to register timeout handler\n");
520 return KEYSERVER_INTERNAL_ERROR;
523 curl_global_init(CURL_GLOBAL_DEFAULT);
524 curl=curl_easy_init();
527 fprintf(console,"gpgkeys: unable to initialize curl\n");
528 ret=KEYSERVER_INTERNAL_ERROR;
532 curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
536 curl_easy_setopt(curl,CURLOPT_STDERR,console);
537 curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
541 curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
544 /* By suggested convention, if the user gives a :port, then disable
547 http_flags&=~HTTP_FLAG_TRY_SRV;
550 /* If it's a GET or a SEARCH, the next thing to come in is the
551 keyids. If it's a SEND, then there are no keyids. */
553 if(opt->action==KS_SEND)
554 while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
555 else if(opt->action==KS_GET || opt->action==KS_SEARCH)
559 struct keylist *work;
561 if(fgets(line,MAX_LINE,input)==NULL)
565 if(line[0]=='\n' || line[0]=='\0')
568 work=malloc(sizeof(struct keylist));
571 fprintf(console,"gpgkeys: out of memory while "
572 "building key list\n");
573 ret=KEYSERVER_NO_MEMORY;
577 strcpy(work->str,line);
579 /* Trim the trailing \n */
580 work->str[strlen(line)-1]='\0';
584 /* Always attach at the end to keep the list in proper
585 order for searching */
597 fprintf(console,"gpgkeys: no keyserver command specified\n");
601 /* Send the response */
603 fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
604 fprintf(output,"PROGRAM %s\n\n",VERSION);
608 fprintf(console,"Host:\t\t%s\n",opt->host);
610 fprintf(console,"Port:\t\t%s\n",opt->port);
611 if(strcmp(opt->path,"/")!=0)
612 fprintf(console,"Path:\t\t%s\n",opt->path);
613 fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
616 if(opt->action==KS_GET)
622 set_timeout(opt->timeout);
624 if(get_key(keyptr->str)!=KEYSERVER_OK)
630 else if(opt->action==KS_SEND)
636 set_timeout(opt->timeout);
638 if(send_key(&eof)!=KEYSERVER_OK)
643 else if(opt->action==KS_SEARCH)
645 char *searchkey=NULL;
648 set_timeout(opt->timeout);
650 /* To search, we stick a space in between each key to search
656 len+=strlen(keyptr->str)+1;
660 searchkey=malloc(len+1);
663 ret=KEYSERVER_NO_MEMORY;
664 fail_all(keylist,KEYSERVER_NO_MEMORY);
673 strcat(searchkey,keyptr->str);
674 strcat(searchkey," ");
678 /* Nail that last space */
680 searchkey[strlen(searchkey)-1]='\0';
682 if(search_key(searchkey)!=KEYSERVER_OK)
696 struct keylist *current=keylist;
697 keylist=keylist->next;