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