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