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