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