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