* gpgkeys_ldap.c (printquoted), curl-shim.c (curl_escape): Fix bad
[gnupg.git] / keyserver / gpgkeys_hkp.c
blobb3ebcf1a9859c13afaa87f01597c2b4c968aa01a
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,
19 * USA.
22 #include <config.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #ifdef HAVE_GETOPT_H
29 #include <getopt.h>
30 #endif
31 #ifdef HAVE_LIBCURL
32 #include <curl/curl.h>
33 #else
34 #include "curl-shim.h"
35 #endif
36 #include "keyserver.h"
37 #include "ksutil.h"
39 extern char *optarg;
40 extern int optind;
42 static FILE *input,*output,*console;
43 static CURL *curl;
44 static struct ks_options *opt;
45 static char errorbuffer[CURL_ERROR_SIZE];
47 static size_t
48 curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
50 static int checked=0,swallow=0;
52 if(!checked)
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. */
58 const char *buf=ptr;
59 if(buf[0]=='<')
60 swallow=1;
62 checked=1;
65 if(swallow || fwrite(ptr,size,nmemb,stream)==nmemb)
66 return size*nmemb;
67 else
68 return 0;
71 /* Append but avoid creating a double slash // in the path. */
72 static char *
73 append_path(char *dest,const char *src)
75 size_t n=strlen(dest);
77 if(src[0]=='/' && n>0 && dest[n-1]=='/')
78 dest[n-1]='\0';
80 return strcat(dest,src);
83 int
84 send_key(int *eof)
86 CURLcode res;
87 char request[MAX_URL+15];
88 int begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
89 char keyid[17];
90 char line[MAX_LINE];
91 char *key=NULL,*encoded_key=NULL;
92 size_t keylen=0,keymax=0;
94 /* Read and throw away input until we see the BEGIN */
96 while(fgets(line,MAX_LINE,input)!=NULL)
97 if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1)
99 begin=1;
100 break;
103 if(!begin)
105 /* i.e. eof before the KEY BEGIN was found. This isn't an
106 error. */
107 *eof=1;
108 ret=KEYSERVER_OK;
109 goto fail;
112 /* Now slurp up everything until we see the END */
114 while(fgets(line,MAX_LINE,input))
115 if(sscanf(line,"KEY %16s END\n",keyid)==1)
117 end=1;
118 break;
120 else
122 if(strlen(line)+keylen>keymax)
124 char *tmp;
126 keymax+=200;
127 tmp=realloc(key,keymax+1);
128 if(!tmp)
130 free(key);
131 fprintf(console,"gpgkeys: out of memory\n");
132 ret=KEYSERVER_NO_MEMORY;
133 goto fail;
136 key=tmp;
139 strcpy(&key[keylen],line);
140 keylen+=strlen(line);
143 if(!end)
145 fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
146 *eof=1;
147 ret=KEYSERVER_KEY_INCOMPLETE;
148 goto fail;
151 encoded_key=curl_escape(key,keylen);
152 if(!encoded_key)
154 fprintf(console,"gpgkeys: out of memory\n");
155 ret=KEYSERVER_NO_MEMORY;
156 goto fail;
159 free(key);
161 key=malloc(8+strlen(encoded_key)+1);
162 if(!key)
164 fprintf(console,"gpgkeys: out of memory\n");
165 ret=KEYSERVER_NO_MEMORY;
166 goto fail;
169 strcpy(key,"keytext=");
170 strcat(key,encoded_key);
172 strcpy(request,"http://");
173 strcat(request,opt->host);
174 strcat(request,":");
175 if(opt->port)
176 strcat(request,opt->port);
177 else
178 strcat(request,"11371");
179 strcat(request,opt->path);
180 /* request is MAX_URL+15 bytes long - MAX_URL covers the whole URL,
181 including any supplied path. The 15 covers /pks/add. */
182 append_path(request,"/pks/add");
184 if(opt->verbose>2)
185 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
187 curl_easy_setopt(curl,CURLOPT_URL,request);
188 curl_easy_setopt(curl,CURLOPT_POST,1);
189 curl_easy_setopt(curl,CURLOPT_POSTFIELDS,key);
190 curl_easy_setopt(curl,CURLOPT_FAILONERROR,1);
192 res=curl_easy_perform(curl);
193 if(res!=0)
195 fprintf(console,"gpgkeys: HTTP post error %d: %s\n",res,errorbuffer);
196 ret=curl_err_to_gpg_err(res);
198 else
199 fprintf(output,"\nKEY %s SENT\n",keyid);
201 ret=KEYSERVER_OK;
203 fail:
204 free(key);
205 curl_free(encoded_key);
207 if(ret!=0 && begin)
208 fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
210 return ret;
213 static int
214 get_key(char *getkey)
216 CURLcode res;
217 char request[MAX_URL+60];
218 char *offset;
219 struct curl_writer_ctx ctx;
221 memset(&ctx,0,sizeof(ctx));
223 /* Build the search string. HKP only uses the short key IDs. */
225 if(strncmp(getkey,"0x",2)==0)
226 getkey+=2;
228 fprintf(output,"KEY 0x%s BEGIN\n",getkey);
230 if(strlen(getkey)==32)
232 fprintf(console,
233 "gpgkeys: HKP keyservers do not support v3 fingerprints\n");
234 fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
235 return KEYSERVER_NOT_SUPPORTED;
238 strcpy(request,"http://");
239 strcat(request,opt->host);
240 strcat(request,":");
241 if(opt->port)
242 strcat(request,opt->port);
243 else
244 strcat(request,"11371");
245 strcat(request,opt->path);
246 /* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
247 including any supplied path. The 60 overcovers this /pks/... etc
248 string plus the 8 bytes of key id */
249 append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
251 /* fingerprint or long key id. Take the last 8 characters and treat
252 it like a short key id */
253 if(strlen(getkey)>8)
254 offset=&getkey[strlen(getkey)-8];
255 else
256 offset=getkey;
258 strcat(request,offset);
260 if(opt->verbose>2)
261 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
263 curl_easy_setopt(curl,CURLOPT_URL,request);
264 curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
265 ctx.stream=output;
266 curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
268 res=curl_easy_perform(curl);
269 if(res!=CURLE_OK)
271 fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
272 fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res));
274 else
276 curl_writer_finalize(&ctx);
277 if(!ctx.flags.done)
279 fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
280 fprintf(output,"\nKEY 0x%s FAILED %d\n",
281 getkey,KEYSERVER_KEY_NOT_FOUND);
283 else
284 fprintf(output,"\nKEY 0x%s END\n",getkey);
287 return KEYSERVER_OK;
290 static int
291 get_name(const char *getkey)
293 CURLcode res;
294 char *request=NULL;
295 char *searchkey_encoded;
296 int ret=KEYSERVER_INTERNAL_ERROR;
297 struct curl_writer_ctx ctx;
299 memset(&ctx,0,sizeof(ctx));
301 searchkey_encoded=curl_escape((char *)getkey,0);
302 if(!searchkey_encoded)
304 fprintf(console,"gpgkeys: out of memory\n");
305 ret=KEYSERVER_NO_MEMORY;
306 goto fail;
309 request=malloc(MAX_URL+60+strlen(searchkey_encoded));
310 if(!request)
312 fprintf(console,"gpgkeys: out of memory\n");
313 ret=KEYSERVER_NO_MEMORY;
314 goto fail;
317 fprintf(output,"NAME %s BEGIN\n",getkey);
319 strcpy(request,"http://");
320 strcat(request,opt->host);
321 strcat(request,":");
322 if(opt->port)
323 strcat(request,opt->port);
324 else
325 strcat(request,"11371");
326 strcat(request,opt->path);
327 append_path(request,"/pks/lookup?op=get&options=mr&search=");
328 strcat(request,searchkey_encoded);
330 if(opt->action==KS_GETNAME)
331 strcat(request,"&exact=on");
333 if(opt->verbose>2)
334 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
336 curl_easy_setopt(curl,CURLOPT_URL,request);
337 curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
338 ctx.stream=output;
339 curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
341 res=curl_easy_perform(curl);
342 if(res!=CURLE_OK)
344 fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
345 ret=curl_err_to_gpg_err(res);
347 else
349 curl_writer_finalize(&ctx);
350 if(!ctx.flags.done)
352 fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
353 ret=KEYSERVER_KEY_NOT_FOUND;
355 else
357 fprintf(output,"\nNAME %s END\n",getkey);
358 ret=KEYSERVER_OK;
362 fail:
363 curl_free(searchkey_encoded);
364 free(request);
366 if(ret!=KEYSERVER_OK)
367 fprintf(output,"\nNAME %s FAILED %d\n",getkey,ret);
369 return ret;
372 static int
373 search_key(const char *searchkey)
375 CURLcode res;
376 char *request=NULL;
377 char *searchkey_encoded;
378 int ret=KEYSERVER_INTERNAL_ERROR;
379 enum ks_search_type search_type;
381 search_type=classify_ks_search(&searchkey);
383 if(opt->debug)
384 fprintf(console,"gpgkeys: search type is %d, and key is \"%s\"\n",
385 search_type,searchkey);
387 searchkey_encoded=curl_escape((char *)searchkey,0);
388 if(!searchkey_encoded)
390 fprintf(console,"gpgkeys: out of memory\n");
391 ret=KEYSERVER_NO_MEMORY;
392 goto fail;
395 request=malloc(MAX_URL+60+strlen(searchkey_encoded));
396 if(!request)
398 fprintf(console,"gpgkeys: out of memory\n");
399 ret=KEYSERVER_NO_MEMORY;
400 goto fail;
403 fprintf(output,"SEARCH %s BEGIN\n",searchkey);
405 strcpy(request,"http://");
406 strcat(request,opt->host);
407 strcat(request,":");
408 if(opt->port)
409 strcat(request,opt->port);
410 else
411 strcat(request,"11371");
412 strcat(request,opt->path);
413 append_path(request,"/pks/lookup?op=index&options=mr&search=");
414 strcat(request,searchkey_encoded);
416 if(search_type!=KS_SEARCH_SUBSTR)
417 strcat(request,"&exact=on");
419 if(opt->verbose>2)
420 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
422 curl_easy_setopt(curl,CURLOPT_URL,request);
423 curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
424 curl_easy_setopt(curl,CURLOPT_FILE,output);
426 res=curl_easy_perform(curl);
427 if(res!=0)
429 fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
430 ret=curl_err_to_gpg_err(res);
432 else
434 fprintf(output,"\nSEARCH %s END\n",searchkey);
435 ret=KEYSERVER_OK;
438 fail:
440 curl_free(searchkey_encoded);
441 free(request);
443 if(ret!=KEYSERVER_OK)
444 fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
446 return ret;
449 void
450 fail_all(struct keylist *keylist,int err)
452 if(!keylist)
453 return;
455 if(opt->action==KS_SEARCH)
457 fprintf(output,"SEARCH ");
458 while(keylist)
460 fprintf(output,"%s ",keylist->str);
461 keylist=keylist->next;
463 fprintf(output,"FAILED %d\n",err);
465 else
466 while(keylist)
468 fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
469 keylist=keylist->next;
473 static void
474 show_help (FILE *fp)
476 fprintf (fp,"-h\thelp\n");
477 fprintf (fp,"-V\tversion\n");
478 fprintf (fp,"-o\toutput to this file\n");
482 main(int argc,char *argv[])
484 int arg,ret=KEYSERVER_INTERNAL_ERROR;
485 char line[MAX_LINE];
486 int failed=0;
487 struct keylist *keylist=NULL,*keyptr=NULL;
488 char *proxy=NULL;
490 console=stderr;
492 /* Kludge to implement standard GNU options. */
493 if (argc > 1 && !strcmp (argv[1], "--version"))
495 fputs ("gpgkeys_hkp (GnuPG) " VERSION"\n", stdout);
496 return 0;
498 else if (argc > 1 && !strcmp (argv[1], "--help"))
500 show_help (stdout);
501 return 0;
504 while((arg=getopt(argc,argv,"hVo:"))!=-1)
505 switch(arg)
507 default:
508 case 'h':
509 show_help (console);
510 return KEYSERVER_OK;
512 case 'V':
513 fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
514 return KEYSERVER_OK;
516 case 'o':
517 output=fopen(optarg,"w");
518 if(output==NULL)
520 fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
521 optarg,strerror(errno));
522 return KEYSERVER_INTERNAL_ERROR;
525 break;
528 if(argc>optind)
530 input=fopen(argv[optind],"r");
531 if(input==NULL)
533 fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
534 argv[optind],strerror(errno));
535 return KEYSERVER_INTERNAL_ERROR;
539 if(input==NULL)
540 input=stdin;
542 if(output==NULL)
543 output=stdout;
545 opt=init_ks_options();
546 if(!opt)
547 return KEYSERVER_NO_MEMORY;
549 /* Get the command and info block */
551 while(fgets(line,MAX_LINE,input)!=NULL)
553 int err;
554 char option[MAX_OPTION+1];
556 if(line[0]=='\n')
557 break;
559 err=parse_ks_options(line,opt);
560 if(err>0)
562 ret=err;
563 goto fail;
565 else if(err==0)
566 continue;
568 if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
570 int no=0;
571 char *start=&option[0];
573 option[MAX_OPTION]='\0';
575 if(strncasecmp(option,"no-",3)==0)
577 no=1;
578 start=&option[3];
581 if(strncasecmp(start,"http-proxy",10)==0)
583 if(no)
585 free(proxy);
586 proxy=strdup("");
588 else if(start[10]=='=')
590 if(strlen(&start[11])<MAX_PROXY)
592 free(proxy);
593 proxy=strdup(&start[11]);
597 #if 0
598 else if(strcasecmp(start,"try-dns-srv")==0)
600 if(no)
601 http_flags&=~HTTP_FLAG_TRY_SRV;
602 else
603 http_flags|=HTTP_FLAG_TRY_SRV;
605 #endif
606 continue;
610 if(!opt->host)
612 fprintf(console,"gpgkeys: no keyserver host provided\n");
613 goto fail;
616 if(opt->timeout && register_timeout()==-1)
618 fprintf(console,"gpgkeys: unable to register timeout handler\n");
619 return KEYSERVER_INTERNAL_ERROR;
622 curl_global_init(CURL_GLOBAL_DEFAULT);
623 curl=curl_easy_init();
624 if(!curl)
626 fprintf(console,"gpgkeys: unable to initialize curl\n");
627 ret=KEYSERVER_INTERNAL_ERROR;
628 goto fail;
631 curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
633 if(opt->auth)
634 curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
636 if(opt->debug)
638 fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
639 curl_easy_setopt(curl,CURLOPT_STDERR,console);
640 curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
643 if(proxy)
644 curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
646 #if 0
647 /* By suggested convention, if the user gives a :port, then disable
648 SRV. */
649 if(opt->port)
650 http_flags&=~HTTP_FLAG_TRY_SRV;
651 #endif
653 /* If it's a GET or a SEARCH, the next thing to come in is the
654 keyids. If it's a SEND, then there are no keyids. */
656 if(opt->action==KS_SEND)
657 while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
658 else if(opt->action==KS_GET
659 || opt->action==KS_GETNAME || opt->action==KS_SEARCH)
661 for(;;)
663 struct keylist *work;
665 if(fgets(line,MAX_LINE,input)==NULL)
666 break;
667 else
669 if(line[0]=='\n' || line[0]=='\0')
670 break;
672 work=malloc(sizeof(struct keylist));
673 if(work==NULL)
675 fprintf(console,"gpgkeys: out of memory while "
676 "building key list\n");
677 ret=KEYSERVER_NO_MEMORY;
678 goto fail;
681 strcpy(work->str,line);
683 /* Trim the trailing \n */
684 work->str[strlen(line)-1]='\0';
686 work->next=NULL;
688 /* Always attach at the end to keep the list in proper
689 order for searching */
690 if(keylist==NULL)
691 keylist=work;
692 else
693 keyptr->next=work;
695 keyptr=work;
699 else
701 fprintf(console,"gpgkeys: no keyserver command specified\n");
702 goto fail;
705 /* Send the response */
707 fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
708 fprintf(output,"PROGRAM %s\n\n",VERSION);
710 if(opt->verbose>1)
712 fprintf(console,"Host:\t\t%s\n",opt->host);
713 if(opt->port)
714 fprintf(console,"Port:\t\t%s\n",opt->port);
715 if(strcmp(opt->path,"/")!=0)
716 fprintf(console,"Path:\t\t%s\n",opt->path);
717 fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
720 if(opt->action==KS_GET)
722 keyptr=keylist;
724 while(keyptr!=NULL)
726 set_timeout(opt->timeout);
728 if(get_key(keyptr->str)!=KEYSERVER_OK)
729 failed++;
731 keyptr=keyptr->next;
734 else if(opt->action==KS_GETNAME)
736 keyptr=keylist;
738 while(keyptr!=NULL)
740 set_timeout(opt->timeout);
742 if(get_name(keyptr->str)!=KEYSERVER_OK)
743 failed++;
745 keyptr=keyptr->next;
748 else if(opt->action==KS_SEND)
750 int eof=0;
754 set_timeout(opt->timeout);
756 if(send_key(&eof)!=KEYSERVER_OK)
757 failed++;
759 while(!eof);
761 else if(opt->action==KS_SEARCH)
763 char *searchkey=NULL;
764 int len=0;
766 set_timeout(opt->timeout);
768 /* To search, we stick a space in between each key to search
769 for. */
771 keyptr=keylist;
772 while(keyptr!=NULL)
774 len+=strlen(keyptr->str)+1;
775 keyptr=keyptr->next;
778 searchkey=malloc(len+1);
779 if(searchkey==NULL)
781 ret=KEYSERVER_NO_MEMORY;
782 fail_all(keylist,KEYSERVER_NO_MEMORY);
783 goto fail;
786 searchkey[0]='\0';
788 keyptr=keylist;
789 while(keyptr!=NULL)
791 strcat(searchkey,keyptr->str);
792 strcat(searchkey," ");
793 keyptr=keyptr->next;
796 /* Nail that last space */
797 if(*searchkey)
798 searchkey[strlen(searchkey)-1]='\0';
800 if(search_key(searchkey)!=KEYSERVER_OK)
801 failed++;
803 free(searchkey);
805 else
806 abort();
808 if(!failed)
809 ret=KEYSERVER_OK;
811 fail:
812 while(keylist!=NULL)
814 struct keylist *current=keylist;
815 keylist=keylist->next;
816 free(current);
819 if(input!=stdin)
820 fclose(input);
822 if(output!=stdout)
823 fclose(output);
825 free_ks_options(opt);
827 if(curl)
828 curl_easy_cleanup(curl);
830 free(proxy);
832 return ret;