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