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