g10: Fix card-edit/fetch to use keyserver_fetch.
[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, 2013 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       long status = 0;
323
324       curl_writer_finalize(&ctx);
325
326       curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &status);
327
328       if (opt->verbose > 2)
329         fprintf (console, "gpgkeys: HTTP response code is %ld\n", status);
330
331       if (status == 200)
332         {
333           if (!ctx.flags.done)
334             {
335               if (ctx.flags.begun)
336                 {
337                   fprintf (console, "gpgkeys: key %s partially retrieved"
338                            " (probably corrupt)\n", getkey);
339                   fprintf (output, "\nKEY 0x%s FAILED %d\n",
340                            getkey, KEYSERVER_KEY_INCOMPLETE);
341                 }
342               else
343                 {
344                   fprintf (console, "gpgkeys: key %s can't be retrieved\n",
345                            getkey);
346                   fprintf (output, "\nKEY 0x%s FAILED %d\n",
347                            getkey, KEYSERVER_GENERAL_ERROR);
348                 }
349             }
350           else
351             fprintf (output, "\nKEY 0x%s END\n", getkey);
352         }
353       else if (status == 404)
354         {
355           fprintf (console, "gpgkeys: key %s not found on keyserver\n", getkey);
356           fprintf (output, "\nKEY 0x%s FAILED %d\n",
357                   getkey, KEYSERVER_KEY_NOT_FOUND);
358         }
359       else
360         {
361           fprintf (console, "gpgkeys: key %s can't be retrieved\n", getkey);
362           fprintf (output, "\nKEY 0x%s FAILED %d\n",
363                   getkey, KEYSERVER_GENERAL_ERROR);
364         }
365     }
366
367   return KEYSERVER_OK;
368 }
369
370 static int
371 get_name(const char *getkey)
372 {
373   CURLcode res;
374   char *request=NULL;
375   char *searchkey_encoded;
376   int ret=KEYSERVER_INTERNAL_ERROR;
377   struct curl_writer_ctx ctx;
378
379   memset(&ctx,0,sizeof(ctx));
380
381   searchkey_encoded=curl_escape((char *)getkey,0);
382   if(!searchkey_encoded)
383     {
384       fprintf(console,"gpgkeys: out of memory\n");
385       ret=KEYSERVER_NO_MEMORY;
386       goto fail;
387     }
388
389   request = strconcat
390     (proto,
391      "://",
392      opt->host,
393      ":",
394      port,
395      opt->path,
396      appendable_path (opt->path,"/pks/lookup?op=get&options=mr&search="),
397      searchkey_encoded,
398      opt->action == KS_GETNAME? "&exact=on":"",
399      NULL);
400   if(!request)
401     {
402       fprintf(console,"gpgkeys: out of memory\n");
403       ret=KEYSERVER_NO_MEMORY;
404       goto fail;
405     }
406
407   fprintf(output,"NAME %s BEGIN\n",getkey);
408
409   if(opt->verbose>2)
410     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
411
412   curl_easy_setopt(curl,CURLOPT_URL,request);
413   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
414   ctx.stream=output;
415   curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
416
417   res=curl_easy_perform(curl);
418   if(res!=CURLE_OK)
419     {
420       fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
421       ret=curl_err_to_gpg_err(res);
422     }
423   else
424     {
425       long status = 0;
426
427       curl_writer_finalize(&ctx);
428
429       curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &status);
430
431       if (opt->verbose > 2)
432         fprintf (console, "gpgkeys: HTTP response code is %ld\n", status);
433
434       if (status == 200)
435         {
436           if (!ctx.flags.done)
437             {
438               if (ctx.flags.begun)
439                 {
440                   fprintf (console, "gpgkeys: key %s partially retrieved"
441                            " (probably corrupt)\n", getkey);
442                   ret = KEYSERVER_KEY_INCOMPLETE;
443                 }
444               else
445                 {
446                   fprintf (console, "gpgkeys: key %s can't be retrieved\n",
447                            getkey);
448                   ret = KEYSERVER_GENERAL_ERROR;
449                 }
450             }
451           else
452             {
453               fprintf (output, "\nNAME %s END\n", getkey);
454               ret = KEYSERVER_OK;
455             }
456         }
457       else if (status == 404)
458         {
459           fprintf (console, "gpgkeys: key %s not found on keyserver\n", getkey);
460           ret = KEYSERVER_KEY_NOT_FOUND;
461         }
462       else
463         {
464           fprintf (console, "gpgkeys: key %s can't be retrieved\n", getkey);
465           ret = KEYSERVER_GENERAL_ERROR;
466         }
467     }
468
469  fail:
470   curl_free(searchkey_encoded);
471   xfree (request);
472
473   if(ret!=KEYSERVER_OK)
474     fprintf(output,"\nNAME %s FAILED %d\n",getkey,ret);
475
476   return ret;
477 }
478
479 static int
480 search_key(const char *searchkey)
481 {
482   CURLcode res;
483   char *request=NULL;
484   char *searchkey_encoded;
485   int ret=KEYSERVER_INTERNAL_ERROR;
486   enum ks_search_type search_type;
487   const char *hexprefix;
488
489   search_type=classify_ks_search(&searchkey);
490
491   if(opt->debug)
492     fprintf(console,"gpgkeys: search type is %d, and key is \"%s\"\n",
493             search_type,searchkey);
494
495   searchkey_encoded=curl_escape((char *)searchkey,0);
496   if(!searchkey_encoded)
497     {
498       fprintf(console,"gpgkeys: out of memory\n");
499       ret=KEYSERVER_NO_MEMORY;
500       goto fail;
501     }
502
503   /* HKP keyservers like the 0x to be present when searching by
504      keyid.  */
505   hexprefix = (search_type==KS_SEARCH_KEYID_SHORT
506                || search_type==KS_SEARCH_KEYID_LONG)? "0x":"";
507
508   request = strconcat
509     (proto,
510      "://",
511      opt->host,
512      ":",
513      port,
514      opt->path,
515      appendable_path (opt->path, "/pks/lookup?op=index&options=mr&search="),
516      hexprefix,
517      searchkey_encoded,
518      opt->action == KS_GETNAME? "&exact=on":"",
519      NULL);
520   if(!request)
521     {
522       fprintf(console,"gpgkeys: out of memory\n");
523       ret=KEYSERVER_NO_MEMORY;
524       goto fail;
525     }
526
527   fprintf(output,"SEARCH %s BEGIN\n",searchkey);
528
529   if(opt->verbose>2)
530     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
531
532   curl_easy_setopt(curl,CURLOPT_URL,request);
533   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
534   curl_easy_setopt(curl,CURLOPT_FILE,output);
535
536   res=curl_easy_perform(curl);
537   if(res!=0)
538     {
539       fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
540       ret=curl_err_to_gpg_err(res);
541     }
542   else
543     {
544       fprintf(output,"\nSEARCH %s END\n",searchkey);
545       ret=KEYSERVER_OK;
546     }
547
548  fail:
549   curl_free(searchkey_encoded);
550   xfree (request);
551
552   if(ret!=KEYSERVER_OK)
553     fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
554
555   return ret;
556 }
557
558 void
559 fail_all(struct keylist *keylist,int err)
560 {
561   if(!keylist)
562     return;
563
564   if(opt->action==KS_SEARCH)
565     {
566       fprintf(output,"SEARCH ");
567       while(keylist)
568         {
569           fprintf(output,"%s ",keylist->str);
570           keylist=keylist->next;
571         }
572       fprintf(output,"FAILED %d\n",err);
573     }
574   else
575     while(keylist)
576       {
577         fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
578         keylist=keylist->next;
579       }
580 }
581
582 #if defined(HAVE_LIBCURL) && defined(USE_DNS_SRV)
583 /* If there is a SRV record, take the highest ranked possibility.
584    This is a hack, as we don't proceed downwards if we can't
585    connect(), but only if we can't getaddinfo().  All this should
586    ideally be replaced by actual SRV support in libcurl someday! */
587
588 #define HOST_HEADER "Host:"
589
590 static void
591 srv_replace(const char *srvtag,
592             struct curl_slist **headers,struct curl_slist **resolve)
593 {
594   struct srventry *srvlist=NULL;
595   int srvcount, srvindex;
596   char *portstr;
597
598   if(!srvtag)
599     return;
600
601   portstr=malloc (MAX_PORT);
602   if(!portstr)
603     return;
604
605   if(1+strlen(srvtag)+6+strlen(opt->host)+1<=MAXDNAME)
606     {
607       char srvname[MAXDNAME];
608
609       strcpy(srvname,"_");
610       strcat(srvname,srvtag);
611       strcat(srvname,"._tcp.");
612       strcat(srvname,opt->host);
613       srvcount=getsrv(srvname,&srvlist);
614     }
615   else
616     srvcount = 0;
617
618   for(srvindex=0 ; srvindex<srvcount && portstr ; srvindex++)
619     {
620       struct addrinfo hints, *res;
621
622       sprintf (portstr, "%hu", srvlist[srvindex].port);
623       memset (&hints, 0, sizeof (hints));
624       hints.ai_socktype = SOCK_STREAM;
625
626       if (getaddrinfo (srvlist[srvindex].target, portstr, &hints, &res) == 0)
627         {
628           /* Very safe */
629           char ipaddr[INET_ADDRSTRLEN+INET6_ADDRSTRLEN];
630
631           if((res->ai_family==AF_INET
632               && inet_ntop (res->ai_family,
633                             &((struct sockaddr_in *)res->ai_addr)->sin_addr,
634                             ipaddr,sizeof(ipaddr)))
635              || (res->ai_family==AF_INET6
636                  && inet_ntop (res->ai_family,
637                                &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
638                                ipaddr,sizeof(ipaddr))))
639             {
640               char *entry,*host;
641
642               entry=malloc (strlen(opt->host)+1
643                             +strlen(portstr)+1+strlen(ipaddr)+1);
644
645               host=malloc (strlen(HOST_HEADER)+1+strlen(opt->host)+1);
646
647               if(entry && host)
648                 {
649                   sprintf (entry, "%s:%s:%s", opt->host, portstr, ipaddr);
650                   sprintf (host, "%s %s", HOST_HEADER, opt->host);
651
652                   *resolve=curl_slist_append (*resolve,entry);
653                   *headers=curl_slist_append (*headers,host);
654
655                   if(*resolve && *headers)
656                     {
657                       if(curl_easy_setopt (curl,
658                                            CURLOPT_RESOLVE,*resolve)==CURLE_OK)
659                         {
660                           if(opt->debug)
661                             fprintf (console, "gpgkeys: Faking %s SRV from"
662                                      " %s to %s:%u\n",
663                                      srvtag, opt->host,
664                                      srvlist[srvindex].target,
665                                      srvlist[srvindex].port);
666
667                           free (opt->port);
668                           opt->port=portstr;
669                           portstr=NULL;
670                         }
671                     }
672                 }
673
674               free (entry);
675               free (host);
676             }
677
678           freeaddrinfo (res);
679         }
680       else
681         continue; /* Not found */
682     }
683
684   free (srvlist);
685   free (portstr);
686 }
687 #endif
688
689 static void
690 show_help (FILE *fp)
691 {
692   fprintf (fp,"-h, --help\thelp\n");
693   fprintf (fp,"-V\t\tmachine readable version\n");
694   fprintf (fp,"--version\thuman readable version\n");
695   fprintf (fp,"-o\t\toutput to this file\n");
696 }
697
698 int
699 main(int argc,char *argv[])
700 {
701   int arg,ret=KEYSERVER_INTERNAL_ERROR;
702   char line[MAX_LINE];
703   int failed=0;
704   struct keylist *keylist=NULL,*keyptr=NULL;
705   char *proxy=NULL;
706   struct curl_slist *headers=NULL,*resolve=NULL;
707
708   /* Only default this to on if we have SRV support */
709 #ifdef USE_DNS_SRV
710   int try_srv = 1;
711 #else
712   int try_srv = 0;
713 #endif
714
715   console=stderr;
716
717   /* Kludge to implement standard GNU options.  */
718   if (argc > 1 && !strcmp (argv[1], "--version"))
719     {
720       printf ("gpgkeys_hkp (GnuPG) %s\n", VERSION);
721       printf ("Uses: %s\n", curl_version());
722       return 0;
723     }
724   else if (argc > 1 && !strcmp (argv[1], "--help"))
725     {
726       show_help (stdout);
727       return 0;
728     }
729
730   while((arg=getopt(argc,argv,"hVo:"))!=-1)
731     switch(arg)
732       {
733       default:
734       case 'h':
735         show_help (console);
736         return KEYSERVER_OK;
737
738       case 'V':
739         fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
740         return KEYSERVER_OK;
741
742       case 'o':
743         output=fopen(optarg,"w");
744         if(output==NULL)
745           {
746             fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
747                     optarg,strerror(errno));
748             return KEYSERVER_INTERNAL_ERROR;
749           }
750
751         break;
752       }
753
754   if(argc>optind)
755     {
756       input=fopen(argv[optind],"r");
757       if(input==NULL)
758         {
759           fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
760                   argv[optind],strerror(errno));
761           return KEYSERVER_INTERNAL_ERROR;
762         }
763     }
764
765   if(input==NULL)
766     input=stdin;
767
768   if(output==NULL)
769     output=stdout;
770
771   opt=init_ks_options();
772   if(!opt)
773     return KEYSERVER_NO_MEMORY;
774
775   /* Get the command and info block */
776
777   while(fgets(line,MAX_LINE,input)!=NULL)
778     {
779       int err;
780       char option[MAX_OPTION+1];
781
782       if(line[0]=='\n')
783         break;
784
785       err=parse_ks_options(line,opt);
786       if(err>0)
787         {
788           ret=err;
789           goto fail;
790         }
791       else if(err==0)
792         continue;
793
794       if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
795         {
796           int no=0;
797           char *start=&option[0];
798
799           option[MAX_OPTION]='\0';
800
801           if(strncasecmp(option,"no-",3)==0)
802             {
803               no=1;
804               start=&option[3];
805             }
806
807           if(strncasecmp(start,"http-proxy",10)==0)
808             {
809               if(no)
810                 {
811                   free(proxy);
812                   proxy=strdup("");
813                 }
814               else if(start[10]=='=')
815                 {
816                   if(strlen(&start[11])<MAX_PROXY)
817                     {
818                       free(proxy);
819                       proxy=strdup(&start[11]);
820                     }
821                 }
822             }
823           else if(strcasecmp(start,"try-dns-srv")==0)
824             {
825               if(no)
826                 try_srv=0;
827               else
828                 try_srv=1;
829             }
830
831           continue;
832         }
833     }
834
835   if(!opt->scheme)
836     {
837       fprintf(console,"gpgkeys: no scheme supplied!\n");
838       ret=KEYSERVER_SCHEME_NOT_FOUND;
839       goto fail;
840     }
841
842   /* Defaults */
843   if(ks_strcasecmp(opt->scheme,"hkps")==0)
844     {
845       proto="https";
846       port="443";
847     }
848   else
849     {
850       proto="http";
851       port="11371";
852     }
853
854   if(!opt->host)
855     {
856       fprintf(console,"gpgkeys: no keyserver host provided\n");
857       goto fail;
858     }
859
860   if(opt->timeout && register_timeout()==-1)
861     {
862       fprintf(console,"gpgkeys: unable to register timeout handler\n");
863       return KEYSERVER_INTERNAL_ERROR;
864     }
865
866   curl_global_init(CURL_GLOBAL_DEFAULT);
867   curl=curl_easy_init();
868   if(!curl)
869     {
870       fprintf(console,"gpgkeys: unable to initialize curl\n");
871       ret=KEYSERVER_INTERNAL_ERROR;
872       goto fail;
873     }
874
875   if(opt->debug)
876     {
877       fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
878       curl_easy_setopt(curl,CURLOPT_STDERR,console);
879       curl_easy_setopt(curl,CURLOPT_VERBOSE,1L);
880     }
881
882   /* Only use SRV if the user does not provide a :port.  The semantics
883      of a specified port and SRV do not play well together. */
884   if(!opt->port && try_srv)
885     {
886       char *srvtag;
887
888       if(ks_strcasecmp(opt->scheme,"hkp")==0)
889         srvtag="pgpkey-http";
890       else if(ks_strcasecmp(opt->scheme,"hkps")==0)
891         srvtag="pgpkey-https";
892       else
893         srvtag=NULL;
894
895 #ifdef HAVE_LIBCURL
896       /* We're using libcurl, so fake SRV support via our wrapper.
897          This isn't as good as true SRV support, as we do not try all
898          possible targets at one particular level and work our way
899          down the list, but it's better than nothing. */
900 #ifdef USE_DNS_SRV
901       srv_replace(srvtag,&headers,&resolve);
902 #else
903       fprintf(console,"gpgkeys: try-dns-srv was requested, but not SRV capable\n");
904 #endif
905 #else /* !HAVE_LIBCURL */
906       /* We're using our internal curl shim, so we can use its (true)
907          SRV support.  Obviously, CURLOPT_SRVTAG_GPG_HACK isn't a real
908          libcurl option.  It's specific to our shim. */
909       curl_easy_setopt(curl,CURLOPT_SRVTAG_GPG_HACK,srvtag);
910 #endif
911     }
912
913   /* If the user provided a port (or it came in via SRV, above),
914      replace the default. */
915   if(opt->port)
916     port=opt->port;
917
918   curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
919
920   if(opt->auth)
921     curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
922
923   curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert);
924   if (opt->ca_cert_file)
925     curl_easy_setopt (curl, CURLOPT_CAINFO, opt->ca_cert_file);
926
927   /* Avoid caches to get the most recent copy of the key.  This is bug
928      #1061.  In pre-curl versions of the code, we didn't do it.  Then
929      we did do it (as a curl default) until curl changed the default.
930      Now we're doing it again, but in such a way that changing
931      defaults in the future won't impact us.  We set both the Pragma
932      and Cache-Control versions of the header, so we're good with both
933      HTTP 1.0 and 1.1. */
934   headers=curl_slist_append(headers,"Pragma: no-cache");
935   if(headers)
936     headers=curl_slist_append(headers,"Cache-Control: no-cache");
937
938   if(!headers)
939     {
940       fprintf(console,"gpgkeys: out of memory when building HTTP headers\n");
941       ret=KEYSERVER_NO_MEMORY;
942       goto fail;
943     }
944
945   curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
946
947   if(proxy)
948     curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
949
950   /* If it's a GET or a SEARCH, the next thing to come in is the
951      keyids.  If it's a SEND, then there are no keyids. */
952
953   if(opt->action==KS_SEND)
954     while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
955   else if(opt->action==KS_GET
956           || opt->action==KS_GETNAME || opt->action==KS_SEARCH)
957     {
958       for(;;)
959         {
960           struct keylist *work;
961
962           if(fgets(line,MAX_LINE,input)==NULL)
963             break;
964           else
965             {
966               if(line[0]=='\n' || line[0]=='\0')
967                 break;
968
969               work=malloc(sizeof(struct keylist));
970               if(work==NULL)
971                 {
972                   fprintf(console,"gpgkeys: out of memory while "
973                           "building key list\n");
974                   ret=KEYSERVER_NO_MEMORY;
975                   goto fail;
976                 }
977
978               strcpy(work->str,line);
979
980               /* Trim the trailing \n */
981               work->str[strlen(line)-1]='\0';
982
983               work->next=NULL;
984
985               /* Always attach at the end to keep the list in proper
986                  order for searching */
987               if(keylist==NULL)
988                 keylist=work;
989               else
990                 keyptr->next=work;
991
992               keyptr=work;
993             }
994         }
995     }
996   else
997     {
998       fprintf(console,"gpgkeys: no keyserver command specified\n");
999       goto fail;
1000     }
1001
1002   /* Send the response */
1003
1004   fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
1005   fprintf(output,"PROGRAM %s\n\n",VERSION);
1006
1007   if(opt->verbose>1)
1008     {
1009       fprintf(console,"Host:\t\t%s\n",opt->host);
1010       if(opt->port)
1011         fprintf(console,"Port:\t\t%s\n",opt->port);
1012       if(strcmp(opt->path,"/")!=0)
1013         fprintf(console,"Path:\t\t%s\n",opt->path);
1014       fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
1015     }
1016
1017   if(opt->action==KS_GET)
1018     {
1019       keyptr=keylist;
1020
1021       while(keyptr!=NULL)
1022         {
1023           set_timeout(opt->timeout);
1024
1025           if(get_key(keyptr->str)!=KEYSERVER_OK)
1026             failed++;
1027
1028           keyptr=keyptr->next;
1029         }
1030     }
1031   else if(opt->action==KS_GETNAME)
1032     {
1033       keyptr=keylist;
1034
1035       while(keyptr!=NULL)
1036         {
1037           set_timeout(opt->timeout);
1038
1039           if(get_name(keyptr->str)!=KEYSERVER_OK)
1040             failed++;
1041
1042           keyptr=keyptr->next;
1043         }
1044     }
1045   else if(opt->action==KS_SEND)
1046     {
1047       int myeof=0;
1048
1049       do
1050         {
1051           set_timeout(opt->timeout);
1052
1053           if(send_key(&myeof)!=KEYSERVER_OK)
1054             failed++;
1055         }
1056       while(!myeof);
1057     }
1058   else if(opt->action==KS_SEARCH)
1059     {
1060       char *searchkey=NULL;
1061       int len=0;
1062
1063       set_timeout(opt->timeout);
1064
1065       /* To search, we stick a space in between each key to search
1066          for. */
1067
1068       keyptr=keylist;
1069       while(keyptr!=NULL)
1070         {
1071           len+=strlen(keyptr->str)+1;
1072           keyptr=keyptr->next;
1073         }
1074
1075       searchkey=malloc(len+1);
1076       if(searchkey==NULL)
1077         {
1078           ret=KEYSERVER_NO_MEMORY;
1079           fail_all(keylist,KEYSERVER_NO_MEMORY);
1080           goto fail;
1081         }
1082
1083       searchkey[0]='\0';
1084
1085       keyptr=keylist;
1086       while(keyptr!=NULL)
1087         {
1088           strcat(searchkey,keyptr->str);
1089           strcat(searchkey," ");
1090           keyptr=keyptr->next;
1091         }
1092
1093       /* Nail that last space */
1094       if(*searchkey)
1095         searchkey[strlen(searchkey)-1]='\0';
1096
1097       if(search_key(searchkey)!=KEYSERVER_OK)
1098         failed++;
1099
1100       free(searchkey);
1101     }
1102   else
1103     abort();
1104
1105   if(!failed)
1106     ret=KEYSERVER_OK;
1107
1108  fail:
1109   while(keylist!=NULL)
1110     {
1111       struct keylist *current=keylist;
1112       keylist=keylist->next;
1113       free(current);
1114     }
1115
1116   if(input!=stdin)
1117     fclose(input);
1118
1119   if(output!=stdout)
1120     fclose(output);
1121
1122   free_ks_options(opt);
1123
1124   curl_slist_free_all(headers);
1125   curl_slist_free_all(resolve);
1126
1127   if(curl)
1128     curl_easy_cleanup(curl);
1129
1130   free(proxy);
1131
1132   return ret;
1133 }