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