* srv.c (getsrv): Raise maximum packet size to 2048, as PACKETSZ is
[gnupg.git] / keyserver / gpgkeys_hkp.c
blobef6fd7cb4fbb0c30be1205e39c6a0243fe0d79d0
1 /* gpgkeys_hkp.c - talk to an HKP keyserver
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 * 2009 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 * In addition, as a special exception, the Free Software Foundation
21 * gives permission to link the code of the keyserver helper tools:
22 * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL
23 * project's "OpenSSL" library (or with modified versions of it that
24 * use the same license as the "OpenSSL" library), and distribute the
25 * linked executables. You must obey the GNU General Public License
26 * in all respects for all of the code used other than "OpenSSL". If
27 * you modify this file, you may extend this exception to your version
28 * of the file, but you are not obligated to do so. If you do not
29 * wish to do so, delete this exception statement from your version.
32 #include <config.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #ifdef HAVE_GETOPT_H
39 #include <getopt.h>
40 #endif
41 #ifdef HAVE_LIBCURL
42 #include <curl/curl.h>
43 #else
44 #include "curl-shim.h"
45 #endif
46 #include "keyserver.h"
47 #include "ksutil.h"
49 extern char *optarg;
50 extern int optind;
52 static FILE *input,*output,*console;
53 static CURL *curl;
54 static struct ks_options *opt;
55 static char errorbuffer[CURL_ERROR_SIZE];
56 static char *proto,*port;
58 static size_t
59 curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
61 static int checked=0,swallow=0;
63 if(!checked)
65 /* If the document begins with a '<', assume it's a HTML
66 response, which we don't support. Discard the whole message
67 body. GPG can handle it, but this is an optimization to deal
68 with it on this side of the pipe. */
69 const char *buf=ptr;
70 if(buf[0]=='<')
71 swallow=1;
73 checked=1;
76 if(swallow || fwrite(ptr,size,nmemb,stream)==nmemb)
77 return size*nmemb;
78 else
79 return 0;
82 /* Append but avoid creating a double slash // in the path. */
83 static char *
84 append_path(char *dest,const char *src)
86 size_t n=strlen(dest);
88 if(src[0]=='/' && n>0 && dest[n-1]=='/')
89 dest[n-1]='\0';
91 return strcat(dest,src);
94 int
95 send_key(int *r_eof)
97 CURLcode res;
98 char request[MAX_URL+15];
99 int begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
100 char keyid[17],state[6];
101 char line[MAX_LINE];
102 char *key=NULL,*encoded_key=NULL;
103 size_t keylen=0,keymax=0;
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%*[ ]%5s\n",keyid,state)==2
109 && strcmp(state,"BEGIN")==0)
111 begin=1;
112 break;
115 if(!begin)
117 /* i.e. eof before the KEY BEGIN was found. This isn't an
118 error. */
119 *r_eof=1;
120 ret=KEYSERVER_OK;
121 goto fail;
124 /* Now slurp up everything until we see the END */
126 while(fgets(line,MAX_LINE,input))
127 if(sscanf(line,"KEY%*[ ]%16s%*[ ]%3s\n",keyid,state)==2
128 && strcmp(state,"END")==0)
130 end=1;
131 break;
133 else
135 if(strlen(line)+keylen>keymax)
137 char *tmp;
139 keymax+=200;
140 tmp=realloc(key,keymax+1);
141 if(!tmp)
143 free(key);
144 fprintf(console,"gpgkeys: out of memory\n");
145 ret=KEYSERVER_NO_MEMORY;
146 goto fail;
149 key=tmp;
152 strcpy(&key[keylen],line);
153 keylen+=strlen(line);
156 if(!end)
158 fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
159 *r_eof=1;
160 ret=KEYSERVER_KEY_INCOMPLETE;
161 goto fail;
164 encoded_key=curl_escape(key,keylen);
165 if(!encoded_key)
167 fprintf(console,"gpgkeys: out of memory\n");
168 ret=KEYSERVER_NO_MEMORY;
169 goto fail;
172 free(key);
174 key=malloc(8+strlen(encoded_key)+1);
175 if(!key)
177 fprintf(console,"gpgkeys: out of memory\n");
178 ret=KEYSERVER_NO_MEMORY;
179 goto fail;
182 strcpy(key,"keytext=");
183 strcat(key,encoded_key);
185 strcpy(request,proto);
186 strcat(request,opt->host);
187 strcat(request,":");
188 strcat(request,port);
189 strcat(request,opt->path);
190 /* request is MAX_URL+15 bytes long - MAX_URL covers the whole URL,
191 including any supplied path. The 15 covers /pks/add. */
192 append_path(request,"/pks/add");
194 if(opt->verbose>2)
195 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
197 curl_easy_setopt(curl,CURLOPT_URL,request);
198 curl_easy_setopt(curl,CURLOPT_POST,1L);
199 curl_easy_setopt(curl,CURLOPT_POSTFIELDS,key);
200 curl_easy_setopt(curl,CURLOPT_FAILONERROR,1L);
202 res=curl_easy_perform(curl);
203 if(res!=0)
205 fprintf(console,"gpgkeys: HTTP post error %d: %s\n",res,errorbuffer);
206 ret=curl_err_to_gpg_err(res);
207 goto fail;
209 else
210 fprintf(output,"\nKEY %s SENT\n",keyid);
212 ret=KEYSERVER_OK;
214 fail:
215 free(key);
216 curl_free(encoded_key);
218 if(ret!=0 && begin)
219 fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
221 return ret;
224 static int
225 get_key(char *getkey)
227 CURLcode res;
228 char request[MAX_URL+60];
229 char *offset;
230 struct curl_writer_ctx ctx;
232 memset(&ctx,0,sizeof(ctx));
234 /* Build the search string. HKP only uses the short key IDs. */
236 if(strncmp(getkey,"0x",2)==0)
237 getkey+=2;
239 fprintf(output,"KEY 0x%s BEGIN\n",getkey);
241 if(strlen(getkey)==32)
243 fprintf(console,
244 "gpgkeys: HKP keyservers do not support v3 fingerprints\n");
245 fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
246 return KEYSERVER_NOT_SUPPORTED;
249 strcpy(request,proto);
250 strcat(request,opt->host);
251 strcat(request,":");
252 strcat(request,port);
253 strcat(request,opt->path);
254 /* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
255 including any supplied path. The 60 overcovers this /pks/... etc
256 string plus the 8 bytes of key id */
257 append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
259 /* fingerprint or long key id. Take the last 8 characters and treat
260 it like a short key id */
261 if(strlen(getkey)>8)
262 offset=&getkey[strlen(getkey)-8];
263 else
264 offset=getkey;
266 strcat(request,offset);
268 if(opt->verbose>2)
269 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
271 curl_easy_setopt(curl,CURLOPT_URL,request);
272 curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
273 ctx.stream=output;
274 curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
276 res=curl_easy_perform(curl);
277 if(res!=CURLE_OK)
279 fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
280 fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res));
282 else
284 curl_writer_finalize(&ctx);
285 if(!ctx.flags.done)
287 fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
288 fprintf(output,"\nKEY 0x%s FAILED %d\n",
289 getkey,KEYSERVER_KEY_NOT_FOUND);
291 else
292 fprintf(output,"\nKEY 0x%s END\n",getkey);
295 return KEYSERVER_OK;
298 static int
299 get_name(const char *getkey)
301 CURLcode res;
302 char *request=NULL;
303 char *searchkey_encoded;
304 int ret=KEYSERVER_INTERNAL_ERROR;
305 struct curl_writer_ctx ctx;
307 memset(&ctx,0,sizeof(ctx));
309 searchkey_encoded=curl_escape((char *)getkey,0);
310 if(!searchkey_encoded)
312 fprintf(console,"gpgkeys: out of memory\n");
313 ret=KEYSERVER_NO_MEMORY;
314 goto fail;
317 request=malloc(MAX_URL+60+strlen(searchkey_encoded));
318 if(!request)
320 fprintf(console,"gpgkeys: out of memory\n");
321 ret=KEYSERVER_NO_MEMORY;
322 goto fail;
325 fprintf(output,"NAME %s BEGIN\n",getkey);
327 strcpy(request,proto);
328 strcat(request,opt->host);
329 strcat(request,":");
330 strcat(request,port);
331 strcat(request,opt->path);
332 append_path(request,"/pks/lookup?op=get&options=mr&search=");
333 strcat(request,searchkey_encoded);
335 if(opt->action==KS_GETNAME)
336 strcat(request,"&exact=on");
338 if(opt->verbose>2)
339 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
341 curl_easy_setopt(curl,CURLOPT_URL,request);
342 curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
343 ctx.stream=output;
344 curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
346 res=curl_easy_perform(curl);
347 if(res!=CURLE_OK)
349 fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
350 ret=curl_err_to_gpg_err(res);
352 else
354 curl_writer_finalize(&ctx);
355 if(!ctx.flags.done)
357 fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
358 ret=KEYSERVER_KEY_NOT_FOUND;
360 else
362 fprintf(output,"\nNAME %s END\n",getkey);
363 ret=KEYSERVER_OK;
367 fail:
368 curl_free(searchkey_encoded);
369 free(request);
371 if(ret!=KEYSERVER_OK)
372 fprintf(output,"\nNAME %s FAILED %d\n",getkey,ret);
374 return ret;
377 static int
378 search_key(const char *searchkey)
380 CURLcode res;
381 char *request=NULL;
382 char *searchkey_encoded;
383 int ret=KEYSERVER_INTERNAL_ERROR;
384 enum ks_search_type search_type;
386 search_type=classify_ks_search(&searchkey);
388 if(opt->debug)
389 fprintf(console,"gpgkeys: search type is %d, and key is \"%s\"\n",
390 search_type,searchkey);
392 searchkey_encoded=curl_escape((char *)searchkey,0);
393 if(!searchkey_encoded)
395 fprintf(console,"gpgkeys: out of memory\n");
396 ret=KEYSERVER_NO_MEMORY;
397 goto fail;
400 request=malloc(MAX_URL+60+strlen(searchkey_encoded));
401 if(!request)
403 fprintf(console,"gpgkeys: out of memory\n");
404 ret=KEYSERVER_NO_MEMORY;
405 goto fail;
408 fprintf(output,"SEARCH %s BEGIN\n",searchkey);
410 strcpy(request,proto);
411 strcat(request,opt->host);
412 strcat(request,":");
413 strcat(request,port);
414 strcat(request,opt->path);
415 append_path(request,"/pks/lookup?op=index&options=mr&search=");
417 /* HKP keyservers like the 0x to be present when searching by
418 keyid */
419 if(search_type==KS_SEARCH_KEYID_SHORT || search_type==KS_SEARCH_KEYID_LONG)
420 strcat(request,"0x");
422 strcat(request,searchkey_encoded);
424 if(search_type!=KS_SEARCH_SUBSTR)
425 strcat(request,"&exact=on");
427 if(opt->verbose>2)
428 fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
430 curl_easy_setopt(curl,CURLOPT_URL,request);
431 curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
432 curl_easy_setopt(curl,CURLOPT_FILE,output);
434 res=curl_easy_perform(curl);
435 if(res!=0)
437 fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
438 ret=curl_err_to_gpg_err(res);
440 else
442 fprintf(output,"\nSEARCH %s END\n",searchkey);
443 ret=KEYSERVER_OK;
446 fail:
448 curl_free(searchkey_encoded);
449 free(request);
451 if(ret!=KEYSERVER_OK)
452 fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
454 return ret;
457 void
458 fail_all(struct keylist *keylist,int err)
460 if(!keylist)
461 return;
463 if(opt->action==KS_SEARCH)
465 fprintf(output,"SEARCH ");
466 while(keylist)
468 fprintf(output,"%s ",keylist->str);
469 keylist=keylist->next;
471 fprintf(output,"FAILED %d\n",err);
473 else
474 while(keylist)
476 fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
477 keylist=keylist->next;
481 static void
482 show_help (FILE *fp)
484 fprintf (fp,"-h, --help\thelp\n");
485 fprintf (fp,"-V\t\tmachine readable version\n");
486 fprintf (fp,"--version\thuman readable version\n");
487 fprintf (fp,"-o\t\toutput to this file\n");
491 main(int argc,char *argv[])
493 int arg,ret=KEYSERVER_INTERNAL_ERROR;
494 char line[MAX_LINE];
495 int failed=0;
496 struct keylist *keylist=NULL,*keyptr=NULL;
497 char *proxy=NULL;
499 console=stderr;
501 /* Kludge to implement standard GNU options. */
502 if (argc > 1 && !strcmp (argv[1], "--version"))
504 printf ("gpgkeys_hkp (GnuPG) %s\n", VERSION);
505 printf ("Uses: %s\n", curl_version());
506 return 0;
508 else if (argc > 1 && !strcmp (argv[1], "--help"))
510 show_help (stdout);
511 return 0;
514 while((arg=getopt(argc,argv,"hVo:"))!=-1)
515 switch(arg)
517 default:
518 case 'h':
519 show_help (console);
520 return KEYSERVER_OK;
522 case 'V':
523 fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
524 return KEYSERVER_OK;
526 case 'o':
527 output=fopen(optarg,"w");
528 if(output==NULL)
530 fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
531 optarg,strerror(errno));
532 return KEYSERVER_INTERNAL_ERROR;
535 break;
538 if(argc>optind)
540 input=fopen(argv[optind],"r");
541 if(input==NULL)
543 fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
544 argv[optind],strerror(errno));
545 return KEYSERVER_INTERNAL_ERROR;
549 if(input==NULL)
550 input=stdin;
552 if(output==NULL)
553 output=stdout;
555 opt=init_ks_options();
556 if(!opt)
557 return KEYSERVER_NO_MEMORY;
559 /* Get the command and info block */
561 while(fgets(line,MAX_LINE,input)!=NULL)
563 int err;
564 char option[MAX_OPTION+1];
566 if(line[0]=='\n')
567 break;
569 err=parse_ks_options(line,opt);
570 if(err>0)
572 ret=err;
573 goto fail;
575 else if(err==0)
576 continue;
578 if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
580 int no=0;
581 char *start=&option[0];
583 option[MAX_OPTION]='\0';
585 if(strncasecmp(option,"no-",3)==0)
587 no=1;
588 start=&option[3];
591 if(strncasecmp(start,"http-proxy",10)==0)
593 if(no)
595 free(proxy);
596 proxy=strdup("");
598 else if(start[10]=='=')
600 if(strlen(&start[11])<MAX_PROXY)
602 free(proxy);
603 proxy=strdup(&start[11]);
607 #if 0
608 else if(strcasecmp(start,"try-dns-srv")==0)
610 if(no)
611 http_flags&=~HTTP_FLAG_TRY_SRV;
612 else
613 http_flags|=HTTP_FLAG_TRY_SRV;
615 #endif
616 continue;
620 if(!opt->scheme)
622 fprintf(console,"gpgkeys: no scheme supplied!\n");
623 ret=KEYSERVER_SCHEME_NOT_FOUND;
624 goto fail;
627 if(ks_strcasecmp(opt->scheme,"hkps")==0)
629 proto="https://";
630 port="443";
632 else
634 proto="http://";
635 port="11371";
638 if(opt->port)
639 port=opt->port;
641 if(!opt->host)
643 fprintf(console,"gpgkeys: no keyserver host provided\n");
644 goto fail;
647 if(opt->timeout && register_timeout()==-1)
649 fprintf(console,"gpgkeys: unable to register timeout handler\n");
650 return KEYSERVER_INTERNAL_ERROR;
653 curl_global_init(CURL_GLOBAL_DEFAULT);
654 curl=curl_easy_init();
655 if(!curl)
657 fprintf(console,"gpgkeys: unable to initialize curl\n");
658 ret=KEYSERVER_INTERNAL_ERROR;
659 goto fail;
662 curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
664 if(opt->auth)
665 curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
667 if(opt->debug)
669 fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
670 curl_easy_setopt(curl,CURLOPT_STDERR,console);
671 curl_easy_setopt(curl,CURLOPT_VERBOSE,1L);
674 curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert);
675 curl_easy_setopt(curl,CURLOPT_CAINFO,opt->ca_cert_file);
677 if(proxy)
678 curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
680 #if 0
681 /* By suggested convention, if the user gives a :port, then disable
682 SRV. */
683 if(opt->port)
684 http_flags&=~HTTP_FLAG_TRY_SRV;
685 #endif
687 /* If it's a GET or a SEARCH, the next thing to come in is the
688 keyids. If it's a SEND, then there are no keyids. */
690 if(opt->action==KS_SEND)
691 while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
692 else if(opt->action==KS_GET
693 || opt->action==KS_GETNAME || opt->action==KS_SEARCH)
695 for(;;)
697 struct keylist *work;
699 if(fgets(line,MAX_LINE,input)==NULL)
700 break;
701 else
703 if(line[0]=='\n' || line[0]=='\0')
704 break;
706 work=malloc(sizeof(struct keylist));
707 if(work==NULL)
709 fprintf(console,"gpgkeys: out of memory while "
710 "building key list\n");
711 ret=KEYSERVER_NO_MEMORY;
712 goto fail;
715 strcpy(work->str,line);
717 /* Trim the trailing \n */
718 work->str[strlen(line)-1]='\0';
720 work->next=NULL;
722 /* Always attach at the end to keep the list in proper
723 order for searching */
724 if(keylist==NULL)
725 keylist=work;
726 else
727 keyptr->next=work;
729 keyptr=work;
733 else
735 fprintf(console,"gpgkeys: no keyserver command specified\n");
736 goto fail;
739 /* Send the response */
741 fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
742 fprintf(output,"PROGRAM %s\n\n",VERSION);
744 if(opt->verbose>1)
746 fprintf(console,"Host:\t\t%s\n",opt->host);
747 if(opt->port)
748 fprintf(console,"Port:\t\t%s\n",opt->port);
749 if(strcmp(opt->path,"/")!=0)
750 fprintf(console,"Path:\t\t%s\n",opt->path);
751 fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
754 if(opt->action==KS_GET)
756 keyptr=keylist;
758 while(keyptr!=NULL)
760 set_timeout(opt->timeout);
762 if(get_key(keyptr->str)!=KEYSERVER_OK)
763 failed++;
765 keyptr=keyptr->next;
768 else if(opt->action==KS_GETNAME)
770 keyptr=keylist;
772 while(keyptr!=NULL)
774 set_timeout(opt->timeout);
776 if(get_name(keyptr->str)!=KEYSERVER_OK)
777 failed++;
779 keyptr=keyptr->next;
782 else if(opt->action==KS_SEND)
784 int myeof=0;
788 set_timeout(opt->timeout);
790 if(send_key(&myeof)!=KEYSERVER_OK)
791 failed++;
793 while(!myeof);
795 else if(opt->action==KS_SEARCH)
797 char *searchkey=NULL;
798 int len=0;
800 set_timeout(opt->timeout);
802 /* To search, we stick a space in between each key to search
803 for. */
805 keyptr=keylist;
806 while(keyptr!=NULL)
808 len+=strlen(keyptr->str)+1;
809 keyptr=keyptr->next;
812 searchkey=malloc(len+1);
813 if(searchkey==NULL)
815 ret=KEYSERVER_NO_MEMORY;
816 fail_all(keylist,KEYSERVER_NO_MEMORY);
817 goto fail;
820 searchkey[0]='\0';
822 keyptr=keylist;
823 while(keyptr!=NULL)
825 strcat(searchkey,keyptr->str);
826 strcat(searchkey," ");
827 keyptr=keyptr->next;
830 /* Nail that last space */
831 if(*searchkey)
832 searchkey[strlen(searchkey)-1]='\0';
834 if(search_key(searchkey)!=KEYSERVER_OK)
835 failed++;
837 free(searchkey);
839 else
840 abort();
842 if(!failed)
843 ret=KEYSERVER_OK;
845 fail:
846 while(keylist!=NULL)
848 struct keylist *current=keylist;
849 keylist=keylist->next;
850 free(current);
853 if(input!=stdin)
854 fclose(input);
856 if(output!=stdout)
857 fclose(output);
859 free_ks_options(opt);
861 if(curl)
862 curl_easy_cleanup(curl);
864 free(proxy);
866 return ret;