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