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