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