RISC OS changes due to dynload removal
[gnupg.git] / keyserver / gpgkeys_ldap.c
1 /* gpgkeys_ldap.c - talk to a LDAP 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 <time.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #ifdef NEED_LBER_H
29 #include <lber.h>
30 #endif
31 #include <ldap.h>
32 #include "keyserver.h"
33
34 #ifdef __riscos__
35 #include "util.h"
36 #endif
37
38 #define GET    0
39 #define SEND   1
40 #define SEARCH 2
41 #define MAX_LINE 80
42
43 int verbose=0,include_disabled=0,include_revoked=0,include_subkeys=0;
44 char *basekeyspacedn=NULL;
45 char host[80];
46 char portstr[10];
47 char *pgpkeystr="pgpKey";
48 FILE *input=NULL,*output=NULL,*console=NULL;
49 LDAP *ldap=NULL;
50
51 struct keylist
52 {
53   char str[MAX_LINE];
54   struct keylist *next;
55 };
56
57 #ifdef __riscos__
58 RISCOS_GLOBAL_STATICS("LDAP Keyfetcher Heap")
59 #endif /* __riscos__ */
60
61 /* Returns 0 on success, -1 on failure, and 1 on eof */
62 int send_key(void)
63 {
64   int err,gotit=0,keysize=1,ret=-1;
65   char *dn=NULL;
66   char line[MAX_LINE];
67   char *key[2]={0,0};
68   char keyid[17];
69 #ifndef __riscos__
70   LDAPMod mod={LDAP_MOD_ADD,pgpkeystr,{key}},*attrs[2]={&mod,NULL};
71 #else
72   LDAPMod mod, *attrs[2];
73   
74   mod.mod_op      = LDAP_MOD_ADD;
75   mod.mod_type    = pgpkeystr;
76   mod.mod_values  = 0;
77   mod.mod_bvalues = 0;
78   
79   attrs[0]    = &mod;
80   attrs[1]    = NULL;
81 #endif
82
83   dn=malloc(strlen("pgpCertid=virtual,")+strlen(basekeyspacedn)+1);
84   if(dn==NULL)
85     {
86       fprintf(console,"gpgkeys: can't allocate memory for keyserver record\n");
87       goto fail;
88     }
89
90   strcpy(dn,"pgpCertid=virtual,");
91   strcat(dn,basekeyspacedn);
92
93   key[0]=malloc(1);
94   if(key[0]==NULL)
95     {
96       fprintf(console,"gpgkeys: unable to allocate memory for key\n");
97       goto fail;
98     }
99
100   key[0][0]='\0';
101
102   /* Read and throw away stdin until we see the BEGIN */
103
104   while(fgets(line,MAX_LINE,input)!=NULL)
105     if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1)
106       {
107         gotit=1;
108         break;
109       }
110
111   if(!gotit)
112     {
113       /* i.e. eof before the KEY BEGIN was found */
114       ret=1;
115       goto fail;
116     }
117
118   gotit=0;
119
120   /* Now slurp up everything until we see the END */
121
122   while(fgets(line,MAX_LINE,input)!=NULL)
123     if(sscanf(line,"KEY %16s END\n",keyid)==1)
124       {
125         gotit=1;
126         break;
127       }
128     else
129       {
130         keysize+=strlen(line);
131         key[0]=realloc(key[0],keysize);
132         if(key[0]==NULL)
133           {
134             fprintf(console,"gpgkeys: unable to reallocate for key\n");
135             goto fail;
136           }
137
138         strcat(key[0],line);
139       }
140
141   if(!gotit)
142     {
143       fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
144       goto fail;
145     }
146
147   err=ldap_add_s(ldap,dn,attrs);
148   if(err!=LDAP_SUCCESS)
149     {
150       fprintf(console,"gpgkeys: error adding key %s to keyserver: %s\n",
151               keyid,ldap_err2string(err));
152       goto fail;
153     }
154
155   ret=0;
156
157  fail:
158
159   free(key[0]);
160   free(dn);
161
162   if(ret!=0)
163     fprintf(output,"KEY %s FAILED\n",keyid);
164
165   return ret;
166 }
167
168 /* Returns 0 on success and -1 on failure.  Note that key-not-found is
169    not an error! */
170 int get_key(char *getkey)
171 {
172   char **vals;
173   LDAPMessage *res,*each;
174   int ret=-1,err,count;
175   struct keylist *dupelist=NULL;
176   char search[62];
177 #ifndef __riscos__
178   char *attrs[]={pgpkeystr,"pgpuserid","pgpkeyid","pgpcertid","pgprevoked",
179                  "pgpdisabled","pgpkeycreatetime","modifytimestamp",
180                  "pgpkeysize","pgpkeytype",NULL};
181 #else
182   char *attrs[]={"foobar","pgpuserid","pgpkeyid","pgpcertid","pgprevoked",
183                  "pgpdisabled","pgpkeycreatetime","modifytimestamp",
184                  "pgpkeysize","pgpkeytype",NULL};
185   attrs[0]=pgpkeystr;
186 #endif
187
188   /* Build the search string */
189
190   /* GPG can send us a v4 fingerprint, a v3 or v4 long key id, or a v3
191      or v4 short key id */
192
193   if(strncmp(getkey,"0x",2)==0)
194     getkey+=2;
195
196   if(strlen(getkey)==32)
197     {
198       fprintf(console,
199               "gpgkeys: LDAP keyservers do not support v3 fingerprints\n");
200       fprintf(output,"KEY 0x%s BEGIN\n",getkey);
201       fprintf(output,"KEY 0x%s FAILED\n",getkey);
202       return -1;
203     }
204
205   if(strlen(getkey)>16)
206     {
207       char *offset=&getkey[strlen(getkey)-16];
208
209       /* fingerprint.  Take the last 16 characters and treat it like a
210          long key id */
211
212       if(include_subkeys)
213         sprintf(search,"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))",
214                 offset,offset);
215       else
216         sprintf(search,"(pgpcertid=%.16s)",offset);
217     }
218   else if(strlen(getkey)>8)
219     {
220       /* long key id */
221
222       if(include_subkeys)
223         sprintf(search,"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))",
224                 getkey,getkey);
225       else
226         sprintf(search,"(pgpcertid=%.16s)",getkey);
227     }
228   else
229     {
230       /* short key id */
231     
232       sprintf(search,"(pgpkeyid=%.8s)",getkey);
233     }
234
235   fprintf(output,"KEY 0x%s BEGIN\n",getkey);
236
237   if(verbose>2)
238     fprintf(console,"gpgkeys: LDAP fetch for: %s\n",search);
239
240   if(!verbose)
241     attrs[1]=NULL;
242
243   if(verbose)
244     fprintf(console,"gpgkeys: requesting key 0x%s from ldap://%s%s%s\n",
245             getkey,host,portstr?":":"",portstr?portstr:"");
246
247   err=ldap_search_s(ldap,basekeyspacedn,
248                     LDAP_SCOPE_SUBTREE,search,attrs,0,&res);
249   if(err!=0)
250     {
251       fprintf(console,"gpgkeys: LDAP search error: %s\n",ldap_err2string(err));
252       fprintf(output,"KEY 0x%s FAILED\n",getkey);
253       return -1;
254     }
255
256   count=ldap_count_entries(ldap,res);
257   if(count<1)
258     {
259       fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
260       fprintf(output,"KEY 0x%s FAILED\n",getkey);
261     }
262   else
263     {
264       /* There may be more than one unique result for a given keyID,
265          so we should fetch them all (test this by fetching short key
266          id 0xDEADBEEF). */
267
268       each=ldap_first_entry(ldap,res);
269       while(each!=NULL)
270         {
271           struct keylist *keyptr=dupelist;
272
273           /* Use the long keyid to remove duplicates.  The LDAP server
274              returns the same keyid more than once if there are
275              multiple user IDs on the key.  Note that this does NOT
276              mean that a keyid that exists multiple times on the
277              keyserver will not be fetched.  It means that each KEY,
278              no matter how many user IDs share it's keyid, will be
279              fetched only once.  If a keyid that belongs to more than
280              one key is fetched, the server quite properly responds
281              with all matching keys. -ds */
282
283           vals=ldap_get_values(ldap,each,"pgpcertid");
284           if(vals!=NULL)
285             {
286               while(keyptr!=NULL)
287                 {
288                   if(strcasecmp(keyptr->str,vals[0])==0)
289                     break;
290
291                   keyptr=keyptr->next;
292                 }
293
294               if(!keyptr)
295                 {
296                   /* it's not a duplicate, so add it */
297
298                   keyptr=malloc(sizeof(struct keylist));
299                   if(keyptr==NULL)
300                     {
301                       fprintf(console,"gpgkeys: out of memory when deduping "
302                               "key list\n");
303                       goto fail;
304                     }
305
306                   strncpy(keyptr->str,vals[0],MAX_LINE);
307                   keyptr->str[MAX_LINE-1]='\0';
308
309                   keyptr->next=dupelist;
310                   dupelist=keyptr;
311                   keyptr=NULL;
312                 }
313
314               ldap_value_free(vals);
315             }
316
317           if(!keyptr) /* it's not a duplicate */
318             {
319               if(verbose)
320                 {
321                   vals=ldap_get_values(ldap,each,"pgpuserid");
322                   if(vals!=NULL)
323                     {
324                       /* This is wrong, as the user ID is UTF8.  A
325                          better way to handle this would be to send it
326                          over to gpg and display it on that side of
327                          the pipe. */
328                       fprintf(console,"\nUser ID:\t%s\n",vals[0]);
329                       ldap_value_free(vals);
330                     }
331
332                   vals=ldap_get_values(ldap,each,"pgprevoked");
333                   if(vals!=NULL)
334                     {
335                       if(atoi(vals[0])==1)
336                         fprintf(console,"\t\t** KEY REVOKED **\n");
337                       ldap_value_free(vals);
338                     }
339
340                   vals=ldap_get_values(ldap,each,"pgpdisabled");
341                   if(vals!=NULL)
342                     {
343                       if(atoi(vals[0])==1)
344                         fprintf(console,"\t\t** KEY DISABLED **\n");
345                       ldap_value_free(vals);
346                     }
347
348                   vals=ldap_get_values(ldap,each,"pgpkeyid");
349                   if(vals!=NULL)
350                     {
351                       fprintf(console,"Short key ID:\t%s\n",vals[0]);
352                       ldap_value_free(vals);
353                     }
354
355                   vals=ldap_get_values(ldap,each,"pgpcertid");
356                   if(vals!=NULL)
357                     {
358                       fprintf(console,"Long key ID:\t%s\n",vals[0]);
359                       ldap_value_free(vals);
360                     }
361
362                   /* YYYYMMDDHHmmssZ */
363
364                   vals=ldap_get_values(ldap,each,"pgpkeycreatetime");
365                   if(vals!=NULL && strlen(vals[0])==15)
366                     {
367                       fprintf(console,"Key created:\t%.2s/%.2s/%.4s\n",
368                               &vals[0][4],&vals[0][6],vals[0]);
369                       ldap_value_free(vals);
370                     }
371
372                   vals=ldap_get_values(ldap,each,"modifytimestamp");
373                   if(vals!=NULL && strlen(vals[0])==15)
374                     {
375                       fprintf(console,"Key modified:\t%.2s/%.2s/%.4s\n",
376                               &vals[0][4],&vals[0][6],vals[0]);
377                       ldap_value_free(vals);
378                     }
379
380                   vals=ldap_get_values(ldap,each,"pgpkeysize");
381                   if(vals!=NULL)
382                     {
383                       fprintf(console,"Key size:\t%d\n",atoi(vals[0]));
384                       ldap_value_free(vals);
385                     }
386
387                   vals=ldap_get_values(ldap,each,"pgpkeytype");
388                   if(vals!=NULL)
389                     {
390                       fprintf(console,"Key type:\t%s\n",vals[0]);
391                       ldap_value_free(vals);
392                     }
393                 }
394
395               vals=ldap_get_values(ldap,each,pgpkeystr);
396               if(vals==NULL)
397                 {
398                   fprintf(console,"gpgkeys: unable to retrieve key %s "
399                           "from keyserver\n",getkey);
400                   fprintf(output,"KEY 0x%s FAILED\n",getkey);
401                 }
402               else
403                 {
404                   fprintf(output,"%sKEY 0x%s END\n",vals[0],getkey);
405
406                   ldap_value_free(vals);
407                 }
408             }
409
410           each=ldap_next_entry(ldap,each);
411         }
412     }
413
414   ret=0;
415
416  fail:
417   ldap_msgfree(res);
418
419   /* free up the dupe checker */
420   while(dupelist!=NULL)
421     {
422       struct keylist *keyptr=dupelist;
423
424       dupelist=keyptr->next;
425       free(keyptr);
426     }
427
428   return ret;
429 }
430
431 time_t ldap2epochtime(const char *timestr)
432 {
433   struct tm pgptime;
434
435   memset(&pgptime,0,sizeof(pgptime));
436
437   /* YYYYMMDDHHmmssZ */
438
439   sscanf(timestr,"%4d%2d%2d%2d%2d%2d",
440          &pgptime.tm_year,
441          &pgptime.tm_mon,
442          &pgptime.tm_mday,
443          &pgptime.tm_hour,
444          &pgptime.tm_min,
445          &pgptime.tm_sec);
446
447   pgptime.tm_year-=1900;
448   pgptime.tm_isdst=-1;
449   pgptime.tm_mon--;
450
451   return mktime(&pgptime);
452 }
453
454 void printquoted(FILE *stream,char *string,char delim)
455 {
456   while(*string)
457     {
458       if(*string==delim || *string=='\\')
459         fprintf(stream,"\\x%02x",*string);
460       else
461         fputc(*string,stream);
462
463       string++;
464     }
465 }
466
467 /* Returns 0 on success and -1 on error.  Note that key-not-found is
468    not an error! */
469 int search_key(char *searchkey)
470 {
471   char **vals;
472   LDAPMessage *res,*each;
473   int err,count;
474   /* The maxium size of the search, including the optional stuff and
475      the trailing \0 */
476   char search[2+12+MAX_LINE+2+15+14+1+1];
477   char *attrs[]={"pgpcertid","pgpuserid","pgprevoked","pgpdisabled",
478                  "pgpkeycreatetime","pgpkeyexpiretime","modifytimestamp",
479                  "pgpkeysize","pgpkeytype",NULL};
480
481   fprintf(output,"SEARCH %s BEGIN\n",searchkey);
482
483   /* Build the search string */
484
485   sprintf(search,"%s(pgpuserid=*%s*)%s%s%s",
486           (!(include_disabled&&include_revoked))?"(&":"",
487           searchkey,
488           include_disabled?"":"(pgpdisabled=0)",
489           include_revoked?"":"(pgprevoked=0)",
490           !(include_disabled&&include_revoked)?")":"");
491
492   if(verbose>2)
493     fprintf(console,"gpgkeys: LDAP search for: %s\n",search);
494
495   fprintf(console,("gpgkeys: searching for \"%s\" from LDAP server %s\n"),
496           searchkey,host);
497
498   err=ldap_search_s(ldap,basekeyspacedn,
499                     LDAP_SCOPE_SUBTREE,search,attrs,0,&res);
500   if(err!=0)
501     {
502       fprintf(console,"gpgkeys: LDAP search error: %s\n",ldap_err2string(err));
503       return -1;
504     }
505
506   count=ldap_count_entries(ldap,res);
507
508   if(count<1)
509     fprintf(output,"COUNT 0\n");
510   else
511     {
512       fprintf(output,"COUNT %d\n",count);
513
514       each=ldap_first_entry(ldap,res);
515       while(each!=NULL)
516         {
517           int flags=0;
518
519           vals=ldap_get_values(ldap,each,"pgpcertid");
520           if(vals!=NULL)
521             {
522               fprintf(output,"%s:",vals[0]);
523               ldap_value_free(vals);
524             }
525           else
526             fputc(':',output);
527
528           vals=ldap_get_values(ldap,each,"pgpuserid");
529           if(vals!=NULL)
530             {
531               /* Need to escape any colons */
532               printquoted(output,vals[0],':');
533               fputc(':',output);
534               ldap_value_free(vals);
535             }
536           else
537             fputc(':',output);
538
539           vals=ldap_get_values(ldap,each,"pgprevoked");
540           if(vals!=NULL)
541             {
542               if(atoi(vals[0])==1)
543                 flags|=1;
544               ldap_value_free(vals);
545             }
546
547           vals=ldap_get_values(ldap,each,"pgpdisabled");
548           if(vals!=NULL)
549             {
550               if(atoi(vals[0])==1)
551                 flags|=2;
552               ldap_value_free(vals);
553             }
554
555           fprintf(output,"%d:",flags);
556
557           /* YYYYMMDDHHmmssZ */
558
559           vals=ldap_get_values(ldap,each,"pgpkeycreatetime");
560           if(vals!=NULL && strlen(vals[0])==15)
561             {
562               fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0]));
563               ldap_value_free(vals);
564             }
565           else
566             fputc(':',output);
567
568           vals=ldap_get_values(ldap,each,"pgpkeyexpiretime");
569           if(vals!=NULL && strlen(vals[0])==15)
570             {
571               fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0]));
572               ldap_value_free(vals);
573             }
574           else
575             fputc(':',output);
576
577           vals=ldap_get_values(ldap,each,"modifytimestamp");
578           if(vals!=NULL && strlen(vals[0])==15)
579             {
580               fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0]));
581               ldap_value_free(vals);
582             }
583           else
584             fputc(':',output);
585
586           vals=ldap_get_values(ldap,each,"pgpkeytype");
587           if(vals!=NULL)
588             {
589               fprintf(output,"%s:",vals[0]);
590               ldap_value_free(vals);
591             }
592           else
593             fputc(':',output);
594
595           vals=ldap_get_values(ldap,each,"pgpkeysize");
596           if(vals!=NULL)
597             {
598               /* Not sure why, but some keys are listed with a key size of
599                  0.  Treat that like an unknown. */
600               if(atoi(vals[0])>0)
601                 fprintf(output,"%d",atoi(vals[0]));
602               ldap_value_free(vals);
603             }
604
605           fputc('\n',output);
606
607           each=ldap_next_entry(ldap,each);
608         }
609     }
610
611   ldap_msgfree(res);
612
613   fprintf(output,"SEARCH %s END\n",searchkey);
614
615   return 0;
616 }
617
618 int main(int argc,char *argv[])
619 {
620   int port=0,arg,err,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
621   char line[MAX_LINE],**vals;
622   int version,failed=0;
623   char *attrs[]={"basekeyspacedn","version","software",NULL};
624   LDAPMessage *res;
625   struct keylist *keylist=NULL,*keyptr=NULL;
626
627 #ifdef __riscos__
628   riscos_global_defaults();
629 #endif
630
631   console=stderr;
632
633   while((arg=getopt(argc,argv,"ho:"))!=-1)
634     switch(arg)
635       {
636       default:
637       case 'h':
638         fprintf(console,"-h\thelp\n");
639         fprintf(console,"-o\toutput to this file\n");
640         return KEYSERVER_OK;
641
642       case 'o':
643         output=fopen(optarg,"w");
644         if(output==NULL)
645           {
646             fprintf(console,"gpgkeys: Cannot open output file \"%s\": %s\n",
647                     optarg,strerror(errno));
648             return KEYSERVER_INTERNAL_ERROR;
649           }
650
651         break;
652       }
653
654   if(argc>optind)
655     {
656       input=fopen(argv[optind],"r");
657       if(input==NULL)
658         {
659           fprintf(console,"gpgkeys: Cannot open input file \"%s\": %s\n",
660                   argv[optind],strerror(errno));
661           return KEYSERVER_INTERNAL_ERROR;
662         }
663     }
664
665   if(input==NULL)
666     input=stdin;
667
668   if(output==NULL)
669     output=stdout;
670
671   /* Get the command and info block */
672
673   while(fgets(line,MAX_LINE,input)!=NULL)
674     {
675       char commandstr[7];
676       char optionstr[30];
677       char hash;
678
679       if(line[0]=='\n')
680         break;
681
682       if(sscanf(line,"%c",&hash)==1 && hash=='#')
683         continue;
684
685       if(sscanf(line,"COMMAND %6s\n",commandstr)==1)
686         {
687           commandstr[6]='\0';
688
689           if(strcasecmp(commandstr,"get")==0)
690             action=GET;
691           else if(strcasecmp(commandstr,"send")==0)
692             action=SEND;
693           else if(strcasecmp(commandstr,"search")==0)
694             action=SEARCH;
695
696           continue;
697         }
698
699       if(sscanf(line,"HOST %79s\n",host)==1)
700         {
701           host[79]='\0';
702           continue;
703         }
704
705       if(sscanf(line,"PORT %9s\n",portstr)==1)
706         {
707           portstr[9]='\0';
708           port=atoi(portstr);
709           continue;
710         }
711
712       if(sscanf(line,"VERSION %d\n",&version)==1)
713         {
714           if(version!=0)
715             {
716               ret=KEYSERVER_VERSION_ERROR;
717               goto fail;
718             }
719
720           continue;
721         }
722
723       if(sscanf(line,"OPTION %29s\n",optionstr)==1)
724         {
725           int no=0;
726           char *start=&optionstr[0];
727
728           optionstr[29]='\0';
729
730           if(strncasecmp(optionstr,"no-",3)==0)
731             {
732               no=1;
733               start=&optionstr[3];
734             }
735
736           if(strcasecmp(start,"verbose")==0)
737             {
738               if(no)
739                 verbose--;
740               else
741                 verbose++;
742             }
743           else if(strcasecmp(start,"include-disabled")==0)
744             {
745               if(no)
746                 include_disabled=0;
747               else
748                 include_disabled=1;
749             }
750           else if(strcasecmp(start,"include-revoked")==0)
751             {
752               if(no)
753                 include_revoked=0;
754               else
755                 include_revoked=1;
756             }
757           else if(strcasecmp(start,"include-subkeys")==0)
758             {
759               if(no)
760                 include_subkeys=0;
761               else
762                 include_subkeys=1;
763             }
764
765           continue;
766         }
767     }
768
769   /* If it's a GET or a SEARCH, the next thing to come in is the
770      keyids.  If it's a SEND, then there are no keyids. */
771
772   if(action==SEND)
773     while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
774   else if(action==GET || action==SEARCH)
775     {
776       for(;;)
777         {
778           struct keylist *work;
779
780           if(fgets(line,MAX_LINE,input)==NULL)
781             break;
782           else
783             {
784               if(line[0]=='\n')
785                 break;
786
787               work=malloc(sizeof(struct keylist));
788               if(work==NULL)
789                 {
790                   fprintf(console,"gpgkeys: out of memory while "
791                           "building key list\n");
792                   goto fail;
793                 }
794
795               strcpy(work->str,line);
796
797               /* Trim the trailing \n */
798               work->str[strlen(line)-1]='\0';
799
800               work->next=NULL;
801
802               /* Always attach at the end to keep the list in proper
803                  order for searching */
804               if(keylist==NULL)
805                 keylist=work;
806               else
807                 keyptr->next=work;
808
809               keyptr=work;
810             }
811         }
812     }
813   else
814     {
815       fprintf(console,"gpgkeys: no keyserver command specified\n");
816       goto fail;
817     }
818
819   /* Send the response */
820
821   fprintf(output,"VERSION 0\n");
822   fprintf(output,"PROGRAM %s\n\n",VERSION);
823
824   if(verbose>1)
825     {
826       fprintf(console,"Host:\t\t%s\n",host);
827       if(port)
828         fprintf(console,"Port:\t\t%d\n",port);
829       fprintf(console,"Command:\t%s\n",action==GET?"GET":
830               action==SEND?"SEND":"SEARCH");
831     }
832
833   ldap=ldap_init(host,port);
834   if(ldap==NULL)
835     {
836       fprintf(console,"gpgkeys: internal LDAP init error: %s\n",strerror(errno));
837       goto fail;
838     }
839
840   err=ldap_simple_bind_s(ldap,NULL,NULL);
841   if(err!=0)
842     {
843       fprintf(console,"gpgkeys: internal LDAP bind error: %s\n",
844               ldap_err2string(err));
845       goto fail;
846     }
847
848   /* Get the magic info record */
849
850   err=ldap_search_s(ldap,"cn=PGPServerInfo",LDAP_SCOPE_BASE,
851                     "(objectclass=*)",attrs,0,&res);
852   if(err==-1)
853     {
854       fprintf(console,"gpgkeys: error retrieving LDAP server info: %s\n",
855               ldap_err2string(err));
856       goto fail;
857     }
858
859   if(ldap_count_entries(ldap,res)!=1)
860     {
861       fprintf(console,"gpgkeys: more than one serverinfo record\n");
862       goto fail;
863     }
864
865   if(verbose>1)
866     {
867       vals=ldap_get_values(ldap,res,"software");
868       if(vals!=NULL)
869         {
870           fprintf(console,"Server: \t%s\n",vals[0]);
871           ldap_value_free(vals);
872         }
873     }
874
875   vals=ldap_get_values(ldap,res,"version");
876   if(vals!=NULL)
877     {
878       if(verbose>1)
879         fprintf(console,"Version:\t%s\n",vals[0]);
880
881       /* If the version is high enough, use the new pgpKeyV2
882          attribute.  This design if iffy at best, but it matches how
883          PGP does it.  I figure the NAI folks assumed that there would
884          never be a LDAP keyserver vendor with a different numbering
885          scheme. */
886       if(atoi(vals[0])>1)
887         pgpkeystr="pgpKeyV2";
888
889       ldap_value_free(vals);
890     }
891
892   /* This is always "OU=ACTIVE,O=PGP KEYSPACE,C=US", but it might not
893      be in the future. */
894
895   vals=ldap_get_values(ldap,res,"basekeyspacedn");
896   if(vals!=NULL)
897     {
898       basekeyspacedn=strdup(vals[0]);
899       if(basekeyspacedn==NULL)
900         {
901           fprintf(console,"gpgkeys: can't allocate string space "
902                   "for LDAP base\n");
903           goto fail;
904         }
905
906       ldap_value_free(vals);
907     }
908
909   ldap_msgfree(res);
910
911   switch(action)
912     {
913     case GET:
914       keyptr=keylist;
915
916       while(keyptr!=NULL)
917         {
918           if(get_key(keyptr->str)==-1)
919             failed++;
920
921           keyptr=keyptr->next;
922         }
923       break;
924
925     case SEND:
926       {
927         int ret2;
928
929         do
930           {
931             ret2=send_key();
932             if(ret2==-1)
933               failed++;
934           }
935         while(ret2!=1);
936       }
937       break;
938
939     case SEARCH:
940       {
941         char *searchkey=NULL;
942         int len=0;
943
944         /* To search, we stick a * in between each key to search for.
945            This means that if the user enters words, they'll get
946            "enters*words".  If the user "enters words", they'll get
947            "enters words" */
948
949         keyptr=keylist;
950         while(keyptr!=NULL)
951           {
952             len+=strlen(keyptr->str)+1;
953             keyptr=keyptr->next;
954           }
955
956         searchkey=malloc(len+1);
957         if(searchkey==NULL)
958           goto fail;
959
960         searchkey[0]='\0';
961
962         keyptr=keylist;
963         while(keyptr!=NULL)
964           {
965             strcat(searchkey,keyptr->str);
966             strcat(searchkey,"*");
967             keyptr=keyptr->next;
968           }
969
970         /* Nail that last "*" */
971         searchkey[strlen(searchkey)-1]='\0';
972
973         if(search_key(searchkey)==-1)
974           {
975             fprintf(output,"SEARCH %s FAILED\n",searchkey);
976             failed++;
977           }
978
979         free(searchkey);
980       }
981
982       break;
983     }
984
985   if(!failed)
986     ret=KEYSERVER_OK;
987
988  fail:
989
990   while(keylist!=NULL)
991     {
992       struct keylist *current=keylist;
993       keylist=keylist->next;
994       free(current);
995     }
996
997   if(input!=stdin)
998     fclose(input);
999
1000   if(output!=stdout)
1001     fclose(output);
1002
1003   if(ldap!=NULL)
1004     ldap_unbind_s(ldap);
1005
1006   free(basekeyspacedn);
1007
1008   return ret;
1009 }