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