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