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