* gpgkeys_curl.c, gpgkeys_ldap.c, gpgkeys_hkp.c, ksutil.c: Rename all
[gnupg.git] / keyserver / gpgkeys_hkp.c
1 /* gpgkeys_hkp.c - talk to an HKP keyserver
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006,
3  *               2007 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 2 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, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA.
21  *
22  * In addition, as a special exception, the Free Software Foundation
23  * gives permission to link the code of the keyserver helper tools:
24  * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL
25  * project's "OpenSSL" library (or with modified versions of it that
26  * use the same license as the "OpenSSL" library), and distribute the
27  * linked executables.  You must obey the GNU General Public License
28  * in all respects for all of the code used other than "OpenSSL".  If
29  * you modify this file, you may extend this exception to your version
30  * of the file, but you are not obligated to do so.  If you do not
31  * wish to do so, delete this exception statement from your version.
32  */
33
34 #include <config.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #ifdef HAVE_GETOPT_H
41 #include <getopt.h>
42 #endif
43 #ifdef HAVE_LIBCURL
44 #include <curl/curl.h>
45 #else
46 #include "curl-shim.h"
47 #endif
48 #include "compat.h"
49 #include "keyserver.h"
50 #include "ksutil.h"
51
52 extern char *optarg;
53 extern int optind;
54
55 static FILE *input,*output,*console;
56 static CURL *curl;
57 static struct ks_options *opt;
58 static char errorbuffer[CURL_ERROR_SIZE];
59
60 static size_t
61 curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
62 {
63   static int checked=0,swallow=0;
64
65   if(!checked)
66     {
67       /* If the document begins with a '<', assume it's a HTML
68          response, which we don't support.  Discard the whole message
69          body.  GPG can handle it, but this is an optimization to deal
70          with it on this side of the pipe.  */
71       const char *buf=ptr;
72       if(buf[0]=='<')
73         swallow=1;
74
75       checked=1;
76     }
77
78   if(swallow || fwrite(ptr,size,nmemb,stream)==nmemb)
79     return size*nmemb;
80   else
81     return 0;
82 }
83
84 /* Append but avoid creating a double slash // in the path. */
85 static char *
86 append_path(char *dest,const char *src)
87 {
88   size_t n=strlen(dest);
89
90   if(src[0]=='/' && n>0 && dest[n-1]=='/')
91     dest[n-1]='\0';
92
93   return strcat(dest,src);
94 }
95
96 int
97 send_key(int *eof)
98 {
99   CURLcode res;
100   char request[MAX_URL+15];
101   int begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
102   char keyid[17],state[6];
103   char line[MAX_LINE];
104   char *key=NULL,*encoded_key=NULL;
105   size_t keysize=1;
106
107   key=malloc(1);
108   if(!key)
109     {
110       fprintf(console,"gpgkeys: unable to allocate memory for key\n");
111       ret=KEYSERVER_NO_MEMORY;
112       goto fail;
113     }
114
115   key[0]='\0';
116
117   /* Read and throw away input until we see the BEGIN */
118
119   while(fgets(line,MAX_LINE,input)!=NULL)
120     if(sscanf(line,"KEY%*[ ]%16s%*[ ]%5s\n",keyid,state)==2
121        && strcmp(state,"BEGIN")==0)
122       {
123         begin=1;
124         break;
125       }
126
127   if(!begin)
128     {
129       /* i.e. eof before the KEY BEGIN was found.  This isn't an
130          error. */
131       *eof=1;
132       ret=KEYSERVER_OK;
133       goto fail;
134     }
135
136   /* Now slurp up everything until we see the END */
137
138   while(fgets(line,MAX_LINE,input))
139     if(sscanf(line,"KEY%*[ ]%16s%*[ ]%3s\n",keyid,state)==2
140        && strcmp(state,"END")==0)
141       {
142         end=1;
143         break;
144       }
145     else
146       {
147         char *tempkey;
148         keysize+=strlen(line);
149         tempkey=realloc(key,keysize);
150         if(tempkey==NULL)
151           {
152             fprintf(console,"gpgkeys: unable to reallocate for key\n");
153             ret=KEYSERVER_NO_MEMORY;
154             goto fail;
155           }
156         else
157           key=tempkey;
158
159         strcat(key,line);
160       }
161
162   if(!end)
163     {
164       fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
165       *eof=1;
166       ret=KEYSERVER_KEY_INCOMPLETE;
167       goto fail;
168     }
169
170   encoded_key=curl_easy_escape(curl,key,keysize);
171   if(!encoded_key)
172     {
173       fprintf(console,"gpgkeys: out of memory\n");
174       ret=KEYSERVER_NO_MEMORY;
175       goto fail;
176     }
177
178   free(key);
179
180   key=malloc(8+strlen(encoded_key)+1);
181   if(!key)
182     {
183       fprintf(console,"gpgkeys: out of memory\n");
184       ret=KEYSERVER_NO_MEMORY;
185       goto fail;
186     }
187
188   strcpy(key,"keytext=");
189   strcat(key,encoded_key);
190
191   strcpy(request,"http://");
192   strcat(request,opt->host);
193   strcat(request,":");
194   if(opt->port)
195     strcat(request,opt->port);
196   else
197     strcat(request,"11371");
198   strcat(request,opt->path);
199   /* request is MAX_URL+15 bytes long - MAX_URL covers the whole URL,
200      including any supplied path.  The 15 covers /pks/add. */
201   append_path(request,"/pks/add");
202
203   if(opt->verbose>2)
204     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
205
206   curl_easy_setopt(curl,CURLOPT_URL,request);
207   curl_easy_setopt(curl,CURLOPT_POST,1);
208   curl_easy_setopt(curl,CURLOPT_POSTFIELDS,key);
209   curl_easy_setopt(curl,CURLOPT_FAILONERROR,1);
210
211   res=curl_easy_perform(curl);
212   if(res!=0)
213     {
214       fprintf(console,"gpgkeys: HTTP post error %d: %s\n",res,errorbuffer);
215       ret=curl_err_to_gpg_err(res);
216       goto fail;
217     }
218   else
219     fprintf(output,"\nKEY %s SENT\n",keyid);
220
221   ret=KEYSERVER_OK;
222
223  fail:
224   free(key);
225   curl_free(encoded_key);
226
227   if(ret!=0 && begin)
228     fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
229
230   return ret;
231 }
232
233 static int
234 get_key(char *getkey)
235 {
236   CURLcode res;
237   char request[MAX_URL+60];
238   char *offset;
239   struct curl_writer_ctx ctx;
240
241   memset(&ctx,0,sizeof(ctx));
242
243   /* Build the search string.  HKP only uses the short key IDs. */
244
245   if(strncmp(getkey,"0x",2)==0)
246     getkey+=2;
247
248   fprintf(output,"KEY 0x%s BEGIN\n",getkey);
249
250   if(strlen(getkey)==32)
251     {
252       fprintf(console,
253               "gpgkeys: HKP keyservers do not support v3 fingerprints\n");
254       fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
255       return KEYSERVER_NOT_SUPPORTED;
256     }
257
258   strcpy(request,"http://");
259   strcat(request,opt->host);
260   strcat(request,":");
261   if(opt->port)
262     strcat(request,opt->port);
263   else
264     strcat(request,"11371");
265   strcat(request,opt->path);
266   /* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
267      including any supplied path.  The 60 overcovers this /pks/... etc
268      string plus the 8 bytes of key id */
269   append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
270
271   /* fingerprint or long key id.  Take the last 8 characters and treat
272      it like a short key id */
273   if(strlen(getkey)>8)
274     offset=&getkey[strlen(getkey)-8];
275   else
276     offset=getkey;
277
278   strcat(request,offset);
279
280   if(opt->verbose>2)
281     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
282
283   curl_easy_setopt(curl,CURLOPT_URL,request);
284   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
285   ctx.stream=output;
286   curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
287
288   res=curl_easy_perform(curl);
289   if(res!=CURLE_OK)
290     {
291       fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
292       fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res));
293     }
294   else
295     {
296       curl_writer_finalize(&ctx);
297       if(!ctx.flags.done)
298         {
299           fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
300           fprintf(output,"\nKEY 0x%s FAILED %d\n",
301                   getkey,KEYSERVER_KEY_NOT_FOUND);
302         }
303       else
304         fprintf(output,"\nKEY 0x%s END\n",getkey);
305     }
306
307   return KEYSERVER_OK;
308 }
309
310 static int
311 get_name(const char *getkey)
312 {
313   CURLcode res;
314   char *request=NULL;
315   char *searchkey_encoded;
316   int ret=KEYSERVER_INTERNAL_ERROR;
317   struct curl_writer_ctx ctx;
318
319   memset(&ctx,0,sizeof(ctx));
320
321   searchkey_encoded=curl_easy_escape(curl,(char *)getkey,0);
322   if(!searchkey_encoded)
323     {
324       fprintf(console,"gpgkeys: out of memory\n");
325       ret=KEYSERVER_NO_MEMORY;
326       goto fail;
327     }
328
329   request=malloc(MAX_URL+60+strlen(searchkey_encoded));
330   if(!request)
331     {
332       fprintf(console,"gpgkeys: out of memory\n");
333       ret=KEYSERVER_NO_MEMORY;
334       goto fail;
335     }
336
337   fprintf(output,"NAME %s BEGIN\n",getkey);
338
339   strcpy(request,"http://");
340   strcat(request,opt->host);
341   strcat(request,":");
342   if(opt->port)
343     strcat(request,opt->port);
344   else
345     strcat(request,"11371");
346   strcat(request,opt->path);
347   append_path(request,"/pks/lookup?op=get&options=mr&search=");
348   strcat(request,searchkey_encoded);
349
350   if(opt->action==KS_GETNAME)
351     strcat(request,"&exact=on");
352
353   if(opt->verbose>2)
354     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
355
356   curl_easy_setopt(curl,CURLOPT_URL,request);
357   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
358   ctx.stream=output;
359   curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
360
361   res=curl_easy_perform(curl);
362   if(res!=CURLE_OK)
363     {
364       fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
365       ret=curl_err_to_gpg_err(res);
366     }
367   else
368     {
369       curl_writer_finalize(&ctx);
370       if(!ctx.flags.done)
371         {
372           fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
373           ret=KEYSERVER_KEY_NOT_FOUND;
374         }
375       else
376         {
377           fprintf(output,"\nNAME %s END\n",getkey);
378           ret=KEYSERVER_OK;
379         }
380     }
381
382  fail:
383   curl_free(searchkey_encoded);
384   free(request);
385
386   if(ret!=KEYSERVER_OK)
387     fprintf(output,"\nNAME %s FAILED %d\n",getkey,ret);
388
389   return ret;
390 }
391
392 static int
393 search_key(const char *searchkey)
394 {
395   CURLcode res;
396   char *request=NULL;
397   char *searchkey_encoded;
398   int ret=KEYSERVER_INTERNAL_ERROR;
399   enum ks_search_type search_type;
400
401   search_type=classify_ks_search(&searchkey);
402
403   if(opt->debug)
404     fprintf(console,"gpgkeys: search type is %d, and key is \"%s\"\n",
405             search_type,searchkey);
406
407   searchkey_encoded=curl_easy_escape(curl,(char *)searchkey,0);
408   if(!searchkey_encoded)
409     {
410       fprintf(console,"gpgkeys: out of memory\n");
411       ret=KEYSERVER_NO_MEMORY;
412       goto fail;
413     }
414
415   request=malloc(MAX_URL+60+strlen(searchkey_encoded));
416   if(!request)
417     {
418       fprintf(console,"gpgkeys: out of memory\n");
419       ret=KEYSERVER_NO_MEMORY;
420       goto fail;
421     }
422
423   fprintf(output,"SEARCH %s BEGIN\n",searchkey);
424
425   strcpy(request,"http://");
426   strcat(request,opt->host);
427   strcat(request,":");
428   if(opt->port)
429     strcat(request,opt->port);
430   else
431     strcat(request,"11371");
432   strcat(request,opt->path);
433   append_path(request,"/pks/lookup?op=index&options=mr&search=");
434
435   /* HKP keyservers like the 0x to be present when searching by
436      keyid */
437   if(search_type==KS_SEARCH_KEYID_SHORT || search_type==KS_SEARCH_KEYID_LONG)
438     strcat(request,"0x");
439
440   strcat(request,searchkey_encoded);
441
442   if(search_type!=KS_SEARCH_SUBSTR)
443     strcat(request,"&exact=on");
444
445   if(opt->verbose>2)
446     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
447
448   curl_easy_setopt(curl,CURLOPT_URL,request);
449   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
450   curl_easy_setopt(curl,CURLOPT_FILE,output);
451
452   res=curl_easy_perform(curl);
453   if(res!=0)
454     {
455       fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
456       ret=curl_err_to_gpg_err(res);
457     }
458   else
459     {
460       fprintf(output,"\nSEARCH %s END\n",searchkey);
461       ret=KEYSERVER_OK;
462     }
463
464  fail:
465
466   curl_free(searchkey_encoded);
467   free(request);
468
469   if(ret!=KEYSERVER_OK)
470     fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
471
472   return ret;
473 }
474
475 void
476 fail_all(struct keylist *keylist,int err)
477 {
478   if(!keylist)
479     return;
480
481   if(opt->action==KS_SEARCH)
482     {
483       fprintf(output,"SEARCH ");
484       while(keylist)
485         {
486           fprintf(output,"%s ",keylist->str);
487           keylist=keylist->next;
488         }
489       fprintf(output,"FAILED %d\n",err);
490     }
491   else
492     while(keylist)
493       {
494         fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
495         keylist=keylist->next;
496       }
497 }
498
499 static void 
500 show_help (FILE *fp)
501 {
502   fprintf (fp,"-h\thelp\n");
503   fprintf (fp,"-V\tversion\n");
504   fprintf (fp,"-o\toutput to this file\n");
505 }
506
507 int
508 main(int argc,char *argv[])
509 {
510   int arg,ret=KEYSERVER_INTERNAL_ERROR;
511   char line[MAX_LINE];
512   int failed=0;
513   struct keylist *keylist=NULL,*keyptr=NULL;
514   char *proxy=NULL;
515
516   console=stderr;
517
518   /* Kludge to implement standard GNU options.  */
519   if (argc > 1 && !strcmp (argv[1], "--version"))
520     {
521       fputs ("gpgkeys_hkp (GnuPG) " VERSION"\n", stdout);
522       return 0;
523     }
524   else if (argc > 1 && !strcmp (argv[1], "--help"))
525     {
526       show_help (stdout);
527       return 0;
528     }
529
530   while((arg=getopt(argc,argv,"hVo:"))!=-1)
531     switch(arg)
532       {
533       default:
534       case 'h':
535         show_help (console);
536         return KEYSERVER_OK;
537
538       case 'V':
539         fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
540         return KEYSERVER_OK;
541
542       case 'o':
543         output=fopen(optarg,"w");
544         if(output==NULL)
545           {
546             fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
547                     optarg,strerror(errno));
548             return KEYSERVER_INTERNAL_ERROR;
549           }
550
551         break;
552       }
553
554   if(argc>optind)
555     {
556       input=fopen(argv[optind],"r");
557       if(input==NULL)
558         {
559           fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
560                   argv[optind],strerror(errno));
561           return KEYSERVER_INTERNAL_ERROR;
562         }
563     }
564
565   if(input==NULL)
566     input=stdin;
567
568   if(output==NULL)
569     output=stdout;
570
571   opt=init_ks_options();
572   if(!opt)
573     return KEYSERVER_NO_MEMORY;
574
575   /* Get the command and info block */
576
577   while(fgets(line,MAX_LINE,input)!=NULL)
578     {
579       int err;
580       char option[MAX_OPTION+1];
581
582       if(line[0]=='\n')
583         break;
584
585       err=parse_ks_options(line,opt);
586       if(err>0)
587         {
588           ret=err;
589           goto fail;
590         }
591       else if(err==0)
592         continue;
593
594       if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
595         {
596           int no=0;
597           char *start=&option[0];
598
599           option[MAX_OPTION]='\0';
600
601           if(ascii_strncasecmp(option,"no-",3)==0)
602             {
603               no=1;
604               start=&option[3];
605             }
606
607           if(ascii_strncasecmp(start,"http-proxy",10)==0)
608             {
609               if(no)
610                 {
611                   free(proxy);
612                   proxy=strdup("");
613                 }
614               else if(start[10]=='=')
615                 {
616                   if(strlen(&start[11])<MAX_PROXY)
617                     {
618                       free(proxy);
619                       proxy=strdup(&start[11]);
620                     }
621                 }
622             }
623 #if 0
624           else if(ascii_strcasecmp(start,"try-dns-srv")==0)
625             {
626               if(no)
627                 http_flags&=~HTTP_FLAG_TRY_SRV;
628               else
629                 http_flags|=HTTP_FLAG_TRY_SRV;
630             }
631 #endif
632           continue;
633         }
634     }
635
636   if(!opt->host)
637     {
638       fprintf(console,"gpgkeys: no keyserver host provided\n");
639       goto fail;
640     }
641
642   if(opt->timeout && register_timeout()==-1)
643     {
644       fprintf(console,"gpgkeys: unable to register timeout handler\n");
645       return KEYSERVER_INTERNAL_ERROR;
646     }
647
648   curl_global_init(CURL_GLOBAL_DEFAULT);
649   curl=curl_easy_init();
650   if(!curl)
651     {
652       fprintf(console,"gpgkeys: unable to initialize curl\n");
653       ret=KEYSERVER_INTERNAL_ERROR;
654       goto fail;
655     }
656
657   curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
658
659   if(opt->auth)
660     curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
661
662   if(opt->debug)
663     {
664       fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
665       curl_easy_setopt(curl,CURLOPT_STDERR,console);
666       curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
667     }
668
669   if(proxy)
670     curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
671
672 #if 0
673   /* By suggested convention, if the user gives a :port, then disable
674      SRV. */
675   if(opt->port)
676     http_flags&=~HTTP_FLAG_TRY_SRV;
677 #endif
678
679   /* If it's a GET or a SEARCH, the next thing to come in is the
680      keyids.  If it's a SEND, then there are no keyids. */
681
682   if(opt->action==KS_SEND)
683     while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
684   else if(opt->action==KS_GET
685           || opt->action==KS_GETNAME || opt->action==KS_SEARCH)
686     {
687       for(;;)
688         {
689           struct keylist *work;
690
691           if(fgets(line,MAX_LINE,input)==NULL)
692             break;
693           else
694             {
695               if(line[0]=='\n' || line[0]=='\0')
696                 break;
697
698               work=malloc(sizeof(struct keylist));
699               if(work==NULL)
700                 {
701                   fprintf(console,"gpgkeys: out of memory while "
702                           "building key list\n");
703                   ret=KEYSERVER_NO_MEMORY;
704                   goto fail;
705                 }
706
707               strcpy(work->str,line);
708
709               /* Trim the trailing \n */
710               work->str[strlen(line)-1]='\0';
711
712               work->next=NULL;
713
714               /* Always attach at the end to keep the list in proper
715                  order for searching */
716               if(keylist==NULL)
717                 keylist=work;
718               else
719                 keyptr->next=work;
720
721               keyptr=work;
722             }
723         }
724     }
725   else
726     {
727       fprintf(console,"gpgkeys: no keyserver command specified\n");
728       goto fail;
729     }
730
731   /* Send the response */
732
733   fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
734   fprintf(output,"PROGRAM %s\n\n",VERSION);
735
736   if(opt->verbose>1)
737     {
738       fprintf(console,"Host:\t\t%s\n",opt->host);
739       if(opt->port)
740         fprintf(console,"Port:\t\t%s\n",opt->port);
741       if(strcmp(opt->path,"/")!=0)
742         fprintf(console,"Path:\t\t%s\n",opt->path);
743       fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
744     }
745
746   if(opt->action==KS_GET)
747     {
748       keyptr=keylist;
749
750       while(keyptr!=NULL)
751         {
752           set_timeout(opt->timeout);
753
754           if(get_key(keyptr->str)!=KEYSERVER_OK)
755             failed++;
756
757           keyptr=keyptr->next;
758         }
759     }
760   else if(opt->action==KS_GETNAME)
761     {
762       keyptr=keylist;
763
764       while(keyptr!=NULL)
765         {
766           set_timeout(opt->timeout);
767
768           if(get_name(keyptr->str)!=KEYSERVER_OK)
769             failed++;
770
771           keyptr=keyptr->next;
772         }
773     }
774   else if(opt->action==KS_SEND)
775     {
776       int eof=0;
777
778       do
779         {
780           set_timeout(opt->timeout);
781
782           if(send_key(&eof)!=KEYSERVER_OK)
783             failed++;
784         }
785       while(!eof);
786     }
787   else if(opt->action==KS_SEARCH)
788     {
789       char *searchkey=NULL;
790       int len=0;
791
792       set_timeout(opt->timeout);
793
794       /* To search, we stick a space in between each key to search
795          for. */
796
797       keyptr=keylist;
798       while(keyptr!=NULL)
799         {
800           len+=strlen(keyptr->str)+1;
801           keyptr=keyptr->next;
802         }
803
804       searchkey=malloc(len+1);
805       if(searchkey==NULL)
806         {
807           ret=KEYSERVER_NO_MEMORY;
808           fail_all(keylist,KEYSERVER_NO_MEMORY);
809           goto fail;
810         }
811
812       searchkey[0]='\0';
813
814       keyptr=keylist;
815       while(keyptr!=NULL)
816         {
817           strcat(searchkey,keyptr->str);
818           strcat(searchkey," ");
819           keyptr=keyptr->next;
820         }
821
822       /* Nail that last space */
823       if(*searchkey)
824         searchkey[strlen(searchkey)-1]='\0';
825
826       if(search_key(searchkey)!=KEYSERVER_OK)
827         failed++;
828
829       free(searchkey);
830     }
831   else
832     abort();
833
834   if(!failed)
835     ret=KEYSERVER_OK;
836
837  fail:
838   while(keylist!=NULL)
839     {
840       struct keylist *current=keylist;
841       keylist=keylist->next;
842       free(current);
843     }
844
845   if(input!=stdin)
846     fclose(input);
847
848   if(output!=stdout)
849     fclose(output);
850
851   free_ks_options(opt);
852
853   if(curl)
854     curl_easy_cleanup(curl);
855
856   free(proxy);
857
858   return ret;
859 }