* gpgkeys_hkp.c (get_key): Use options=mr when getting a key so keyserver
[gnupg.git] / keyserver / gpgkeys_hkp.c
1 /* gpgkeys_hkp.c - talk to an HKP keyserver
2  * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #define INCLUDED_BY_MAIN_MODULE 1
29 #include "util.h"
30 #include "http.h"
31 #include "keyserver.h"
32
33 #define GET    0
34 #define SEND   1
35 #define SEARCH 2
36 #define MAX_LINE 80
37
38 int verbose=0,include_revoked=0,include_disabled=0;
39 unsigned int http_flags=0;
40 char host[80]={'\0'},port[10]={'\0'};
41 FILE *input=NULL,*output=NULL,*console=NULL;
42
43 struct keylist
44 {
45   char str[MAX_LINE];
46   struct keylist *next;
47 };
48
49 #ifdef __riscos__
50 RISCOS_GLOBAL_STATICS("HKP Keyfetcher Heap")
51 #endif /* __riscos__ */
52
53 int
54 urlencode_filter( void *opaque, int control,
55                   IOBUF a, byte *buf, size_t *ret_len)
56 {
57     size_t size = *ret_len;
58     int rc=0;
59
60     if( control == IOBUFCTRL_FLUSH ) {
61         const byte *p;
62         for(p=buf; size; p++, size-- ) {
63             if( isalnum(*p) || *p == '-' )
64                 iobuf_put( a, *p );
65             else if( *p == ' ' )
66                 iobuf_put( a, '+' );
67             else {
68                 char numbuf[5];
69                 sprintf(numbuf, "%%%02X", *p );
70                 iobuf_writestr(a, numbuf );
71             }
72         }
73     }
74     else if( control == IOBUFCTRL_DESC )
75         *(char**)buf = "urlencode_filter";
76     return rc;
77 }
78
79 int
80 send_key(int *eof)
81 {
82   int rc,begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
83   char keyid[17];
84   char *request;
85   struct http_context hd;
86   unsigned int status;
87   IOBUF temp = iobuf_temp();
88   char line[MAX_LINE];
89
90   memset(&hd,0,sizeof(hd));
91
92   request=malloc(strlen(host)+100);
93   if(!request)
94     {
95       fprintf(console,"gpgkeys: out of memory\n");
96       return KEYSERVER_NO_MEMORY;
97     }
98
99   iobuf_push_filter(temp,urlencode_filter,NULL);
100
101   /* Read and throw away input until we see the BEGIN */
102
103   while(fgets(line,MAX_LINE,input)!=NULL)
104     if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1)
105       {
106         begin=1;
107         break;
108       }
109
110   if(!begin)
111     {
112       /* i.e. eof before the KEY BEGIN was found.  This isn't an
113          error. */
114       *eof=1;
115       ret=KEYSERVER_OK;
116       goto fail;
117     }
118
119   /* Now slurp up everything until we see the END */
120
121   while(fgets(line,MAX_LINE,input))
122     if(sscanf(line,"KEY %16s END\n",keyid)==1)
123       {
124         end=1;
125         break;
126       }
127     else
128       if(iobuf_writestr(temp,line))
129         {
130           fprintf(console,"gpgkeys: internal iobuf error\n");
131           goto fail;
132         }
133
134   if(!end)
135     {
136       fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
137       *eof=1;
138       ret=KEYSERVER_KEY_INCOMPLETE;
139       goto fail;
140     }
141
142   iobuf_flush_temp(temp);
143
144   sprintf(request,"x-hkp://%s%s%s/pks/add",
145           host,port[0]?":":"",port[0]?port:"");
146
147   if(verbose>2)
148     fprintf(console,"gpgkeys: HTTP URL is \"%s\"\n",request);
149
150   rc=http_open(&hd,HTTP_REQ_POST,request,http_flags);
151   if(rc)
152     {
153       fprintf(console,"gpgkeys: unable to connect to `%s'\n",host);
154       goto fail;
155     }
156
157   sprintf(request,"Content-Length: %u\r\n",
158           (unsigned)iobuf_get_temp_length(temp)+9);
159   iobuf_writestr(hd.fp_write,request);
160
161   http_start_data(&hd);
162
163   iobuf_writestr(hd.fp_write,"keytext=");
164   iobuf_write(hd.fp_write,
165               iobuf_get_temp_buffer(temp),iobuf_get_temp_length(temp));
166   iobuf_put(hd.fp_write,'\n');
167
168   rc=http_wait_response(&hd,&status);
169   if(rc)
170     {
171       fprintf(console,"gpgkeys: error sending to `%s': %s\n",
172               host,g10_errstr(rc));
173       goto fail;
174     }
175
176   if((status/100)!=2)
177     {
178       fprintf(console,"gpgkeys: remote server returned error %d\n",status);
179       goto fail;
180     }
181
182   fprintf(output,"KEY %s SENT\n",keyid);
183
184   ret=KEYSERVER_OK;
185
186  fail:
187   free(request);
188   iobuf_close(temp);
189   http_close(&hd);
190
191   if(ret!=0 && begin)
192     fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
193
194   return ret;
195 }
196
197 int
198 get_key(char *getkey)
199 {
200   int rc,gotit=0;
201   char search[29];
202   char *request;
203   struct http_context hd;
204
205   /* Build the search string.  HKP only uses the short key IDs. */
206
207   if(strncmp(getkey,"0x",2)==0)
208     getkey+=2;
209
210   if(strlen(getkey)==32)
211     {
212       fprintf(console,
213               "gpgkeys: HKP keyservers do not support v3 fingerprints\n");
214       fprintf(output,"KEY 0x%s BEGIN\n",getkey);
215       fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
216       return KEYSERVER_NOT_SUPPORTED;
217     }
218
219  if(strlen(getkey)>8)
220     {
221       char *offset=&getkey[strlen(getkey)-8];
222
223       /* fingerprint or long key id.  Take the last 8 characters and
224          treat it like a short key id */
225
226       sprintf(search,"0x%.8s",offset);
227     }
228  else
229    {
230       /* short key id */
231     
232       sprintf(search,"0x%.8s",getkey);
233     }
234
235   fprintf(output,"KEY 0x%s BEGIN\n",getkey);
236
237   if(verbose)
238     fprintf(console,"gpgkeys: requesting key 0x%s from hkp://%s%s%s\n",
239             getkey,host,port[0]?":":"",port[0]?port:"");
240
241   request=malloc(strlen(host)+100);
242   if(!request)
243     {
244       fprintf(console,"gpgkeys: out of memory\n");
245       return KEYSERVER_NO_MEMORY;
246     }
247
248   sprintf(request,"x-hkp://%s%s%s/pks/lookup?op=get&options=mr&search=%s",
249           host,port[0]?":":"",port[0]?port:"", search);
250
251   if(verbose>2)
252     fprintf(console,"gpgkeys: HTTP URL is \"%s\"\n",request);
253
254   rc=http_open_document(&hd,request,http_flags);
255   if(rc!=0)
256     {
257       fprintf(console,"gpgkeys: HKP fetch error: %s\n",
258               rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
259       fprintf(output,"KEY 0x%s FAILED %d\n",getkey,
260             rc==G10ERR_NETWORK?KEYSERVER_UNREACHABLE:KEYSERVER_INTERNAL_ERROR);
261     }
262   else
263     {
264       unsigned int maxlen=1024,buflen;
265       byte *line=NULL;
266
267       while(iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen))
268         {
269           maxlen=1024;
270
271           if(gotit)
272             {
273               fprintf(output,line);
274               if(strcmp(line,"-----END PGP PUBLIC KEY BLOCK-----\n")==0)
275                 break;
276             }
277           else
278             if(strcmp(line,"-----BEGIN PGP PUBLIC KEY BLOCK-----\n")==0)
279               {
280                 fprintf(output,line);
281                 gotit=1;
282               }
283         }
284
285       if(gotit)
286         fprintf(output,"KEY 0x%s END\n",getkey);
287       else
288         {
289           fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
290           fprintf(output,"KEY 0x%s FAILED %d\n",
291                   getkey,KEYSERVER_KEY_NOT_FOUND);
292         }
293
294       m_free(line);
295     }
296
297   free(request);
298
299   return KEYSERVER_OK;
300 }
301
302 /* Remove anything <between brackets> and de-urlencode in place.  Note
303    that this requires all brackets to be closed on the same line.  It
304    also means that the result is never larger than the input. */
305 void
306 dehtmlize(char *line)
307 {
308   int parsedindex=0;
309   char *parsed=line;
310
311   while(*line!='\0')
312     {
313       switch(*line)
314         {
315         case '<':
316           while(*line!='>' && *line!='\0')
317             line++;
318
319           if(*line!='\0')
320             line++;
321           break;
322
323         case '&':
324           if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='l') &&
325              (*(line+2)!='\0' && ascii_tolower(*(line+2))=='t') &&
326              (*(line+3)!='\0' && *(line+3)==';'))
327             {
328               parsed[parsedindex++]='<';
329               line+=4;
330               break;
331             }
332           else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='g') &&
333                   (*(line+2)!='\0' && ascii_tolower(*(line+2))=='t') &&
334                   (*(line+3)!='\0' && *(line+3)==';'))
335             {
336               parsed[parsedindex++]='>';
337               line+=4;
338               break;
339             }
340           else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='a') &&
341                   (*(line+2)!='\0' && ascii_tolower(*(line+2))=='m') &&
342                   (*(line+3)!='\0' && ascii_tolower(*(line+3))=='p') &&
343                   (*(line+4)!='\0' && *(line+4)==';'))
344             {
345               parsed[parsedindex++]='&';
346               line+=5;
347               break;
348             }
349
350         default:
351           parsed[parsedindex++]=*line;
352           line++;
353           break;
354         }
355     }
356
357   parsed[parsedindex]='\0';
358
359   /* Chop off any trailing whitespace.  Note that the HKP servers have
360      \r\n as line endings, and the NAI HKP servers have just \n. */
361
362   if(parsedindex>0)
363     {
364       parsedindex--;
365       while(isspace(((unsigned char *)parsed)[parsedindex]))
366         {
367           parsed[parsedindex]='\0';
368           parsedindex--;
369         }
370     }
371 }
372
373 int
374 write_quoted(IOBUF a, const char *buf, char delim)
375 {
376   char quoted[5];
377
378   sprintf(quoted,"%%%02X",delim);
379
380   while(*buf)
381     {
382       if(*buf==delim)
383         {
384           if(iobuf_writestr(a,quoted))
385             return -1;
386         }
387       else if(*buf=='%')
388         {
389           if(iobuf_writestr(a,"%25"))
390             return -1;
391         }
392       else
393         {
394           if(iobuf_writebyte(a,*buf))
395             return -1;
396         }
397
398       buf++;
399     }
400
401   return 0;
402 }
403
404 /* pub  2048/<a href="/pks/lookup?op=get&search=0x3CB3B415">3CB3B415</a> 1998/04/03 David M. Shaw &lt;<a href="/pks/lookup?op=get&search=0x3CB3B415">dshaw@jabberwocky.com</a>&gt; */
405
406 /* Luckily enough, both the HKP server and NAI HKP interface to their
407    LDAP server are close enough in output so the same function can
408    parse them both. */
409
410 int 
411 parse_hkp_index(IOBUF buffer,char *line)
412 {
413   int ret=0;
414
415   /* printf("Open %d, LINE: \"%s\"\n",open,line); */
416
417   dehtmlize(line);
418
419   /* printf("Now open %d, LINE: \"%s\"\n",open,line); */
420
421   if(line[0]=='\0')
422     return 0;
423   else if(ascii_strncasecmp(line,"pub",3)==0)
424     {
425       char *tok,*keyid,*uid=NULL,number[15];
426       int bits=0,type=0,disabled=0,revoked=0;
427       u32 createtime=0;
428
429       line+=3;
430
431       if(*line=='-')
432         {
433           disabled=1;
434           if(!include_disabled)
435             return 0;
436         }
437
438       line++;
439
440       tok=strsep(&line,"/");
441       if(tok==NULL)
442         return ret;
443
444       if(tok[strlen(tok)-1]=='R')
445         type=1;
446       else if(tok[strlen(tok)-1]=='D')
447         type=17;
448
449       bits=atoi(tok);
450
451       keyid=strsep(&line," ");
452
453       tok=strsep(&line," ");
454       if(tok!=NULL)
455         {
456           char *temp=tok;
457
458           /* The date parser wants '-' instead of '/', so... */
459           while(*temp!='\0')
460             {
461               if(*temp=='/')
462                 *temp='-';
463
464               temp++;
465             }
466
467           createtime=scan_isodatestr(tok);
468         }
469
470       if(line!=NULL)
471         {
472           while(*line==' ' && *line!='\0')
473             line++;
474
475           if(*line!='\0')
476             {
477               if(strncmp(line,"*** KEY REVOKED ***",19)==0)
478                 {
479                   revoked=1;
480                   if(!include_revoked)
481                     return 0;
482                 }
483               else
484                 uid=line;
485             }
486         }
487
488       if(keyid)
489         {
490           iobuf_writestr(buffer,"pub:");
491
492           write_quoted(buffer,keyid,':');
493
494           iobuf_writestr(buffer,":");
495
496           if(type)
497             {
498               sprintf(number,"%d",type);
499               write_quoted(buffer,number,':');
500             }
501
502           iobuf_writestr(buffer,":");
503
504           if(bits)
505             {
506               sprintf(number,"%d",bits);
507               write_quoted(buffer,number,':');
508             }
509
510           iobuf_writestr(buffer,":");
511
512           if(createtime)
513             {
514               sprintf(number,"%d",createtime);
515               write_quoted(buffer,number,':');
516             }
517
518           iobuf_writestr(buffer,"::");
519
520           if(revoked)
521             write_quoted(buffer,"r",':');
522
523           if(disabled)
524             write_quoted(buffer,"d",':');
525
526           if(uid)
527             {
528               iobuf_writestr(buffer,"\nuid:");
529               write_quoted(buffer,uid,':');
530             }
531                   
532           iobuf_writestr(buffer,"\n");
533
534           ret=1;
535         }
536     }
537   else if(ascii_strncasecmp(line,"   ",3)==0)
538     {
539       while(*line==' ' && *line!='\0')
540         line++;
541
542       if(*line!='\0')
543         {
544           iobuf_writestr(buffer,"uid:");
545           write_quoted(buffer,line,':');
546           iobuf_writestr(buffer,"\n");
547         }
548     }
549
550 #if 0
551   else if(open)
552     {
553       /* Try and catch some bastardization of HKP.  If we don't have
554          certain unchanging landmarks, we can't reliably parse the
555          response.  This only complains about problems within the key
556          section itself.  Headers and footers should not matter. */
557
558       fprintf(console,"gpgkeys: this keyserver does not support searching\n");
559       ret=-1;
560     }
561 #endif
562
563   return ret;
564 }
565
566 void
567 handle_old_hkp_index(IOBUF inp)
568 {
569   int ret,rc,count=0;
570   unsigned int buflen;
571   byte *line=NULL;
572   IOBUF buffer=iobuf_temp();
573
574   do
575     {
576       unsigned int maxlen=1024;
577
578       /* This is a judgement call.  Is it better to slurp up all the
579          results before prompting the user?  On the one hand, it
580          probably makes the keyserver happier to not be blocked on
581          sending for a long time while the user picks a key.  On the
582          other hand, it might be nice for the server to be able to
583          stop sending before a large search result page is
584          complete. */
585
586       rc=iobuf_read_line(inp,&line,&buflen,&maxlen);
587
588       ret=parse_hkp_index(buffer,line);
589       if(ret==-1)
590         break;
591
592       if(rc!=0)
593         count+=ret;
594     }
595   while(rc!=0);
596
597   m_free(line);
598
599   if(ret>-1)
600     fprintf(output,"info:1:%d\n%s",count,iobuf_get_temp_buffer(buffer));
601
602   iobuf_close(buffer);
603 }
604
605 int
606 search_key(char *searchkey)
607 {
608   int max=0,len=0,ret=KEYSERVER_INTERNAL_ERROR,rc;
609   struct http_context hd;
610   char *search=NULL,*request=NULL,*skey=searchkey;
611
612   fprintf(output,"SEARCH %s BEGIN\n",searchkey);
613
614   /* Build the search string.  It's going to need url-encoding. */
615
616   while(*skey!='\0')
617     {
618       if(max-len<3)
619         {
620           max+=100;
621           search=realloc(search,max+1); /* Note +1 for \0 */
622           if (!search)
623             {
624               fprintf(console,"gpgkeys: out of memory\n");
625               ret=KEYSERVER_NO_MEMORY;
626               goto fail;
627             }
628         }
629
630       if(isalnum(*skey) || *skey=='-')
631         search[len++]=*skey;
632       else if(*skey==' ')
633         search[len++]='+';
634       else
635         {
636           sprintf(&search[len],"%%%02X",*skey);
637           len+=3;
638         }
639
640       skey++;
641     }
642
643   search[len]='\0';
644
645   fprintf(console,("gpgkeys: searching for \"%s\" from HKP server %s\n"),
646           searchkey,host);
647
648   request=malloc(strlen(host)+100+strlen(search));
649   if(!request)
650     {
651       fprintf(console,"gpgkeys: out of memory\n");
652       ret=KEYSERVER_NO_MEMORY;
653       goto fail;
654     }
655
656   sprintf(request,"x-hkp://%s%s%s/pks/lookup?op=index&options=mr&search=%s",
657           host,port[0]?":":"",port[0]?port:"",search);
658
659  if(verbose>2)
660     fprintf(console,"gpgkeys: HTTP URL is \"%s\"\n",request);
661
662   rc=http_open_document(&hd,request,http_flags);
663   if(rc)
664     {
665       fprintf(console,"gpgkeys: can't search keyserver `%s': %s\n",
666               host,rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
667     }
668   else
669     {
670       unsigned int maxlen=1024,buflen;
671       byte *line=NULL;
672
673       /* Is it a pksd that knows how to handle machine-readable
674          format? */
675
676       rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
677       if(line[0]=='<')
678         handle_old_hkp_index(hd.fp_read);
679       else
680         do
681           {
682             fprintf(output,"%s",line);
683             maxlen=1024;
684             rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
685           }
686         while(rc!=0);
687
688       m_free(line);
689
690       http_close(&hd);
691
692       fprintf(output,"SEARCH %s END\n",searchkey);
693
694       ret=KEYSERVER_OK;
695     }
696
697  fail:
698
699   free(request);
700   free(search);
701
702   if(ret!=KEYSERVER_OK)
703     fprintf(output,"SEARCH %s FAILED %d\n",searchkey,ret);
704
705   return ret;
706 }
707
708 void
709 fail_all(struct keylist *keylist,int action,int err)
710 {
711   if(!keylist)
712     return;
713
714   if(action==SEARCH)
715     {
716       fprintf(output,"SEARCH ");
717       while(keylist)
718         {
719           fprintf(output,"%s ",keylist->str);
720           keylist=keylist->next;
721         }
722       fprintf(output,"FAILED %d\n",err);
723     }
724   else
725     while(keylist)
726       {
727         fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
728         keylist=keylist->next;
729       }
730 }
731
732 int
733 main(int argc,char *argv[])
734 {
735   int arg,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
736   char line[MAX_LINE];
737   int failed=0;
738   struct keylist *keylist=NULL,*keyptr=NULL;
739
740 #ifdef __riscos__
741   riscos_global_defaults();
742 #endif
743
744   console=stderr;
745
746   while((arg=getopt(argc,argv,"hVo:"))!=-1)
747     switch(arg)
748       {
749       default:
750       case 'h':
751         fprintf(console,"-h\thelp\n");
752         fprintf(console,"-V\tversion\n");
753         fprintf(console,"-o\toutput to this file\n");
754         return KEYSERVER_OK;
755
756       case 'V':
757         fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
758         return KEYSERVER_OK;
759
760       case 'o':
761         output=fopen(optarg,"w");
762         if(output==NULL)
763           {
764             fprintf(console,"gpgkeys: Cannot open output file \"%s\": %s\n",
765                     optarg,strerror(errno));
766             return KEYSERVER_INTERNAL_ERROR;
767           }
768
769         break;
770       }
771
772   if(argc>optind)
773     {
774       input=fopen(argv[optind],"r");
775       if(input==NULL)
776         {
777           fprintf(console,"gpgkeys: Cannot open input file \"%s\": %s\n",
778                   argv[optind],strerror(errno));
779           return KEYSERVER_INTERNAL_ERROR;
780         }
781     }
782
783   if(input==NULL)
784     input=stdin;
785
786   if(output==NULL)
787     output=stdout;
788
789   /* Get the command and info block */
790
791   while(fgets(line,MAX_LINE,input)!=NULL)
792     {
793       int version;
794       char commandstr[7];
795       char optionstr[30];
796       char hash;
797
798       if(line[0]=='\n')
799         break;
800
801       if(sscanf(line,"%c",&hash)==1 && hash=='#')
802         continue;
803
804       if(sscanf(line,"COMMAND %6s\n",commandstr)==1)
805         {
806           commandstr[6]='\0';
807
808           if(strcasecmp(commandstr,"get")==0)
809             action=GET;
810           else if(strcasecmp(commandstr,"send")==0)
811             action=SEND;
812           else if(strcasecmp(commandstr,"search")==0)
813             action=SEARCH;
814
815           continue;
816         }
817
818       if(sscanf(line,"HOST %79s\n",host)==1)
819         {
820           host[79]='\0';
821           continue;
822         }
823
824       if(sscanf(line,"PORT %9s\n",port)==1)
825         {
826           port[9]='\0';
827           continue;
828         }
829
830       if(sscanf(line,"VERSION %d\n",&version)==1)
831         {
832           if(version!=KEYSERVER_PROTO_VERSION)
833             {
834               ret=KEYSERVER_VERSION_ERROR;
835               goto fail;
836             }
837
838           continue;
839         }
840
841       if(sscanf(line,"OPTION %29s\n",optionstr)==1)
842         {
843           int no=0;
844           char *start=&optionstr[0];
845
846           optionstr[29]='\0';
847
848           if(strncasecmp(optionstr,"no-",3)==0)
849             {
850               no=1;
851               start=&optionstr[3];
852             }
853
854           if(strcasecmp(start,"verbose")==0)
855             {
856               if(no)
857                 verbose--;
858               else
859                 verbose++;
860             }
861           else if(strcasecmp(start,"include-revoked")==0)
862             {
863               if(no)
864                 include_revoked=0;
865               else
866                 include_revoked=1;
867             }
868           else if(strcasecmp(start,"include-disabled")==0)
869             {
870               if(no)
871                 include_disabled=0;
872               else
873                 include_disabled=1;
874             }
875           else if(strcasecmp(start,"honor-http-proxy")==0)
876             {
877               if(no)
878                 http_flags&=~HTTP_FLAG_TRY_PROXY;
879               else
880                 http_flags|=HTTP_FLAG_TRY_PROXY;
881
882             }
883           else if(strcasecmp(start,"broken-http-proxy")==0)
884             {
885               if(no)
886                 http_flags&=~HTTP_FLAG_NO_SHUTDOWN;
887               else
888                 http_flags|=HTTP_FLAG_NO_SHUTDOWN;
889             }
890
891           continue;
892         }
893     }
894
895   /* If it's a GET or a SEARCH, the next thing to come in is the
896      keyids.  If it's a SEND, then there are no keyids. */
897
898   if(action==SEND)
899     while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
900   else if(action==GET || action==SEARCH)
901     {
902       for(;;)
903         {
904           struct keylist *work;
905
906           if(fgets(line,MAX_LINE,input)==NULL)
907             break;
908           else
909             {
910               if(line[0]=='\n')
911                 break;
912
913               work=malloc(sizeof(struct keylist));
914               if(work==NULL)
915                 {
916                   fprintf(console,"gpgkeys: out of memory while "
917                           "building key list\n");
918                   ret=KEYSERVER_NO_MEMORY;
919                   goto fail;
920                 }
921
922               strcpy(work->str,line);
923
924               /* Trim the trailing \n */
925               work->str[strlen(line)-1]='\0';
926
927               work->next=NULL;
928
929               /* Always attach at the end to keep the list in proper
930                  order for searching */
931               if(keylist==NULL)
932                 keylist=work;
933               else
934                 keyptr->next=work;
935
936               keyptr=work;
937             }
938         }
939     }
940   else
941     {
942       fprintf(console,"gpgkeys: no keyserver command specified\n");
943       goto fail;
944     }
945
946   /* Send the response */
947
948   fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
949   fprintf(output,"PROGRAM %s\n\n",VERSION);
950
951   if(verbose>1)
952     {
953       fprintf(console,"Host:\t\t%s\n",host);
954       if(port[0])
955         fprintf(console,"Port:\t\t%s\n",port);
956       fprintf(console,"Command:\t%s\n",action==GET?"GET":
957               action==SEND?"SEND":"SEARCH");
958     }
959
960 #if 0
961   if(verbose>1)
962     {
963       vals=ldap_get_values(ldap,res,"software");
964       if(vals!=NULL)
965         {
966           fprintf(console,"Server: \t%s\n",vals[0]);
967           ldap_value_free(vals);
968         }
969
970       vals=ldap_get_values(ldap,res,"version");
971       if(vals!=NULL)
972         {
973           fprintf(console,"Version:\t%s\n",vals[0]);
974           ldap_value_free(vals);
975         }
976     }
977 #endif
978
979   switch(action)
980     {
981     case GET:
982       keyptr=keylist;
983
984       while(keyptr!=NULL)
985         {
986           if(get_key(keyptr->str)!=KEYSERVER_OK)
987             failed++;
988
989           keyptr=keyptr->next;
990         }
991       break;
992
993     case SEND:
994       {
995         int eof=0;
996
997         do
998           {
999             if(send_key(&eof)!=KEYSERVER_OK)
1000               failed++;
1001           }
1002         while(!eof);
1003       }
1004       break;
1005
1006     case SEARCH:
1007       {
1008         char *searchkey=NULL;
1009         int len=0;
1010
1011         /* To search, we stick a space in between each key to search
1012            for. */
1013
1014         keyptr=keylist;
1015         while(keyptr!=NULL)
1016           {
1017             len+=strlen(keyptr->str)+1;
1018             keyptr=keyptr->next;
1019           }
1020
1021         searchkey=malloc(len+1);
1022         if(searchkey==NULL)
1023           {
1024             ret=KEYSERVER_NO_MEMORY;
1025             fail_all(keylist,action,KEYSERVER_NO_MEMORY);
1026             goto fail;
1027           }
1028
1029         searchkey[0]='\0';
1030
1031         keyptr=keylist;
1032         while(keyptr!=NULL)
1033           {
1034             strcat(searchkey,keyptr->str);
1035             strcat(searchkey," ");
1036             keyptr=keyptr->next;
1037           }
1038
1039         /* Nail that last space */
1040         searchkey[strlen(searchkey)-1]='\0';
1041
1042         if(search_key(searchkey)!=KEYSERVER_OK)
1043           failed++;
1044
1045         free(searchkey);
1046       }
1047
1048       break;
1049     }
1050
1051   if(!failed)
1052     ret=KEYSERVER_OK;
1053
1054  fail:
1055   while(keylist!=NULL)
1056     {
1057       struct keylist *current=keylist;
1058       keylist=keylist->next;
1059       free(current);
1060     }
1061
1062   if(input!=stdin)
1063     fclose(input);
1064
1065   if(output!=stdout)
1066     fclose(output);
1067
1068   return ret;
1069 }