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