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