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