Issue 1447: Pass proper Host header and SNI when SRV is used with curl.
[gnupg.git] / keyserver / gpgkeys_hkp.c
1 /* gpgkeys_hkp.c - talk to an HKP keyserver
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3  *               2009, 2012 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
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.
11  *
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.
16  *
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/>.
19  *
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.
30  */
31
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 /* This #define rigamarole is to enable a hack to fake DNS SRV using
44    libcurl.  It only works if we have getaddrinfo(), inet_ntop(), and
45    a modern enough version of libcurl (7.21.3) so we can use
46    CURLOPT_RESOLVE to feed the resolver from the outside to force
47    libcurl to pass the right SNI. */
48 #if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_NTOP) && LIBCURL_VERNUM >= 0x071503
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <netdb.h>
52 #include <arpa/inet.h>
53 #else
54 #undef USE_DNS_SRV
55 #endif
56 #else
57 #include "curl-shim.h"
58 #endif
59 #include "util.h"
60 #ifdef USE_DNS_SRV
61 #include "srv.h"
62 #endif
63 #include "keyserver.h"
64 #include "ksutil.h"
65
66 extern char *optarg;
67 extern int optind;
68
69 static FILE *input,*output,*console;
70 static CURL *curl;
71 static struct ks_options *opt;
72 static char errorbuffer[CURL_ERROR_SIZE];
73 static char *proto,*port;
74
75 static size_t
76 curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
77 {
78   static int checked=0,swallow=0;
79
80   if(!checked)
81     {
82       /* If the document begins with a '<', assume it's a HTML
83          response, which we don't support.  Discard the whole message
84          body.  GPG can handle it, but this is an optimization to deal
85          with it on this side of the pipe.  */
86       const char *buf=ptr;
87       if(buf[0]=='<')
88         swallow=1;
89
90       checked=1;
91     }
92
93   if(swallow || fwrite(ptr,size,nmemb,stream)==nmemb)
94     return size*nmemb;
95   else
96     return 0;
97 }
98
99 /* Append but avoid creating a double slash // in the path. */
100 static char *
101 append_path(char *dest,const char *src)
102 {
103   size_t n=strlen(dest);
104
105   if(src[0]=='/' && n>0 && dest[n-1]=='/')
106     dest[n-1]='\0';
107
108   return strcat(dest,src);
109 }
110
111 /* Return a pointer into STRING so that appending PATH to STRING will
112    not yield a duplicated slash. */
113 static const char *
114 appendable_path (const char *string, const char *path)
115 {
116   size_t n;
117
118   if (path[0] == '/' && (n=strlen (string)) && string[n-1] == '/')
119     return path+1;
120   else
121     return path;
122 }
123
124
125 int
126 send_key(int *r_eof)
127 {
128   CURLcode res;
129   char request[MAX_URL+15];
130   int begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
131   char keyid[17],state[6];
132   char line[MAX_LINE];
133   char *key=NULL,*encoded_key=NULL;
134   size_t keylen=0,keymax=0;
135
136   /* Read and throw away input until we see the BEGIN */
137
138   while(fgets(line,MAX_LINE,input)!=NULL)
139     if(sscanf(line,"KEY%*[ ]%16s%*[ ]%5s\n",keyid,state)==2
140        && strcmp(state,"BEGIN")==0)
141       {
142         begin=1;
143         break;
144       }
145
146   if(!begin)
147     {
148       /* i.e. eof before the KEY BEGIN was found.  This isn't an
149          error. */
150       *r_eof=1;
151       ret=KEYSERVER_OK;
152       goto fail;
153     }
154
155   /* Now slurp up everything until we see the END */
156
157   while(fgets(line,MAX_LINE,input))
158     if(sscanf(line,"KEY%*[ ]%16s%*[ ]%3s\n",keyid,state)==2
159        && strcmp(state,"END")==0)
160       {
161         end=1;
162         break;
163       }
164     else
165       {
166         if(strlen(line)+keylen>keymax)
167           {
168             char *tmp;
169
170             keymax+=200;
171             tmp=realloc(key,keymax+1);
172             if(!tmp)
173               {
174                 free(key);
175                 fprintf(console,"gpgkeys: out of memory\n");
176                 ret=KEYSERVER_NO_MEMORY;
177                 goto fail;
178               }
179
180             key=tmp;
181           }
182
183         strcpy(&key[keylen],line);
184         keylen+=strlen(line);
185       }
186
187   if(!end)
188     {
189       fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
190       *r_eof=1;
191       ret=KEYSERVER_KEY_INCOMPLETE;
192       goto fail;
193     }
194
195   encoded_key=curl_escape(key,keylen);
196   if(!encoded_key)
197     {
198       fprintf(console,"gpgkeys: out of memory\n");
199       ret=KEYSERVER_NO_MEMORY;
200       goto fail;
201     }
202
203   free(key);
204
205   key = strconcat ("keytext=", encoded_key, NULL);
206   if(!key)
207     {
208       fprintf(console,"gpgkeys: out of memory\n");
209       ret=KEYSERVER_NO_MEMORY;
210       goto fail;
211     }
212
213   strcpy(request,proto);
214   strcat(request,"://");
215   strcat(request,opt->host);
216   strcat(request,":");
217   strcat(request,port);
218   strcat(request,opt->path);
219   /* request is MAX_URL+15 bytes long - MAX_URL covers the whole URL,
220      including any supplied path.  The 15 covers /pks/add. */
221   append_path(request,"/pks/add");
222
223   if(opt->verbose>2)
224     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
225
226   curl_easy_setopt(curl,CURLOPT_URL,request);
227   curl_easy_setopt(curl,CURLOPT_POST,1L);
228   curl_easy_setopt(curl,CURLOPT_POSTFIELDS,key);
229   curl_easy_setopt(curl,CURLOPT_FAILONERROR,1L);
230
231   res=curl_easy_perform(curl);
232   if(res!=0)
233     {
234       fprintf(console,"gpgkeys: HTTP post error %d: %s\n",res,errorbuffer);
235       ret=curl_err_to_gpg_err(res);
236       goto fail;
237     }
238   else
239     fprintf(output,"\nKEY %s SENT\n",keyid);
240
241   ret=KEYSERVER_OK;
242
243  fail:
244   xfree (key);
245   curl_free(encoded_key);
246
247   if(ret!=0 && begin)
248     fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
249
250   return ret;
251 }
252
253 static int
254 get_key(char *getkey)
255 {
256   CURLcode res;
257   char request[MAX_URL+92];
258   char *offset;
259   struct curl_writer_ctx ctx;
260   size_t keylen;
261
262   memset(&ctx,0,sizeof(ctx));
263
264   /* Build the search string.  HKP only uses the short key IDs. */
265
266   if(strncmp(getkey,"0x",2)==0)
267     getkey+=2;
268
269   fprintf(output,"KEY 0x%s BEGIN\n",getkey);
270
271   if(strlen(getkey)==32)
272     {
273       fprintf(console,
274               "gpgkeys: HKP keyservers do not support v3 fingerprints\n");
275       fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
276       return KEYSERVER_NOT_SUPPORTED;
277     }
278
279   strcpy(request,proto);
280   strcat(request,"://");
281   strcat(request,opt->host);
282   strcat(request,":");
283   strcat(request,port);
284   strcat(request,opt->path);
285   /* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
286      including any supplied path.  The 92 overcovers this /pks/... etc
287      string plus the 8, 16, or 40 bytes of key id/fingerprint */
288   append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
289
290   /* send only fingerprint, long key id, or short keyid.  see:
291      https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-3.1.1.1 */
292   keylen = strlen(getkey);
293   if(keylen >= 40)
294     offset=&getkey[keylen-40];
295   else if(keylen >= 16)
296     offset=&getkey[keylen-16];
297   else if(keylen >= 8)
298     offset=&getkey[keylen-8];
299   else
300     offset=getkey;
301
302   strcat(request,offset);
303
304   if(opt->verbose>2)
305     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
306
307   curl_easy_setopt(curl,CURLOPT_URL,request);
308   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
309   ctx.stream=output;
310   curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
311
312   res=curl_easy_perform(curl);
313   if(res!=CURLE_OK)
314     {
315       fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
316       fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res));
317     }
318   else
319     {
320       curl_writer_finalize(&ctx);
321       if(!ctx.flags.done)
322         {
323           fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
324           fprintf(output,"\nKEY 0x%s FAILED %d\n",
325                   getkey,KEYSERVER_KEY_NOT_FOUND);
326         }
327       else
328         fprintf(output,"\nKEY 0x%s END\n",getkey);
329     }
330
331   return KEYSERVER_OK;
332 }
333
334 static int
335 get_name(const char *getkey)
336 {
337   CURLcode res;
338   char *request=NULL;
339   char *searchkey_encoded;
340   int ret=KEYSERVER_INTERNAL_ERROR;
341   struct curl_writer_ctx ctx;
342
343   memset(&ctx,0,sizeof(ctx));
344
345   searchkey_encoded=curl_escape((char *)getkey,0);
346   if(!searchkey_encoded)
347     {
348       fprintf(console,"gpgkeys: out of memory\n");
349       ret=KEYSERVER_NO_MEMORY;
350       goto fail;
351     }
352
353   request = strconcat
354     (proto,
355      "://",
356      opt->host,
357      ":",
358      port,
359      opt->path,
360      appendable_path (opt->path,"/pks/lookup?op=get&options=mr&search="),
361      searchkey_encoded,
362      opt->action == KS_GETNAME? "&exact=on":"",
363      NULL);
364   if(!request)
365     {
366       fprintf(console,"gpgkeys: out of memory\n");
367       ret=KEYSERVER_NO_MEMORY;
368       goto fail;
369     }
370   
371   fprintf(output,"NAME %s BEGIN\n",getkey);
372
373   if(opt->verbose>2)
374     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
375
376   curl_easy_setopt(curl,CURLOPT_URL,request);
377   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
378   ctx.stream=output;
379   curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
380
381   res=curl_easy_perform(curl);
382   if(res!=CURLE_OK)
383     {
384       fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
385       ret=curl_err_to_gpg_err(res);
386     }
387   else
388     {
389       curl_writer_finalize(&ctx);
390       if(!ctx.flags.done)
391         {
392           fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
393           ret=KEYSERVER_KEY_NOT_FOUND;
394         }
395       else
396         {
397           fprintf(output,"\nNAME %s END\n",getkey);
398           ret=KEYSERVER_OK;
399         }
400     }
401
402  fail:
403   curl_free(searchkey_encoded);
404   xfree (request);
405
406   if(ret!=KEYSERVER_OK)
407     fprintf(output,"\nNAME %s FAILED %d\n",getkey,ret);
408
409   return ret;
410 }
411
412 static int
413 search_key(const char *searchkey)
414 {
415   CURLcode res;
416   char *request=NULL;
417   char *searchkey_encoded;
418   int ret=KEYSERVER_INTERNAL_ERROR;
419   enum ks_search_type search_type;
420   const char *hexprefix;
421
422   search_type=classify_ks_search(&searchkey);
423
424   if(opt->debug)
425     fprintf(console,"gpgkeys: search type is %d, and key is \"%s\"\n",
426             search_type,searchkey);
427
428   searchkey_encoded=curl_escape((char *)searchkey,0);
429   if(!searchkey_encoded)
430     {
431       fprintf(console,"gpgkeys: out of memory\n");
432       ret=KEYSERVER_NO_MEMORY;
433       goto fail;
434     }
435
436   /* HKP keyservers like the 0x to be present when searching by
437      keyid.  */
438   hexprefix = (search_type==KS_SEARCH_KEYID_SHORT
439                || search_type==KS_SEARCH_KEYID_LONG)? "0x":"";
440
441   request = strconcat
442     (proto,
443      "://",
444      opt->host,
445      ":",
446      port,
447      opt->path,
448      appendable_path (opt->path, "/pks/lookup?op=index&options=mr&search="),
449      hexprefix,
450      searchkey_encoded,
451      opt->action == KS_GETNAME? "&exact=on":"",
452      NULL);
453   if(!request)
454     {
455       fprintf(console,"gpgkeys: out of memory\n");
456       ret=KEYSERVER_NO_MEMORY;
457       goto fail;
458     }
459
460   fprintf(output,"SEARCH %s BEGIN\n",searchkey);
461
462   if(opt->verbose>2)
463     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
464
465   curl_easy_setopt(curl,CURLOPT_URL,request);
466   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
467   curl_easy_setopt(curl,CURLOPT_FILE,output);
468
469   res=curl_easy_perform(curl);
470   if(res!=0)
471     {
472       fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
473       ret=curl_err_to_gpg_err(res);
474     }
475   else
476     {
477       fprintf(output,"\nSEARCH %s END\n",searchkey);
478       ret=KEYSERVER_OK;
479     }
480
481  fail:
482   curl_free(searchkey_encoded);
483   xfree (request);
484
485   if(ret!=KEYSERVER_OK)
486     fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
487
488   return ret;
489 }
490
491 void
492 fail_all(struct keylist *keylist,int err)
493 {
494   if(!keylist)
495     return;
496
497   if(opt->action==KS_SEARCH)
498     {
499       fprintf(output,"SEARCH ");
500       while(keylist)
501         {
502           fprintf(output,"%s ",keylist->str);
503           keylist=keylist->next;
504         }
505       fprintf(output,"FAILED %d\n",err);
506     }
507   else
508     while(keylist)
509       {
510         fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
511         keylist=keylist->next;
512       }
513 }
514
515 #if defined(HAVE_LIBCURL) && defined(USE_DNS_SRV)
516 /* If there is a SRV record, take the highest ranked possibility.
517    This is a hack, as we don't proceed downwards if we can't
518    connect(), but only if we can't getaddinfo().  All this should
519    ideally be replaced by actual SRV support in libcurl someday! */
520
521 #define HOST_HEADER "Host:"
522
523 static void
524 srv_replace(const char *srvtag,
525             struct curl_slist **headers,struct curl_slist **resolve)
526 {
527   struct srventry *srvlist=NULL;
528   int srvcount, srvindex;
529   char *portstr;
530
531   if(!srvtag)
532     return;
533
534   portstr=malloc (MAX_PORT);
535   if(!portstr)
536     return;
537
538   if(1+strlen(srvtag)+6+strlen(opt->host)+1<=MAXDNAME)
539     {
540       char srvname[MAXDNAME];
541
542       strcpy(srvname,"_");
543       strcat(srvname,srvtag);
544       strcat(srvname,"._tcp.");
545       strcat(srvname,opt->host);
546       srvcount=getsrv(srvname,&srvlist);
547     }
548
549   for(srvindex=0 ; srvindex<srvcount && portstr ; srvindex++)
550     {
551       struct addrinfo hints, *res;
552
553       sprintf (portstr, "%hu", srvlist[srvindex].port);
554       memset (&hints, 0, sizeof (hints));
555       hints.ai_socktype = SOCK_STREAM;
556
557       if (getaddrinfo (srvlist[srvindex].target, portstr, &hints, &res) == 0)
558         {
559           /* Very safe */
560           char ipaddr[INET_ADDRSTRLEN+INET6_ADDRSTRLEN];
561
562           if((res->ai_family==AF_INET
563               && inet_ntop (res->ai_family,
564                             &((struct sockaddr_in *)res->ai_addr)->sin_addr,
565                             ipaddr,sizeof(ipaddr)))
566              || (res->ai_family==AF_INET6
567                  && inet_ntop (res->ai_family,
568                                &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
569                                ipaddr,sizeof(ipaddr))))
570             {
571               char *entry,*host;
572
573               entry=malloc (strlen(opt->host)+1
574                             +strlen(portstr)+1+strlen(ipaddr)+1);
575
576               host=malloc (strlen(HOST_HEADER)+1+strlen(opt->host)+1);
577
578               if(entry && host)
579                 {
580                   sprintf (entry, "%s:%s:%s", opt->host, portstr, ipaddr);
581                   sprintf (host, "%s %s", HOST_HEADER, opt->host);
582
583                   *resolve=curl_slist_append (*resolve,entry);
584                   *headers=curl_slist_append (*headers,host);
585
586                   if(*resolve && *headers)
587                     {
588                       if(curl_easy_setopt (curl,
589                                            CURLOPT_RESOLVE,*resolve)==CURLE_OK)
590                         {
591                           if(opt->debug)
592                             fprintf (console, "gpgkeys: Faking %s SRV from"
593                                      " %s to %s:%u\n",
594                                      srvtag, opt->host,
595                                      srvlist[srvindex].target,
596                                      srvlist[srvindex].port);
597
598                           free (opt->port);
599                           opt->port=portstr;
600                           portstr=NULL;
601                         }
602                     }
603                 }
604
605               free (entry);
606               free (host);
607             }
608
609           freeaddrinfo (res);
610         }
611       else
612         continue; /* Not found */
613     }
614
615   free (srvlist);
616   free (portstr);
617 }
618 #endif
619
620 static void 
621 show_help (FILE *fp)
622 {
623   fprintf (fp,"-h, --help\thelp\n");
624   fprintf (fp,"-V\t\tmachine readable version\n");
625   fprintf (fp,"--version\thuman readable version\n");
626   fprintf (fp,"-o\t\toutput to this file\n");
627 }
628
629 int
630 main(int argc,char *argv[])
631 {
632   int arg,ret=KEYSERVER_INTERNAL_ERROR,try_srv=1;
633   char line[MAX_LINE];
634   int failed=0;
635   struct keylist *keylist=NULL,*keyptr=NULL;
636   char *proxy=NULL;
637   struct curl_slist *headers=NULL,*resolve=NULL;
638
639   console=stderr;
640
641   /* Kludge to implement standard GNU options.  */
642   if (argc > 1 && !strcmp (argv[1], "--version"))
643     {
644       printf ("gpgkeys_hkp (GnuPG) %s\n", VERSION);
645       printf ("Uses: %s\n", curl_version());
646       return 0;
647     }
648   else if (argc > 1 && !strcmp (argv[1], "--help"))
649     {
650       show_help (stdout);
651       return 0;
652     }
653
654   while((arg=getopt(argc,argv,"hVo:"))!=-1)
655     switch(arg)
656       {
657       default:
658       case 'h':
659         show_help (console);
660         return KEYSERVER_OK;
661
662       case 'V':
663         fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
664         return KEYSERVER_OK;
665
666       case 'o':
667         output=fopen(optarg,"w");
668         if(output==NULL)
669           {
670             fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
671                     optarg,strerror(errno));
672             return KEYSERVER_INTERNAL_ERROR;
673           }
674
675         break;
676       }
677
678   if(argc>optind)
679     {
680       input=fopen(argv[optind],"r");
681       if(input==NULL)
682         {
683           fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
684                   argv[optind],strerror(errno));
685           return KEYSERVER_INTERNAL_ERROR;
686         }
687     }
688
689   if(input==NULL)
690     input=stdin;
691
692   if(output==NULL)
693     output=stdout;
694
695   opt=init_ks_options();
696   if(!opt)
697     return KEYSERVER_NO_MEMORY;
698
699   /* Get the command and info block */
700
701   while(fgets(line,MAX_LINE,input)!=NULL)
702     {
703       int err;
704       char option[MAX_OPTION+1];
705
706       if(line[0]=='\n')
707         break;
708
709       err=parse_ks_options(line,opt);
710       if(err>0)
711         {
712           ret=err;
713           goto fail;
714         }
715       else if(err==0)
716         continue;
717
718       if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
719         {
720           int no=0;
721           char *start=&option[0];
722
723           option[MAX_OPTION]='\0';
724
725           if(strncasecmp(option,"no-",3)==0)
726             {
727               no=1;
728               start=&option[3];
729             }
730
731           if(strncasecmp(start,"http-proxy",10)==0)
732             {
733               if(no)
734                 {
735                   free(proxy);
736                   proxy=strdup("");
737                 }
738               else if(start[10]=='=')
739                 {
740                   if(strlen(&start[11])<MAX_PROXY)
741                     {
742                       free(proxy);
743                       proxy=strdup(&start[11]);
744                     }
745                 }
746             }
747           else if(strcasecmp(start,"try-dns-srv")==0)
748             {
749               if(no)
750                 try_srv=0;
751               else
752                 try_srv=1;
753             }
754
755           continue;
756         }
757     }
758
759   if(!opt->scheme)
760     {
761       fprintf(console,"gpgkeys: no scheme supplied!\n");
762       ret=KEYSERVER_SCHEME_NOT_FOUND;
763       goto fail;
764     }
765
766   /* Defaults */
767   if(ks_strcasecmp(opt->scheme,"hkps")==0)
768     {
769       proto="https";
770       port="443";
771     }
772   else
773     {
774       proto="http";
775       port="11371";
776     }
777
778   if(!opt->host)
779     {
780       fprintf(console,"gpgkeys: no keyserver host provided\n");
781       goto fail;
782     }
783
784   if(opt->timeout && register_timeout()==-1)
785     {
786       fprintf(console,"gpgkeys: unable to register timeout handler\n");
787       return KEYSERVER_INTERNAL_ERROR;
788     }
789
790   curl_global_init(CURL_GLOBAL_DEFAULT);
791   curl=curl_easy_init();
792   if(!curl)
793     {
794       fprintf(console,"gpgkeys: unable to initialize curl\n");
795       ret=KEYSERVER_INTERNAL_ERROR;
796       goto fail;
797     }
798
799   if(opt->debug)
800     {
801       fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
802       curl_easy_setopt(curl,CURLOPT_STDERR,console);
803       curl_easy_setopt(curl,CURLOPT_VERBOSE,1L);
804     }
805
806   /* Only use SRV if the user does not provide a :port.  The semantics
807      of a specified port and SRV do not play well together. */
808   if(!opt->port && try_srv)
809     {
810       char *srvtag;
811
812       if(ks_strcasecmp(opt->scheme,"hkp")==0)
813         srvtag="pgpkey-http";
814       else if(ks_strcasecmp(opt->scheme,"hkps")==0)
815         srvtag="pgpkey-https";
816       else
817         srvtag=NULL;
818
819 #ifdef HAVE_LIBCURL
820       /* We're using libcurl, so fake SRV support via our wrapper.
821          This isn't as good as true SRV support, as we do not try all
822          possible targets at one particular level and work our way
823          down the list, but it's better than nothing. */      
824 #ifdef USE_DNS_SRV
825       srv_replace(srvtag,&headers,&resolve);
826 #else
827       fprintf(console,"gpgkeys: try-dns-srv was requested, but not SRV capable\n");
828 #endif
829 #else /* !HAVE_LIBCURL */
830       /* We're using our internal curl shim, so we can use its (true)
831          SRV support.  Obviously, CURLOPT_SRVTAG_GPG_HACK isn't a real
832          libcurl option.  It's specific to our shim. */
833       curl_easy_setopt(curl,CURLOPT_SRVTAG_GPG_HACK,srvtag);
834 #endif
835     }
836
837   /* If the user provided a port (or it came in via SRV, above),
838      replace the default. */
839   if(opt->port)
840     port=opt->port;
841
842   curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
843
844   if(opt->auth)
845     curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
846
847   curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert);
848   curl_easy_setopt(curl,CURLOPT_CAINFO,opt->ca_cert_file);
849
850   /* Avoid caches to get the most recent copy of the key.  This is bug
851      #1061.  In pre-curl versions of the code, we didn't do it.  Then
852      we did do it (as a curl default) until curl changed the default.
853      Now we're doing it again, but in such a way that changing
854      defaults in the future won't impact us.  We set both the Pragma
855      and Cache-Control versions of the header, so we're good with both
856      HTTP 1.0 and 1.1. */
857   headers=curl_slist_append(headers,"Pragma: no-cache");
858   if(headers)
859     headers=curl_slist_append(headers,"Cache-Control: no-cache");
860
861   if(!headers)
862     {
863       fprintf(console,"gpgkeys: out of memory when building HTTP headers\n");
864       ret=KEYSERVER_NO_MEMORY;
865       goto fail;
866     }
867
868   curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
869
870   if(proxy)
871     curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
872
873   /* If it's a GET or a SEARCH, the next thing to come in is the
874      keyids.  If it's a SEND, then there are no keyids. */
875
876   if(opt->action==KS_SEND)
877     while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
878   else if(opt->action==KS_GET
879           || opt->action==KS_GETNAME || opt->action==KS_SEARCH)
880     {
881       for(;;)
882         {
883           struct keylist *work;
884
885           if(fgets(line,MAX_LINE,input)==NULL)
886             break;
887           else
888             {
889               if(line[0]=='\n' || line[0]=='\0')
890                 break;
891
892               work=malloc(sizeof(struct keylist));
893               if(work==NULL)
894                 {
895                   fprintf(console,"gpgkeys: out of memory while "
896                           "building key list\n");
897                   ret=KEYSERVER_NO_MEMORY;
898                   goto fail;
899                 }
900
901               strcpy(work->str,line);
902
903               /* Trim the trailing \n */
904               work->str[strlen(line)-1]='\0';
905
906               work->next=NULL;
907
908               /* Always attach at the end to keep the list in proper
909                  order for searching */
910               if(keylist==NULL)
911                 keylist=work;
912               else
913                 keyptr->next=work;
914
915               keyptr=work;
916             }
917         }
918     }
919   else
920     {
921       fprintf(console,"gpgkeys: no keyserver command specified\n");
922       goto fail;
923     }
924
925   /* Send the response */
926
927   fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
928   fprintf(output,"PROGRAM %s\n\n",VERSION);
929
930   if(opt->verbose>1)
931     {
932       fprintf(console,"Host:\t\t%s\n",opt->host);
933       if(opt->port)
934         fprintf(console,"Port:\t\t%s\n",opt->port);
935       if(strcmp(opt->path,"/")!=0)
936         fprintf(console,"Path:\t\t%s\n",opt->path);
937       fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
938     }
939
940   if(opt->action==KS_GET)
941     {
942       keyptr=keylist;
943
944       while(keyptr!=NULL)
945         {
946           set_timeout(opt->timeout);
947
948           if(get_key(keyptr->str)!=KEYSERVER_OK)
949             failed++;
950
951           keyptr=keyptr->next;
952         }
953     }
954   else if(opt->action==KS_GETNAME)
955     {
956       keyptr=keylist;
957
958       while(keyptr!=NULL)
959         {
960           set_timeout(opt->timeout);
961
962           if(get_name(keyptr->str)!=KEYSERVER_OK)
963             failed++;
964
965           keyptr=keyptr->next;
966         }
967     }
968   else if(opt->action==KS_SEND)
969     {
970       int myeof=0;
971
972       do
973         {
974           set_timeout(opt->timeout);
975
976           if(send_key(&myeof)!=KEYSERVER_OK)
977             failed++;
978         }
979       while(!myeof);
980     }
981   else if(opt->action==KS_SEARCH)
982     {
983       char *searchkey=NULL;
984       int len=0;
985
986       set_timeout(opt->timeout);
987
988       /* To search, we stick a space in between each key to search
989          for. */
990
991       keyptr=keylist;
992       while(keyptr!=NULL)
993         {
994           len+=strlen(keyptr->str)+1;
995           keyptr=keyptr->next;
996         }
997
998       searchkey=malloc(len+1);
999       if(searchkey==NULL)
1000         {
1001           ret=KEYSERVER_NO_MEMORY;
1002           fail_all(keylist,KEYSERVER_NO_MEMORY);
1003           goto fail;
1004         }
1005
1006       searchkey[0]='\0';
1007
1008       keyptr=keylist;
1009       while(keyptr!=NULL)
1010         {
1011           strcat(searchkey,keyptr->str);
1012           strcat(searchkey," ");
1013           keyptr=keyptr->next;
1014         }
1015
1016       /* Nail that last space */
1017       if(*searchkey)
1018         searchkey[strlen(searchkey)-1]='\0';
1019
1020       if(search_key(searchkey)!=KEYSERVER_OK)
1021         failed++;
1022
1023       free(searchkey);
1024     }
1025   else
1026     abort();
1027
1028   if(!failed)
1029     ret=KEYSERVER_OK;
1030
1031  fail:
1032   while(keylist!=NULL)
1033     {
1034       struct keylist *current=keylist;
1035       keylist=keylist->next;
1036       free(current);
1037     }
1038
1039   if(input!=stdin)
1040     fclose(input);
1041
1042   if(output!=stdout)
1043     fclose(output);
1044
1045   free_ks_options(opt);
1046
1047   curl_slist_free_all(headers);
1048   curl_slist_free_all(resolve);
1049
1050   if(curl)
1051     curl_easy_cleanup(curl);
1052
1053   free(proxy);
1054
1055   return ret;
1056 }