aboutsummaryrefslogtreecommitdiffstats
path: root/keyserver/gpgkeys_ldap.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyserver/gpgkeys_ldap.c')
-rw-r--r--keyserver/gpgkeys_ldap.c863
1 files changed, 863 insertions, 0 deletions
diff --git a/keyserver/gpgkeys_ldap.c b/keyserver/gpgkeys_ldap.c
new file mode 100644
index 000000000..e2e63dbdc
--- /dev/null
+++ b/keyserver/gpgkeys_ldap.c
@@ -0,0 +1,863 @@
+/* gpgkeys_ldap.c - talk to a LDAP keyserver
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ldap.h>
+#include "keyserver.h"
+
+#ifdef __riscos__
+#include <unixlib/local.h>
+#endif
+
+#define GET 0
+#define SEND 1
+#define SEARCH 2
+#define MAX_LINE 80
+
+int verbose=0,include_disabled=0,include_revoked=0;
+char *basekeyspacedn=NULL;
+char host[80];
+struct keylist
+{
+ char *keystr;
+ struct keylist *next;
+};
+FILE *input=NULL,*output=NULL,*console=NULL;
+
+/* Returns 0 on success, -1 on failure, and 1 on eof */
+int send_key(LDAP *ldap,char *keyid)
+{
+ int err,gotit=0,keysize=1,ret=-1;
+ char *dn=NULL;
+ char line[MAX_LINE];
+ char *key[2]={0,0};
+#ifndef __riscos__
+ LDAPMod mod={LDAP_MOD_ADD,"pgpKeyV2",{key}},*attrs[2]={&mod,NULL};
+#else
+ LDAPMod mod, *attrs[2];
+
+ mod.mod_op = LDAP_MOD_ADD;
+ mod.mod_type = "pgpKeyV2";
+ mod.mod_values = 0;
+ mod.mod_bvalues = 0;
+
+ attrs[0] = &mod;
+ attrs[1] = NULL;
+#endif
+
+ dn=malloc(strlen("pgpCertid=virtual,")+strlen(basekeyspacedn)+1);
+ if(dn==NULL)
+ {
+ fprintf(console,"gpg: Can't allocate memory for keyserver record\n");
+ goto fail;
+ }
+
+ strcpy(dn,"pgpCertid=virtual,");
+ strcat(dn,basekeyspacedn);
+
+ key[0]=malloc(1);
+ if(key[0]==NULL)
+ {
+ fprintf(console,"gpg: Unable to allocate memory for key\n");
+ goto fail;
+ }
+
+ key[0][0]='\0';
+
+ /* Read and throw away stdin until we see the BEGIN */
+
+ while(fgets(line,MAX_LINE,input)!=NULL)
+ if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1)
+ {
+ gotit=1;
+ break;
+ }
+
+ if(!gotit)
+ {
+ /* i.e. eof before the KEY BEGIN was found */
+ ret=1;
+ goto fail;
+ }
+
+ gotit=0;
+
+ /* Now slurp up everything until we see the END */
+
+ while(fgets(line,MAX_LINE,input)!=NULL)
+ if(sscanf(line,"KEY %16s END\n",keyid)==1)
+ {
+ gotit=1;
+ break;
+ }
+ else
+ {
+ keysize+=strlen(line);
+ key[0]=realloc(key[0],keysize);
+ if(key[0]==NULL)
+ {
+ fprintf(console,"gpg: Unable to reallocate for key\n");
+ goto fail;
+ }
+
+ strcat(key[0],line);
+ }
+
+ if(!gotit)
+ {
+ fprintf(console,"gpg: keyserver: No KEY %s END found\n",keyid);
+ goto fail;
+ }
+
+ err=ldap_add_s(ldap,dn,attrs);
+ if(err!=LDAP_SUCCESS)
+ {
+ fprintf(console,"gpg: error adding key %s to keyserver: %s\n",
+ keyid,ldap_err2string(err));
+ goto fail;
+ }
+
+ ret=0;
+
+ fail:
+
+ free(key[0]);
+
+ return ret;
+}
+
+int get_key(LDAP *ldap,char *getkey)
+{
+ char **vals;
+ LDAPMessage *res;
+ int err,count,i;
+ char search[29];
+ char *attrs[]={"pgpKeyV2","pgpuserid","pgpkeyid","pgpcertid","pgprevoked",
+ "pgpdisabled","pgpkeycreatetime","modifytimestamp",
+ "pgpkeysize","pgpkeytype",NULL};
+
+ /* Build the search string */
+
+ if(strncmp(getkey,"0x00000000",10)==0)
+ {
+ getkey+=10;
+ sprintf(search,"(pgpkeyid=%.8s)",getkey);
+ }
+ else
+ {
+ getkey+=2;
+ sprintf(search,"(pgpcertid=%.16s)",getkey);
+ }
+
+ fprintf(output,"KEY 0x%s BEGIN\n",getkey);
+
+ if(verbose>2)
+ fprintf(console,"LDAP fetch for: %s\n",search);
+
+ if(!verbose)
+ attrs[1]=NULL;
+
+ fprintf(console,
+ "gpg: requesting key %s from LDAP keyserver %s\n",
+ getkey,host);
+
+ err=ldap_search_s(ldap,basekeyspacedn,
+ LDAP_SCOPE_SUBTREE,search,attrs,0,&res);
+ if(err!=0)
+ {
+ fprintf(console,"gpg: LDAP search error: %s\n",ldap_err2string(err));
+ fprintf(output,"KEY 0x%s FAILED\n",getkey);
+ return -1;
+ }
+
+ count=ldap_count_entries(ldap,res);
+ if(count<1)
+ {
+ fprintf(console,"gpg: Key %s not found on keyserver\n",getkey);
+ fprintf(output,"KEY 0x%s FAILED\n",getkey);
+ return -1;
+ }
+
+ /* There may be more than one result for a given keyID, so we should
+ fetch them all. */
+ for(i=0;i<count;i++)
+ {
+ if(verbose)
+ {
+ vals=ldap_get_values(ldap,res,"pgpuserid");
+ if(vals!=NULL)
+ {
+ /* This is wrong, as the user ID is UTF8. A better way to
+ handle this would be to send it over to gpg and display
+ it on that side of the pipe. */
+ fprintf(console,"\nUser ID:\t%s\n",vals[0]);
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,res,"pgprevoked");
+ if(vals!=NULL)
+ {
+ if(atoi(vals[0])==1)
+ fprintf(console,"\t\t** KEY REVOKED **\n");
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,res,"pgpdisabled");
+ if(vals!=NULL)
+ {
+ if(atoi(vals[0])==1)
+ fprintf(console,"\t\t** KEY DISABLED **\n");
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,res,"pgpkeyid");
+ if(vals!=NULL)
+ {
+ fprintf(console,"Short key ID:\t%s\n",vals[0]);
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,res,"pgpcertid");
+ if(vals!=NULL)
+ {
+ fprintf(console,"Long key ID:\t%s\n",vals[0]);
+ ldap_value_free(vals);
+ }
+
+ /* YYYYMMDDHHmmssZ */
+
+ vals=ldap_get_values(ldap,res,"pgpkeycreatetime");
+ if(vals!=NULL && strlen(vals[0])==15)
+ {
+ fprintf(console,"Key created:\t%.2s/%.2s/%.4s\n",
+ &vals[0][4],&vals[0][6],vals[0]);
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,res,"modifytimestamp");
+ if(vals!=NULL && strlen(vals[0])==15)
+ {
+ fprintf(console,"Key modified:\t%.2s/%.2s/%.4s\n",
+ &vals[0][4],&vals[0][6],vals[0]);
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,res,"pgpkeysize");
+ if(vals!=NULL)
+ {
+ fprintf(console,"Key size:\t%d\n",atoi(vals[0]));
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,res,"pgpkeytype");
+ if(vals!=NULL)
+ {
+ fprintf(console,"Key type:\t%s\n",vals[0]);
+ ldap_value_free(vals);
+ }
+ }
+
+ vals=ldap_get_values(ldap,res,"pgpKeyV2");
+ if(vals==NULL)
+ {
+ fprintf(console,
+ "gpg: Unable to retrieve key %s from keyserver\n",getkey);
+ fprintf(output,"KEY 0x%s FAILED\n",getkey);
+ }
+ else
+ {
+ fprintf(output,"%sKEY 0x%s END\n",vals[0],getkey);
+
+ ldap_value_free(vals);
+ }
+ }
+
+ return 0;
+}
+
+time_t ldap2epochtime(const char *timestr)
+{
+ struct tm pgptime;
+
+ memset(&pgptime,0,sizeof(pgptime));
+
+ /* YYYYMMDDHHmmssZ */
+
+ sscanf(timestr,"%4d%2d%2d%2d%2d%2d",
+ &pgptime.tm_year,
+ &pgptime.tm_mon,
+ &pgptime.tm_mday,
+ &pgptime.tm_hour,
+ &pgptime.tm_min,
+ &pgptime.tm_sec);
+
+ pgptime.tm_year-=1900;
+ pgptime.tm_isdst=-1;
+ pgptime.tm_mon--;
+
+ return mktime(&pgptime);
+}
+
+void printquoted(FILE *stream,char *string,char delim)
+{
+ while(*string)
+ {
+ if(*string==delim)
+ fprintf(stream,"\\x%02X",*string);
+ else
+ fputc(*string,stream);
+
+ string++;
+ }
+}
+
+int search_key(LDAP *ldap,char *searchkey)
+{
+ char **vals;
+ LDAPMessage *res,*each;
+ int err,count;
+ /* The maxium size of the search, including the optional stuff and
+ the trailing \0 */
+ char search[2+12+MAX_LINE+2+15+14+1+1];
+ char *attrs[]={"pgpcertid","pgpuserid","pgprevoked","pgpdisabled",
+ "pgpkeycreatetime","pgpkeyexpiretime","modifytimestamp",
+ "pgpkeysize","pgpkeytype",NULL};
+
+ fprintf(output,"SEARCH %s BEGIN\n",searchkey);
+
+ /* Build the search string */
+
+ sprintf(search,"%s(pgpuserid=*%s*)%s%s%s",
+ (!(include_disabled&&include_revoked))?"(&":"",
+ searchkey,
+ include_disabled?"":"(pgpdisabled=0)",
+ include_revoked?"":"(pgprevoked=0)",
+ !(include_disabled&&include_revoked)?")":"");
+
+ if(verbose>2)
+ fprintf(console,"LDAP search for: %s\n",search);
+
+ fprintf(console,("gpg: searching for \"%s\" from LDAP server %s\n"),
+ searchkey,host);
+
+ err=ldap_search_s(ldap,basekeyspacedn,
+ LDAP_SCOPE_SUBTREE,search,attrs,0,&res);
+ if(err!=0)
+ {
+ fprintf(console,"gpg: LDAP search error: %s\n",ldap_err2string(err));
+ return -1;
+ }
+
+ count=ldap_count_entries(ldap,res);
+
+ if(count<1)
+ fprintf(output,"COUNT 0\n");
+ else
+ {
+ fprintf(output,"COUNT %d\n",count);
+
+ each=ldap_first_entry(ldap,res);
+ while(each!=NULL)
+ {
+ int flags=0;
+
+ vals=ldap_get_values(ldap,each,"pgpcertid");
+ if(vals!=NULL)
+ {
+ fprintf(output,"%s:",vals[0]);
+ ldap_value_free(vals);
+ }
+ else
+ fputc(':',output);
+
+ vals=ldap_get_values(ldap,each,"pgpuserid");
+ if(vals!=NULL)
+ {
+ /* Need to escape any colons */
+ printquoted(output,vals[0],':');
+ fputc(':',output);
+ ldap_value_free(vals);
+ }
+ else
+ fputc(':',output);
+
+ vals=ldap_get_values(ldap,each,"pgprevoked");
+ if(vals!=NULL)
+ {
+ if(atoi(vals[0])==1)
+ flags|=1;
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,each,"pgpdisabled");
+ if(vals!=NULL)
+ {
+ if(atoi(vals[0])==1)
+ flags|=2;
+ ldap_value_free(vals);
+ }
+
+ fprintf(output,"%d:",flags);
+
+ /* YYYYMMDDHHmmssZ */
+
+ vals=ldap_get_values(ldap,each,"pgpkeycreatetime");
+ if(vals!=NULL && strlen(vals[0])==15)
+ {
+ fprintf(output,"%u:",(uint)ldap2epochtime(vals[0]));
+ ldap_value_free(vals);
+ }
+ else
+ fputc(':',output);
+
+ vals=ldap_get_values(ldap,each,"pgpkeyexpiretime");
+ if(vals!=NULL && strlen(vals[0])==15)
+ {
+ fprintf(output,"%u:",(uint)ldap2epochtime(vals[0]));
+ ldap_value_free(vals);
+ }
+ else
+ fputc(':',output);
+
+ vals=ldap_get_values(ldap,each,"modifytimestamp");
+ if(vals!=NULL && strlen(vals[0])==15)
+ {
+ fprintf(output,"%u:",(uint)ldap2epochtime(vals[0]));
+ ldap_value_free(vals);
+ }
+ else
+ fputc(':',output);
+
+ vals=ldap_get_values(ldap,each,"pgpkeytype");
+ if(vals!=NULL)
+ {
+ fprintf(output,"%s:",vals[0]);
+ ldap_value_free(vals);
+ }
+ else
+ fputc(':',output);
+
+ vals=ldap_get_values(ldap,each,"pgpkeysize");
+ if(vals!=NULL)
+ {
+ /* Not sure why, but some keys are listed with a key size of
+ 0. Treat that like an unknown. */
+ if(atoi(vals[0])>0)
+ fprintf(output,"%d",atoi(vals[0]));
+ ldap_value_free(vals);
+ }
+
+ fputc('\n',output);
+
+ each=ldap_next_entry(ldap,each);
+ }
+ }
+
+ fprintf(output,"SEARCH %s END\n",searchkey);
+
+ return 0;
+}
+
+int main(int argc,char *argv[])
+{
+ LDAP *ldap=NULL;
+ int port=0,arg,err,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
+ char line[MAX_LINE],**vals;
+ int version;
+ char *attrs[]={"basekeyspacedn","version","software",NULL};
+ LDAPMessage *res;
+ struct keylist *keylist=NULL,*keyptr;
+
+#ifdef __riscos__
+ __riscosify_control = __RISCOSIFY_NO_PROCESS;
+#endif
+
+ console=stderr;
+
+ while((arg=getopt(argc,argv,"ho:"))!=-1)
+ switch(arg)
+ {
+ default:
+ case 'h':
+ fprintf(console,"-h\thelp\n");
+ fprintf(console,"-o\toutput to this file\n");
+ return KEYSERVER_OK;
+
+ case 'o':
+ output=fopen(optarg,"w");
+ if(output==NULL)
+ {
+ fprintf(console,"gpgkeys: Cannot open output file \"%s\": %s\n",
+ optarg,strerror(errno));
+ return KEYSERVER_INTERNAL_ERROR;
+ }
+
+ break;
+ }
+
+ if(argc>optind)
+ {
+ input=fopen(argv[optind],"r");
+ if(input==NULL)
+ {
+ fprintf(console,"gpgkeys: Cannot open input file \"%s\": %s\n",
+ argv[optind],strerror(errno));
+ return KEYSERVER_INTERNAL_ERROR;
+ }
+ }
+
+ if(input==NULL)
+ input=stdin;
+
+ if(output==NULL)
+ output=stdout;
+
+ /* Get the command and info block */
+
+ while(fgets(line,MAX_LINE,input)!=NULL)
+ {
+ char commandstr[7];
+ char portstr[10];
+ char optionstr[30];
+ char hash;
+
+ if(line[0]=='\n')
+ break;
+
+ if(sscanf(line,"%c",&hash)==1 && hash=='#')
+ continue;
+
+ if(sscanf(line,"COMMAND %6s\n",commandstr)==1)
+ {
+ commandstr[6]='\0';
+
+ if(strcasecmp(commandstr,"get")==0)
+ action=GET;
+ else if(strcasecmp(commandstr,"send")==0)
+ action=SEND;
+ else if(strcasecmp(commandstr,"search")==0)
+ action=SEARCH;
+
+ continue;
+ }
+
+ if(sscanf(line,"HOST %79s\n",host)==1)
+ {
+ host[79]='\0';
+ continue;
+ }
+
+ if(sscanf(line,"PORT %9s\n",portstr)==1)
+ {
+ portstr[9]='\0';
+ port=atoi(portstr);
+ continue;
+ }
+
+ if(sscanf(line,"VERSION %d\n",&version)==1)
+ {
+ if(version!=0)
+ {
+ ret=KEYSERVER_VERSION_ERROR;
+ goto fail;
+ }
+
+ continue;
+ }
+
+ if(sscanf(line,"OPTION %29s\n",optionstr)==1)
+ {
+ int no=0;
+ char *start=&optionstr[0];
+
+ optionstr[29]='\0';
+
+ if(strncasecmp(optionstr,"no-",3)==0)
+ {
+ no=1;
+ start=&optionstr[3];
+ }
+
+ if(strcasecmp(start,"verbose")==0)
+ {
+ if(no)
+ verbose--;
+ else
+ verbose++;
+ }
+ else if(strcasecmp(start,"include-disabled")==0)
+ {
+ if(no)
+ include_disabled=0;
+ else
+ include_disabled=1;
+ }
+ else if(strcasecmp(start,"include-revoked")==0)
+ {
+ if(no)
+ include_revoked=0;
+ else
+ include_revoked=1;
+ }
+
+ continue;
+ }
+ }
+
+ /* If it's a GET or a SEARCH, the next thing to come in is the
+ keyids. If it's a SEND, then there are no keyids. */
+
+ if(action==SEND)
+ while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
+ else if(action==GET || action==SEARCH)
+ {
+ keylist=malloc(sizeof(struct keylist));
+ if(keylist==NULL)
+ {
+ fprintf(console,"gpg: Out of memory when building key list\n");
+ goto fail;
+ }
+
+ keyptr=keylist;
+
+ keyptr->keystr=malloc(MAX_LINE);
+ if(keyptr->keystr==NULL)
+ {
+ fprintf(console,"gpg: Out of memory when building key list\n");
+ goto fail;
+ }
+
+ while(fgets(keyptr->keystr,MAX_LINE,input)!=NULL)
+ {
+ int len;
+
+ if(keyptr->keystr[0]=='\n')
+ {
+ free(keyptr->keystr);
+ keyptr->keystr=NULL;
+ break;
+ }
+
+ /* Trim the trailing \n */
+ len=strlen(keyptr->keystr);
+ if(len>1)
+ keyptr->keystr[len-1]='\0';
+
+ keyptr->next=malloc(sizeof(struct keylist));
+ if(keyptr->next==NULL)
+ {
+ fprintf(console,"gpg: Out of memory when building key list\n");
+ goto fail;
+ }
+
+ keyptr=keyptr->next;
+ keyptr->next=NULL;
+
+ keyptr->keystr=malloc(MAX_LINE);
+ if(keyptr->keystr==NULL)
+ {
+ fprintf(console,"gpg: Out of memory when building key list\n");
+ goto fail;
+ }
+ }
+ }
+ else
+ {
+ fprintf(console,"gpg: No keyserver command specified\n");
+ goto fail;
+ }
+
+ /* Send the response */
+
+ fprintf(output,"VERSION 0\n");
+ fprintf(output,"PROGRAM %s\n\n",VERSION);
+
+ if(verbose>1)
+ {
+ fprintf(console,"Host:\t\t%s\n",host);
+ if(port)
+ fprintf(console,"Port:\t%d\n",port);
+ fprintf(console,"Command:\t%s\n",action==GET?"GET":
+ action==SEND?"SEND":"SEARCH");
+ }
+
+ ldap=ldap_init(host,port);
+ if(ldap==NULL)
+ {
+ fprintf(console,"gpg: Internal LDAP init error: %s\n",strerror(errno));
+ goto fail;
+ }
+
+ err=ldap_simple_bind_s(ldap,NULL,NULL);
+ if(err!=0)
+ {
+ fprintf(console,"gpg: Internal LDAP bind error: %s\n",
+ ldap_err2string(err));
+ goto fail;
+ }
+
+ /* Get the magic info record */
+
+ err=ldap_search_s(ldap,"cn=PGPServerInfo",LDAP_SCOPE_BASE,
+ "(objectclass=*)",attrs,0,&res);
+ if(err==-1)
+ {
+ fprintf(console,"gpg: Error retrieving LDAP server info: %s\n",
+ ldap_err2string(err));
+ goto fail;
+ }
+
+ if(ldap_count_entries(ldap,res)!=1)
+ {
+ fprintf(console,"gpg: More than one serverinfo record\n");
+ goto fail;
+ }
+
+ if(verbose>1)
+ {
+ vals=ldap_get_values(ldap,res,"software");
+ if(vals!=NULL)
+ {
+ fprintf(console,"Server: \t%s\n",vals[0]);
+ ldap_value_free(vals);
+ }
+
+ vals=ldap_get_values(ldap,res,"version");
+ if(vals!=NULL)
+ {
+ fprintf(console,"Version:\t%s\n",vals[0]);
+ ldap_value_free(vals);
+ }
+ }
+
+ /* This is always "OU=ACTIVE,O=PGP KEYSPACE,C=US", but it might not
+ be in the future. */
+
+ vals=ldap_get_values(ldap,res,"basekeyspacedn");
+ if(vals!=NULL)
+ {
+ basekeyspacedn=strdup(vals[0]);
+ if(basekeyspacedn==NULL)
+ {
+ fprintf(console,"gpg: Can't allocate string space for LDAP base\n");
+ goto fail;
+ }
+
+ ldap_value_free(vals);
+ }
+
+ switch(action)
+ {
+ case GET:
+ keyptr=keylist;
+
+ while(keyptr->keystr!=NULL)
+ {
+ struct keylist *current=keyptr;
+
+ get_key(ldap,current->keystr);
+
+ keyptr=current->next;
+
+ /* Free it as we go */
+ free(current->keystr);
+ free(current);
+ }
+ break;
+
+ case SEND:
+ {
+ char keyid[17]="????";
+ int ret;
+
+ while((ret=send_key(ldap,keyid))!=1)
+ {
+ if(ret!=0)
+ fprintf(output,"KEY %s FAILED\n",keyid);
+ }
+ }
+ break;
+
+ case SEARCH:
+ {
+ char *searchkey=NULL;
+ int len=0;
+
+ /* To search, we stick a * in between each key to search for.
+ This means that if the user enters words, they'll get
+ "enters*words". If the user "enters words", they'll get
+ "enters words" */
+
+ keyptr=keylist;
+ while(keyptr->keystr!=NULL)
+ {
+ len+=strlen(keyptr->keystr)+1;
+ keyptr=keyptr->next;
+ }
+
+ searchkey=malloc(len+1);
+ if(searchkey==NULL)
+ goto fail;
+
+ searchkey[0]='\0';
+
+ keyptr=keylist;
+ while(keyptr->keystr!=NULL)
+ {
+ struct keylist *current=keyptr;
+
+ strcat(searchkey,current->keystr);
+ strcat(searchkey,"*");
+ keyptr=current->next;
+
+ /* Free it as we go */
+ free(current->keystr);
+ free(current);
+ }
+
+ /* Nail that last "*" */
+ searchkey[strlen(searchkey)-1]='\0';
+
+ if(search_key(ldap,searchkey)==-1)
+ fprintf(output,"SEARCH %s FAILED\n",searchkey);
+
+ free(searchkey);
+ }
+
+ break;
+ }
+
+ ret=KEYSERVER_OK;
+
+ fail:
+
+ if(ldap!=NULL)
+ ldap_unbind_s(ldap);
+
+ free(basekeyspacedn);
+
+ return ret;
+}