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