* gpgkeys_hkp.c (dehtmlize, parse_hkp_index): Fix memory corruption bug on
[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           if(parsedindex==0)
372             break;
373           parsedindex--;
374         }
375     }
376 }
377
378 int
379 write_quoted(IOBUF a, const char *buf, char delim)
380 {
381   char quoted[5];
382
383   sprintf(quoted,"%%%02X",delim);
384
385   while(*buf)
386     {
387       if(*buf==delim)
388         {
389           if(iobuf_writestr(a,quoted))
390             return -1;
391         }
392       else if(*buf=='%')
393         {
394           if(iobuf_writestr(a,"%25"))
395             return -1;
396         }
397       else
398         {
399           if(iobuf_writebyte(a,*buf))
400             return -1;
401         }
402
403       buf++;
404     }
405
406   return 0;
407 }
408
409 /* 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; */
410
411 /* Luckily enough, both the HKP server and NAI HKP interface to their
412    LDAP server are close enough in output so the same function can
413    parse them both. */
414
415 int 
416 parse_hkp_index(IOBUF buffer,char *line)
417 {
418   int ret=0;
419
420   /* printf("Open %d, LINE: \"%s\"\n",open,line); */
421
422   dehtmlize(line);
423
424   /* printf("Now open %d, LINE: \"%s\"\n",open,line); */
425
426   if(line[0]=='\0')
427     return 0;
428   else if(ascii_strncasecmp(line,"pub",3)==0)
429     {
430       char *tok,*keyid,*uid=NULL,number[15];
431       int bits=0,type=0,disabled=0,revoked=0;
432       u32 createtime=0;
433
434       line+=3;
435
436       if(*line=='-')
437         {
438           disabled=1;
439           if(!include_disabled)
440             return 0;
441         }
442
443       line++;
444
445       tok=strsep(&line,"/");
446       if(tok==NULL || strlen(tok)==0)
447         return ret;
448
449       if(tok[strlen(tok)-1]=='R')
450         type=1;
451       else if(tok[strlen(tok)-1]=='D')
452         type=17;
453
454       bits=atoi(tok);
455
456       keyid=strsep(&line," ");
457
458       tok=strsep(&line," ");
459       if(tok!=NULL)
460         {
461           char *temp=tok;
462
463           /* The date parser wants '-' instead of '/', so... */
464           while(*temp!='\0')
465             {
466               if(*temp=='/')
467                 *temp='-';
468
469               temp++;
470             }
471
472           createtime=scan_isodatestr(tok);
473         }
474
475       if(line!=NULL)
476         {
477           while(*line==' ' && *line!='\0')
478             line++;
479
480           if(*line!='\0')
481             {
482               if(strncmp(line,"*** KEY REVOKED ***",19)==0)
483                 {
484                   revoked=1;
485                   if(!include_revoked)
486                     return 0;
487                 }
488               else
489                 uid=line;
490             }
491         }
492
493       if(keyid)
494         {
495           iobuf_writestr(buffer,"pub:");
496
497           write_quoted(buffer,keyid,':');
498
499           iobuf_writestr(buffer,":");
500
501           if(type)
502             {
503               sprintf(number,"%d",type);
504               write_quoted(buffer,number,':');
505             }
506
507           iobuf_writestr(buffer,":");
508
509           if(bits)
510             {
511               sprintf(number,"%d",bits);
512               write_quoted(buffer,number,':');
513             }
514
515           iobuf_writestr(buffer,":");
516
517           if(createtime)
518             {
519               sprintf(number,"%d",createtime);
520               write_quoted(buffer,number,':');
521             }
522
523           iobuf_writestr(buffer,"::");
524
525           if(revoked)
526             write_quoted(buffer,"r",':');
527
528           if(disabled)
529             write_quoted(buffer,"d",':');
530
531           if(uid)
532             {
533               iobuf_writestr(buffer,"\nuid:");
534               write_quoted(buffer,uid,':');
535             }
536                   
537           iobuf_writestr(buffer,"\n");
538
539           ret=1;
540         }
541     }
542   else if(ascii_strncasecmp(line,"   ",3)==0)
543     {
544       while(*line==' ' && *line!='\0')
545         line++;
546
547       if(*line!='\0')
548         {
549           iobuf_writestr(buffer,"uid:");
550           write_quoted(buffer,line,':');
551           iobuf_writestr(buffer,"\n");
552         }
553     }
554
555 #if 0
556   else if(open)
557     {
558       /* Try and catch some bastardization of HKP.  If we don't have
559          certain unchanging landmarks, we can't reliably parse the
560          response.  This only complains about problems within the key
561          section itself.  Headers and footers should not matter. */
562
563       fprintf(console,"gpgkeys: this keyserver does not support searching\n");
564       ret=-1;
565     }
566 #endif
567
568   return ret;
569 }
570
571 void
572 handle_old_hkp_index(IOBUF inp)
573 {
574   int ret,rc,count=0;
575   unsigned int buflen;
576   byte *line=NULL;
577   IOBUF buffer=iobuf_temp();
578
579   do
580     {
581       unsigned int maxlen=1024;
582
583       /* This is a judgement call.  Is it better to slurp up all the
584          results before prompting the user?  On the one hand, it
585          probably makes the keyserver happier to not be blocked on
586          sending for a long time while the user picks a key.  On the
587          other hand, it might be nice for the server to be able to
588          stop sending before a large search result page is
589          complete. */
590
591       rc=iobuf_read_line(inp,&line,&buflen,&maxlen);
592
593       ret=parse_hkp_index(buffer,line);
594       if(ret==-1)
595         break;
596
597       if(rc!=0)
598         count+=ret;
599     }
600   while(rc!=0);
601
602   m_free(line);
603
604   if(ret>-1)
605     fprintf(output,"info:1:%d\n%s",count,iobuf_get_temp_buffer(buffer));
606
607   iobuf_close(buffer);
608 }
609
610 int
611 search_key(char *searchkey)
612 {
613   int max=0,len=0,ret=KEYSERVER_INTERNAL_ERROR,rc;
614   struct http_context hd;
615   char *search=NULL,*request=NULL,*skey=searchkey;
616
617   fprintf(output,"SEARCH %s BEGIN\n",searchkey);
618
619   /* Build the search string.  It's going to need url-encoding. */
620
621   while(*skey!='\0')
622     {
623       if(max-len<3)
624         {
625           max+=100;
626           search=realloc(search,max+1); /* Note +1 for \0 */
627           if (!search)
628             {
629               fprintf(console,"gpgkeys: out of memory\n");
630               ret=KEYSERVER_NO_MEMORY;
631               goto fail;
632             }
633         }
634
635       if(isalnum(*skey) || *skey=='-')
636         search[len++]=*skey;
637       else if(*skey==' ')
638         search[len++]='+';
639       else
640         {
641           sprintf(&search[len],"%%%02X",*skey);
642           len+=3;
643         }
644
645       skey++;
646     }
647
648   search[len]='\0';
649
650   fprintf(console,("gpgkeys: searching for \"%s\" from HKP server %s\n"),
651           searchkey,host);
652
653   request=malloc(strlen(host)+100+strlen(search));
654   if(!request)
655     {
656       fprintf(console,"gpgkeys: out of memory\n");
657       ret=KEYSERVER_NO_MEMORY;
658       goto fail;
659     }
660
661   sprintf(request,"x-hkp://%s%s%s/pks/lookup?op=index&options=mr&search=%s",
662           host,port[0]?":":"",port[0]?port:"",search);
663
664  if(verbose>2)
665     fprintf(console,"gpgkeys: HTTP URL is \"%s\"\n",request);
666
667   rc=http_open_document(&hd,request,http_flags);
668   if(rc)
669     {
670       fprintf(console,"gpgkeys: can't search keyserver `%s': %s\n",
671               host,rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
672     }
673   else
674     {
675       unsigned int maxlen=1024,buflen;
676       byte *line=NULL;
677
678       /* Is it a pksd that knows how to handle machine-readable
679          format? */
680
681       rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
682       if(line[0]=='<')
683         handle_old_hkp_index(hd.fp_read);
684       else
685         do
686           {
687             fprintf(output,"%s",line);
688             maxlen=1024;
689             rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
690           }
691         while(rc!=0);
692
693       m_free(line);
694
695       http_close(&hd);
696
697       fprintf(output,"SEARCH %s END\n",searchkey);
698
699       ret=KEYSERVER_OK;
700     }
701
702  fail:
703
704   free(request);
705   free(search);
706
707   if(ret!=KEYSERVER_OK)
708     fprintf(output,"SEARCH %s FAILED %d\n",searchkey,ret);
709
710   return ret;
711 }
712
713 void
714 fail_all(struct keylist *keylist,int action,int err)
715 {
716   if(!keylist)
717     return;
718
719   if(action==SEARCH)
720     {
721       fprintf(output,"SEARCH ");
722       while(keylist)
723         {
724           fprintf(output,"%s ",keylist->str);
725           keylist=keylist->next;
726         }
727       fprintf(output,"FAILED %d\n",err);
728     }
729   else
730     while(keylist)
731       {
732         fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
733         keylist=keylist->next;
734       }
735 }
736
737 int
738 main(int argc,char *argv[])
739 {
740   int arg,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
741   char line[MAX_LINE];
742   int failed=0;
743   struct keylist *keylist=NULL,*keyptr=NULL;
744
745 #ifdef __riscos__
746   riscos_global_defaults();
747 #endif
748
749   console=stderr;
750
751   while((arg=getopt(argc,argv,"hVo:"))!=-1)
752     switch(arg)
753       {
754       default:
755       case 'h':
756         fprintf(console,"-h\thelp\n");
757         fprintf(console,"-V\tversion\n");
758         fprintf(console,"-o\toutput to this file\n");
759         return KEYSERVER_OK;
760
761       case 'V':
762         fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
763         return KEYSERVER_OK;
764
765       case 'o':
766         output=fopen(optarg,"w");
767         if(output==NULL)
768           {
769             fprintf(console,"gpgkeys: Cannot open output file \"%s\": %s\n",
770                     optarg,strerror(errno));
771             return KEYSERVER_INTERNAL_ERROR;
772           }
773
774         break;
775       }
776
777   if(argc>optind)
778     {
779       input=fopen(argv[optind],"r");
780       if(input==NULL)
781         {
782           fprintf(console,"gpgkeys: Cannot open input file \"%s\": %s\n",
783                   argv[optind],strerror(errno));
784           return KEYSERVER_INTERNAL_ERROR;
785         }
786     }
787
788   if(input==NULL)
789     input=stdin;
790
791   if(output==NULL)
792     output=stdout;
793
794   /* Get the command and info block */
795
796   while(fgets(line,MAX_LINE,input)!=NULL)
797     {
798       int version;
799       char commandstr[7];
800       char optionstr[30];
801       char hash;
802
803       if(line[0]=='\n')
804         break;
805
806       if(sscanf(line,"%c",&hash)==1 && hash=='#')
807         continue;
808
809       if(sscanf(line,"COMMAND %6s\n",commandstr)==1)
810         {
811           commandstr[6]='\0';
812
813           if(strcasecmp(commandstr,"get")==0)
814             action=GET;
815           else if(strcasecmp(commandstr,"send")==0)
816             action=SEND;
817           else if(strcasecmp(commandstr,"search")==0)
818             action=SEARCH;
819
820           continue;
821         }
822
823       if(sscanf(line,"HOST %79s\n",host)==1)
824         {
825           host[79]='\0';
826           continue;
827         }
828
829       if(sscanf(line,"PORT %9s\n",port)==1)
830         {
831           port[9]='\0';
832           continue;
833         }
834
835       if(sscanf(line,"VERSION %d\n",&version)==1)
836         {
837           if(version!=KEYSERVER_PROTO_VERSION)
838             {
839               ret=KEYSERVER_VERSION_ERROR;
840               goto fail;
841             }
842
843           continue;
844         }
845
846       if(sscanf(line,"OPTION %29s\n",optionstr)==1)
847         {
848           int no=0;
849           char *start=&optionstr[0];
850
851           optionstr[29]='\0';
852
853           if(strncasecmp(optionstr,"no-",3)==0)
854             {
855               no=1;
856               start=&optionstr[3];
857             }
858
859           if(strcasecmp(start,"verbose")==0)
860             {
861               if(no)
862                 verbose--;
863               else
864                 verbose++;
865             }
866           else if(strcasecmp(start,"include-revoked")==0)
867             {
868               if(no)
869                 include_revoked=0;
870               else
871                 include_revoked=1;
872             }
873           else if(strcasecmp(start,"include-disabled")==0)
874             {
875               if(no)
876                 include_disabled=0;
877               else
878                 include_disabled=1;
879             }
880           else if(strcasecmp(start,"honor-http-proxy")==0)
881             {
882               if(no)
883                 http_flags&=~HTTP_FLAG_TRY_PROXY;
884               else
885                 http_flags|=HTTP_FLAG_TRY_PROXY;
886
887             }
888           else if(strcasecmp(start,"broken-http-proxy")==0)
889             {
890               if(no)
891                 http_flags&=~HTTP_FLAG_NO_SHUTDOWN;
892               else
893                 http_flags|=HTTP_FLAG_NO_SHUTDOWN;
894             }
895           else if(strcasecmp(start,"try-dns-srv")==0)
896             {
897               if(no)
898                 http_flags&=~HTTP_FLAG_TRY_SRV;
899               else
900                 http_flags|=HTTP_FLAG_TRY_SRV;
901             }
902
903           continue;
904         }
905     }
906
907   /* By suggested convention, if the user gives a :port, then disable
908      SRV. */
909   if(port[0])
910     http_flags&=~HTTP_FLAG_TRY_SRV;
911
912   /* If it's a GET or a SEARCH, the next thing to come in is the
913      keyids.  If it's a SEND, then there are no keyids. */
914
915   if(action==SEND)
916     while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
917   else if(action==GET || action==SEARCH)
918     {
919       for(;;)
920         {
921           struct keylist *work;
922
923           if(fgets(line,MAX_LINE,input)==NULL)
924             break;
925           else
926             {
927               if(line[0]=='\n')
928                 break;
929
930               work=malloc(sizeof(struct keylist));
931               if(work==NULL)
932                 {
933                   fprintf(console,"gpgkeys: out of memory while "
934                           "building key list\n");
935                   ret=KEYSERVER_NO_MEMORY;
936                   goto fail;
937                 }
938
939               strcpy(work->str,line);
940
941               /* Trim the trailing \n */
942               work->str[strlen(line)-1]='\0';
943
944               work->next=NULL;
945
946               /* Always attach at the end to keep the list in proper
947                  order for searching */
948               if(keylist==NULL)
949                 keylist=work;
950               else
951                 keyptr->next=work;
952
953               keyptr=work;
954             }
955         }
956     }
957   else
958     {
959       fprintf(console,"gpgkeys: no keyserver command specified\n");
960       goto fail;
961     }
962
963   /* Send the response */
964
965   fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
966   fprintf(output,"PROGRAM %s\n\n",VERSION);
967
968   if(verbose>1)
969     {
970       fprintf(console,"Host:\t\t%s\n",host);
971       if(port[0])
972         fprintf(console,"Port:\t\t%s\n",port);
973       fprintf(console,"Command:\t%s\n",action==GET?"GET":
974               action==SEND?"SEND":"SEARCH");
975     }
976
977 #if 0
978   if(verbose>1)
979     {
980       vals=ldap_get_values(ldap,res,"software");
981       if(vals!=NULL)
982         {
983           fprintf(console,"Server: \t%s\n",vals[0]);
984           ldap_value_free(vals);
985         }
986
987       vals=ldap_get_values(ldap,res,"version");
988       if(vals!=NULL)
989         {
990           fprintf(console,"Version:\t%s\n",vals[0]);
991           ldap_value_free(vals);
992         }
993     }
994 #endif
995
996   switch(action)
997     {
998     case GET:
999       keyptr=keylist;
1000
1001       while(keyptr!=NULL)
1002         {
1003           if(get_key(keyptr->str)!=KEYSERVER_OK)
1004             failed++;
1005
1006           keyptr=keyptr->next;
1007         }
1008       break;
1009
1010     case SEND:
1011       {
1012         int eof=0;
1013
1014         do
1015           {
1016             if(send_key(&eof)!=KEYSERVER_OK)
1017               failed++;
1018           }
1019         while(!eof);
1020       }
1021       break;
1022
1023     case SEARCH:
1024       {
1025         char *searchkey=NULL;
1026         int len=0;
1027
1028         /* To search, we stick a space in between each key to search
1029            for. */
1030
1031         keyptr=keylist;
1032         while(keyptr!=NULL)
1033           {
1034             len+=strlen(keyptr->str)+1;
1035             keyptr=keyptr->next;
1036           }
1037
1038         searchkey=malloc(len+1);
1039         if(searchkey==NULL)
1040           {
1041             ret=KEYSERVER_NO_MEMORY;
1042             fail_all(keylist,action,KEYSERVER_NO_MEMORY);
1043             goto fail;
1044           }
1045
1046         searchkey[0]='\0';
1047
1048         keyptr=keylist;
1049         while(keyptr!=NULL)
1050           {
1051             strcat(searchkey,keyptr->str);
1052             strcat(searchkey," ");
1053             keyptr=keyptr->next;
1054           }
1055
1056         /* Nail that last space */
1057         searchkey[strlen(searchkey)-1]='\0';
1058
1059         if(search_key(searchkey)!=KEYSERVER_OK)
1060           failed++;
1061
1062         free(searchkey);
1063       }
1064
1065       break;
1066     }
1067
1068   if(!failed)
1069     ret=KEYSERVER_OK;
1070
1071  fail:
1072   while(keylist!=NULL)
1073     {
1074       struct keylist *current=keylist;
1075       keylist=keylist->next;
1076       free(current);
1077     }
1078
1079   if(input!=stdin)
1080     fclose(input);
1081
1082   if(output!=stdout)
1083     fclose(output);
1084
1085   return ret;
1086 }