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