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