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