summaryrefslogtreecommitdiff
path: root/nslcd/ldap-nss.c
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2007-10-28 12:37:20 +0000
committerArthur de Jong <arthur@arthurdejong.org>2007-10-28 12:37:20 +0000
commitfdc5b7c137ba199f1ee2efd4daa151957d8691d3 (patch)
tree6c1ddc1889d9a942843ec58ee6d448419bb7315e /nslcd/ldap-nss.c
parent5bce1be447b864ba6e788754c71d479a8aedc9e3 (diff)
replace calls to _nss_ldap_get_values() by myldap_get_values(), remove unused functions, remove struct ldap_state and replace remaining references to context to use search instead
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-ldapd@470 ef36b2f9-881f-0410-afb5-c4e39611909c
Diffstat (limited to 'nslcd/ldap-nss.c')
-rw-r--r--nslcd/ldap-nss.c421
1 files changed, 76 insertions, 345 deletions
diff --git a/nslcd/ldap-nss.c b/nslcd/ldap-nss.c
index a088216..84b1380 100644
--- a/nslcd/ldap-nss.c
+++ b/nslcd/ldap-nss.c
@@ -76,9 +76,15 @@
#include "common/dict.h"
/*
- * LS_INIT only used for enumeration contexts
+ * thread specific context: result chain, and state data
*/
-#define LS_INIT(state) do { state.ls_type = LS_TYPE_INDEX; state.ls_retry = 0; state.ls_info.ls_index = -1; } while (0)
+struct ent_context
+{
+ MYLDAP_SESSION *session; /* the connection to the LDAP server */
+ int ec_msgid; /* message ID */
+ LDAPMessage *ec_res; /* result chain */
+ struct berval *ec_cookie; /* cookie for paged searches */
+};
/* the maximum number of searches per session */
#define MAX_SEARCHES_IN_SESSION 4
@@ -229,7 +235,10 @@ static MYLDAP_SEARCH *myldap_search_new(
}
search->attrs[i]=NULL;
/* initialize context */
- _nss_ldap_ent_context_init(&(search->context),session);
+ search->context.session=session;
+ search->context.ec_cookie=NULL;
+ search->context.ec_res=NULL;
+ search->context.ec_msgid=-1;
/* clear result entry */
search->entry=NULL;
/* return the new search struct */
@@ -241,8 +250,12 @@ static void myldap_search_free(MYLDAP_SEARCH *search)
/* free any search entries */
if (search->entry!=NULL)
myldap_entry_free(search->entry);
- /* free the context */
- _nss_ldap_ent_context_cleanup(&(search->context));
+ /* free read messages */
+ if (search->context.ec_res!=NULL)
+ ldap_msgfree(search->context.ec_res);
+ /* clean up cookie */
+ if (search->context.ec_cookie!=NULL)
+ ber_bvfree(search->context.ec_cookie);
/* free the storage we allocated */
free(search);
}
@@ -602,7 +615,7 @@ static int do_open(MYLDAP_SESSION *session)
* Wrapper around ldap_result() to skip over search references
* and deal transparently with the last entry.
*/
-static enum nss_status do_result_async(struct ent_context *context)
+static enum nss_status do_result_async(MYLDAP_SEARCH *search)
{
int rc = LDAP_UNAVAILABLE;
enum nss_status stat = NSS_STATUS_TRYAGAIN;
@@ -621,17 +634,17 @@ static enum nss_status do_result_async(struct ent_context *context)
do
{
- if (context->ec_res!=NULL)
+ if (search->context.ec_res!=NULL)
{
- ldap_msgfree(context->ec_res);
- context->ec_res=NULL;
+ ldap_msgfree(search->context.ec_res);
+ search->context.ec_res=NULL;
}
- rc=ldap_result(context->session->ls_conn,context->ec_msgid,LDAP_MSG_ONE,tvp,&(context->ec_res));
+ rc=ldap_result(search->session->ls_conn,search->context.ec_msgid,LDAP_MSG_ONE,tvp,&(search->context.ec_res));
switch (rc)
{
case -1:
case 0:
- if (ldap_get_option(context->session->ls_conn,LDAP_OPT_ERROR_NUMBER,&rc)!=LDAP_SUCCESS)
+ if (ldap_get_option(search->session->ls_conn,LDAP_OPT_ERROR_NUMBER,&rc)!=LDAP_SUCCESS)
rc=LDAP_UNAVAILABLE;
log_log(LOG_ERR,"could not get LDAP result: %s",ldap_err2string(rc));
stat=NSS_STATUS_UNAVAIL;
@@ -642,31 +655,31 @@ static enum nss_status do_result_async(struct ent_context *context)
case LDAP_RES_SEARCH_RESULT:
/* NB: this frees context->ec_res */
resultControls=NULL;
- if (context->ec_cookie!=NULL)
- ber_bvfree(context->ec_cookie);
- context->ec_cookie=NULL;
- parserc=ldap_parse_result(context->session->ls_conn,context->ec_res,&rc,NULL,
+ if (search->context.ec_cookie!=NULL)
+ ber_bvfree(search->context.ec_cookie);
+ search->context.ec_cookie=NULL;
+ parserc=ldap_parse_result(search->session->ls_conn,search->context.ec_res,&rc,NULL,
NULL,NULL,&resultControls,1);
if ((parserc!=LDAP_SUCCESS)&&(parserc!=LDAP_MORE_RESULTS_TO_RETURN))
{
stat = NSS_STATUS_UNAVAIL;
- ldap_abandon(context->session->ls_conn, context->ec_msgid);
+ ldap_abandon(search->session->ls_conn,search->context.ec_msgid);
log_log(LOG_ERR,"could not get LDAP result: %s",ldap_err2string(rc));
}
else if (resultControls!=NULL)
{
/* See if there are any more pages to come */
- parserc=ldap_parse_page_control(context->session->ls_conn,
+ parserc=ldap_parse_page_control(search->session->ls_conn,
resultControls,NULL,
- &(context->ec_cookie));
+ &(search->context.ec_cookie));
/* TODO: handle the above return code?? */
ldap_controls_free(resultControls);
stat=NSS_STATUS_NOTFOUND;
}
else
stat=NSS_STATUS_NOTFOUND;
- context->ec_res=NULL;
- context->ec_msgid=-1;
+ search->context.ec_res=NULL;
+ search->context.ec_msgid=-1;
break;
default:
stat = NSS_STATUS_UNAVAIL;
@@ -677,55 +690,12 @@ static enum nss_status do_result_async(struct ent_context *context)
/* update timestamp on success */
if (stat==NSS_STATUS_SUCCESS)
- time(&(context->session->ls_timestamp));
+ time(&(search->session->ls_timestamp));
return stat;
}
/*
- * This function initializes an enumeration context.
- *
- * It could be done from the default constructor, under Solaris, but we
- * delay it until the setXXent() function is called.
- */
-void _nss_ldap_ent_context_init(struct ent_context *context,MYLDAP_SESSION *session)
-{
- context->session=session;
- context->ec_cookie=NULL;
- context->ec_res=NULL;
- context->ec_msgid=-1;
- LS_INIT(context->ec_state);
-}
-
-/*
- * Clears a given context.
- */
-void _nss_ldap_ent_context_cleanup(struct ent_context *context)
-{
- if (context==NULL)
- return;
- /* abandon the search if there were more results to fetch */
- if ((context->ec_msgid>-1)&&(do_result_async(context)==NSS_STATUS_SUCCESS))
- {
- ldap_abandon(context->session->ls_conn,context->ec_msgid);
- context->ec_msgid=-1;
- }
- /* free read messages */
- if (context->ec_res!=NULL)
- {
- ldap_msgfree(context->ec_res);
- context->ec_res=NULL;
- }
- /* clean up cookie */
- if (context->ec_cookie!=NULL)
- {
- ber_bvfree(context->ec_cookie);
- context->ec_cookie=NULL;
- }
- LS_INIT(context->ec_state);
-}
-
-/*
* Synchronous search function. Don't call this directly;
* always wrap calls to this with do_with_reconnect(), or,
* better still, use _nss_ldap_search().
@@ -888,34 +858,6 @@ static enum nss_status do_with_reconnect(
}
}
-/*
- * Simple wrapper around ldap_get_values(). Requires that
- * session is already established.
- */
-char **_nss_ldap_get_values(MYLDAP_ENTRY *entry,
- const char *attr)
-{
- if (!entry->search->session->is_connected)
- return NULL;
- assert(entry->search->session->ls_conn!=NULL);
- return ldap_get_values(entry->search->session->ls_conn,entry->msg,attr);
-}
-
-/* translates a nslcd return code (as defined in nslcd.h) to
- a nss code (as defined in nss.h) */
-/* FIXME: this is a temporary hack, get rid of it */
-static int nss2nslcd(enum nss_status code)
-{
- switch (code)
- {
- case NSS_STATUS_UNAVAIL: return NSLCD_RESULT_UNAVAIL;
- case NSS_STATUS_NOTFOUND: return NSLCD_RESULT_NOTFOUND;
- case NSS_STATUS_SUCCESS: return NSLCD_RESULT_SUCCESS;
-/* case NSS_STATUS_TRYAGAIN: return NSLCD_RS_SMALLBUF; */
- default: return NSLCD_RESULT_UNAVAIL;
- }
-}
-
MYLDAP_SESSION *myldap_create_session(void)
{
return myldap_session_new();
@@ -982,6 +924,9 @@ void myldap_search_close(MYLDAP_SEARCH *search)
int i;
if ((search==NULL)||(search->session==NULL))
return;
+ /* abandon the search if there were more results to fetch */
+ if ((search->context.ec_msgid>-1)&&(do_result_async(search)==NSS_STATUS_SUCCESS))
+ ldap_abandon(search->session->ls_conn,search->context.ec_msgid);
/* find the reference to this search in the session */
for (i=0;i<MAX_SEARCHES_IN_SESSION;i++)
{
@@ -1015,7 +960,7 @@ MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search)
{
/* get an entry from the LDAP server, the result
is stored in context->ec_res */
- stat=do_result_async(&(search->context));
+ stat=do_result_async(search);
/* we we have an entry construct a search entry from it */
if (stat==NSS_STATUS_SUCCESS)
{
@@ -1250,146 +1195,6 @@ int myldap_has_objectclass(MYLDAP_ENTRY *entry,const char *objectclass)
}
/*
- * Internal entry point for enumeration routines.
- * This should really use the asynchronous LDAP search API to avoid
- * pulling down all the entries at once, particularly if the
- * enumeration is not completed.
- */
-int _nss_ldap_getent(
- struct ent_context *context,void *result,char *buffer,size_t buflen,
- const char *base,int scope,const char *filter,const char **attrs,
- parser_t parser)
-{
- enum nss_status stat=NSS_STATUS_SUCCESS;
- int msgid=-1;
- log_log(LOG_DEBUG,"_nss_ldap_getent(base=\"%s\", filter=\"%s\")",base,filter);
- /* if context->ec_msgid < 0, then we haven't searched yet */
- if (context->ec_msgid<0)
- {
- /* set up a new search */
- stat=do_with_reconnect(context->session,base,scope,filter,(char **)attrs,LDAP_NO_LIMIT,NULL,&msgid);
- if (stat != NSS_STATUS_SUCCESS)
- return nss2nslcd(stat);
- context->ec_msgid=msgid;
- }
- /* try to parse results until we have a final error or ok */
- while (1)
- {
- /*
- * Tries parser function "parser" on entries, calling do_result_async()
- * to retrieve them from the LDAP server until one parses
- * correctly or there is an exceptional condition.
- */
- stat=NSS_STATUS_NOTFOUND;
- /*
- * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
- * entry off the LDAP chain, and instead refeed the existing result to
- * the parser. Once the parser has finished with it, it will return
- * NSS_STATUS_NOTFOUND and reset the index to -1, at which point we'll retrieve
- * another entry.
- */
- do
- {
- enum nss_status resultStat=NSS_STATUS_SUCCESS;
- /* get an entry from the LDAP server */
- if ((context->ec_state.ls_retry==0) &&
- ( (context->ec_state.ls_type==LS_TYPE_KEY) ||
- (context->ec_state.ls_info.ls_index==-1) ))
- {
- resultStat=do_result_async(context);
- if (resultStat!=NSS_STATUS_SUCCESS)
- {
- stat=resultStat;
- break;
- }
- }
- /*
- * We have an entry; now, try to parse it.
- *
- * If we do not parse the entry because of a schema
- * violation, the parser should return NSS_STATUS_NOTFOUND.
- * We'll keep on trying subsequent entries until we
- * find one which is parseable, or exhaust avialable
- * entries, whichever is first.
- */
- stat=parser(context->session,context->ec_res,&(context->ec_state),result,buffer,buflen);
-
- /* hold onto the state if we're out of memory XXX */
- context->ec_state.ls_retry=(stat==NSS_STATUS_TRYAGAIN)&&(buffer!=NULL);
-
- /* free entry is we're moving on */
- if ((context->ec_state.ls_retry==0) &&
- ( (context->ec_state.ls_type==LS_TYPE_KEY) ||
- (context->ec_state.ls_info.ls_index==-1) ))
- {
- /* we don't need the result anymore, ditch it. */
- ldap_msgfree(context->ec_res);
- context->ec_res=NULL;
- }
- }
- while (stat==NSS_STATUS_NOTFOUND);
- /* if this had no more results, try the next page */
- if ((stat==NSS_STATUS_NOTFOUND)&&(context->ec_cookie!=NULL)&&(context->ec_cookie->bv_len!=0))
- {
- LDAPControl *serverctrls[2]={ NULL, NULL };
- stat=ldap_create_page_control(context->session->ls_conn,
- nslcd_cfg->ldc_pagesize,
- context->ec_cookie,0,&serverctrls[0]);
- if (stat!=LDAP_SUCCESS)
- return NSS_STATUS_UNAVAIL;
- stat=ldap_search_ext(context->session->ls_conn,
- base,scope,filter,
- (char **)attrs,0,serverctrls,NULL,LDAP_NO_LIMIT,
- LDAP_NO_LIMIT,&msgid);
- ldap_control_free(serverctrls[0]);
- if (msgid<0)
- return nss2nslcd(NSS_STATUS_UNAVAIL);
- context->ec_msgid=msgid;
- }
- else
- return nss2nslcd(stat);
- }
-}
-
-/*
- * General match function.
- */
-int _nss_ldap_getbyname(MYLDAP_SESSION *session,void *result, char *buffer, size_t buflen,
- const char *base,int scope,const char *filter,const char **attrs,
- parser_t parser)
-{
- MYLDAP_SEARCH *search;
- MYLDAP_ENTRY *entry;
- enum nss_status stat=NSS_STATUS_NOTFOUND;
- /* do the search */
- search=myldap_search(session,base,scope,filter,attrs);
- if (search==NULL)
- return NSLCD_RESULT_UNAVAIL;
- /*
- * we pass this along for the benefit of the services parser,
- * which uses it to figure out which protocol we really wanted.
- * we only pass the second argument along, as that's what we need
- * in services.
- */
- search->context.ec_state.ls_type=LS_TYPE_KEY;
- search->context.ec_state.ls_info.ls_key=NULL /*was: args->la_arg2.la_string*/;
- do
- {
- entry = myldap_get_entry(search);
- if (entry!=NULL)
- {
- stat=parser(session,entry->msg,&(search->context.ec_state),result,buffer,buflen);
- /* hold onto the state if we're out of memory XXX */
- search->context.ec_state.ls_retry=(stat==NSS_STATUS_TRYAGAIN)&&(buffer!=NULL);
- }
- }
- while ((stat==NSS_STATUS_NOTFOUND)&&(entry!=NULL));
- /* clean up this search */
- myldap_search_close(search);
- return nss2nslcd(stat);
-}
-
-/*
* These functions are called from within the parser, where it is assumed
* to be safe to use the connection and the respective message.
*/
@@ -1402,8 +1207,8 @@ enum nss_status _nss_ldap_assign_attrvals(
const char *attr,const char *omitvalue,
char ***valptr,char **pbuffer,size_t *pbuflen,size_t *pvalcount)
{
- char **vals;
- char **valiter;
+ const char **vals;
+ const char **valiter;
size_t valcount;
char **p=NULL;
@@ -1416,12 +1221,11 @@ enum nss_status _nss_ldap_assign_attrvals(
if (entry->search->session->ls_conn==NULL)
return NSS_STATUS_UNAVAIL;
- vals=_nss_ldap_get_values(entry,attr);
+ vals=myldap_get_values(entry,attr);
- valcount=(vals==NULL)?0:ldap_count_values(vals);
+ valcount=myldap_count_values(vals);
if (bytesleft(buffer,buflen,char *)<(valcount+1)*sizeof(char *))
{
- ldap_value_free(vals);
return NSS_STATUS_TRYAGAIN;
}
@@ -1453,7 +1257,6 @@ enum nss_status _nss_ldap_assign_attrvals(
vallen=strlen(*valiter);
if (buflen<(vallen+1))
{
- ldap_value_free(vals);
return NSS_STATUS_TRYAGAIN;
}
@@ -1477,7 +1280,6 @@ enum nss_status _nss_ldap_assign_attrvals(
if (pvalcount!=NULL)
*pvalcount=valcount;
- ldap_value_free(vals);
return NSS_STATUS_SUCCESS;
}
@@ -1486,17 +1288,16 @@ enum nss_status _nss_ldap_assign_attrval(
MYLDAP_ENTRY *entry,const char *attr,char **valptr,
char **buffer,size_t *buflen)
{
- char **vals;
+ const char **vals;
int vallen;
if (entry->search->session->ls_conn==NULL)
return NSS_STATUS_UNAVAIL;
- vals=_nss_ldap_get_values(entry,attr);
- if (vals==NULL)
+ vals=myldap_get_values(entry,attr);
+ if ((vals==NULL)||(vals[0]==NULL))
return NSS_STATUS_NOTFOUND;
- vallen=strlen(*vals);
+ vallen=strlen(vals[0]);
if (*buflen<(size_t)(vallen+1))
{
- ldap_value_free(vals);
return NSS_STATUS_TRYAGAIN;
}
*valptr=*buffer;
@@ -1504,15 +1305,14 @@ enum nss_status _nss_ldap_assign_attrval(
(*valptr)[vallen]='\0';
*buffer+=vallen + 1;
*buflen-=vallen + 1;
- ldap_value_free(vals);
return NSS_STATUS_SUCCESS;
}
-static const char *_nss_ldap_locate_userpassword(char **vals)
+static const char *_nss_ldap_locate_userpassword(const char **vals)
{
const char *token=NULL;
size_t token_length=0;
- char **valiter;
+ const char **valiter;
const char *pwd=NULL;
if (nslcd_cfg!=NULL)
@@ -1563,19 +1363,17 @@ enum nss_status _nss_ldap_assign_userpassword(
const char *attr,char **valptr,
char **buffer,size_t *buflen)
{
- char **vals;
+ const char **vals;
const char *pwd;
int vallen;
log_log(LOG_DEBUG,"==> _nss_ldap_assign_userpassword");
if (entry->search->session->ls_conn==NULL)
return NSS_STATUS_UNAVAIL;
- vals=_nss_ldap_get_values(entry,attr);
+ vals=myldap_get_values(entry,attr);
pwd=_nss_ldap_locate_userpassword(vals);
vallen=strlen(pwd);
if (*buflen<(size_t)(vallen+1))
{
- if (vals!=NULL)
- ldap_value_free(vals);
log_log(LOG_DEBUG,"<== _nss_ldap_assign_userpassword");
return NSS_STATUS_TRYAGAIN;
}
@@ -1584,113 +1382,46 @@ enum nss_status _nss_ldap_assign_userpassword(
(*valptr)[vallen]='\0';
*buffer+=vallen+1;
*buflen-=vallen+1;
- if (vals!=NULL)
- ldap_value_free(vals);
log_log(LOG_DEBUG,"<== _nss_ldap_assign_userpassword");
return NSS_STATUS_SUCCESS;
}
-static enum nss_status do_getrdnvalue(
- const char *dn,const char *rdntype,
+enum nss_status _nss_ldap_getrdnvalue(
+ MYLDAP_ENTRY *entry,const char *rdntype,
char **rval,char **buffer,size_t *buflen)
{
- char **exploded_dn;
- char *rdnvalue=NULL;
- char rdnava[64];
- size_t rdnlen=0,rdnavalen;
-
- snprintf(rdnava,sizeof(rdnava),"%s=",rdntype);
- rdnavalen=strlen(rdnava);
-
- exploded_dn=ldap_explode_dn(dn,0);
+ size_t rdnlen;
+ const char *rdnval;
+ const char **vals;
- if (exploded_dn!=NULL)
+ rdnval=myldap_get_rdn_value(entry,rdntype);
+ if (rdnval==NULL)
{
/*
- * attempt to get the naming attribute's principal
- * value by parsing the RDN. We need to support
- * multivalued RDNs (as they're essentially mandated
- * for services)
+ * If examining the DN failed, then pick the nominal first
+ * value of cn as the canonical name (recall that attributes
+ * are sets, not sequences)
*/
- char **p, **exploded_rdn;
- exploded_rdn=ldap_explode_rdn(*exploded_dn,0);
- if (exploded_rdn!=NULL)
- {
- for (p=exploded_rdn;*p!=NULL;p++)
- {
- if (strncasecmp(*p,rdnava,rdnavalen) == 0)
- {
- char *r=*p+rdnavalen;
- rdnlen=strlen(r);
- if (*buflen<=rdnlen)
- {
- ldap_value_free(exploded_rdn);
- ldap_value_free(exploded_dn);
- return NSS_STATUS_TRYAGAIN;
- }
- rdnvalue=*buffer;
- strncpy(rdnvalue,r,rdnlen);
- break;
- }
- }
- ldap_value_free(exploded_rdn);
- }
+ vals=myldap_get_values(entry,rdntype);
+ if ((vals==NULL)||(vals[0]==NULL))
+ return NSS_STATUS_NOTFOUND;
+ rdnval=vals[0];
}
- if (exploded_dn!=NULL)
- ldap_value_free (exploded_dn);
-
- if (rdnvalue!=NULL)
- return NSS_STATUS_NOTFOUND;
-
- rdnvalue[rdnlen]='\0';
- *buffer+=rdnlen+1;
- *buflen-=rdnlen+1;
- *rval=rdnvalue;
- return NSS_STATUS_SUCCESS;
-}
-
-enum nss_status _nss_ldap_getrdnvalue(
- MYLDAP_ENTRY *entry,const char *rdntype,
- char **rval,char **buffer,size_t *buflen)
-{
- const char *dn;
- enum nss_status status;
- size_t rdnlen;
-
- dn=myldap_get_dn(entry);
- if (dn==NULL)
- return NSS_STATUS_NOTFOUND;
- status=do_getrdnvalue(dn,rdntype,rval,buffer,buflen);
-
- /*
- * If examining the DN failed, then pick the nominal first
- * value of cn as the canonical name (recall that attributes
- * are sets, not sequences)
- */
- if (status==NSS_STATUS_NOTFOUND)
+ /* copy the value into the destination buffer */
+ rdnlen = strlen(rdnval);
+ if (*buflen > rdnlen)
{
- char **vals;
- vals=_nss_ldap_get_values(entry,rdntype);
- if (vals != NULL)
- {
- rdnlen = strlen (*vals);
- if (*buflen > rdnlen)
- {
- char *rdnvalue = *buffer;
- strncpy (rdnvalue, *vals, rdnlen);
- rdnvalue[rdnlen] = '\0';
- *buffer += rdnlen + 1;
- *buflen -= rdnlen + 1;
- *rval = rdnvalue;
- status = NSS_STATUS_SUCCESS;
- }
- else
- status=NSS_STATUS_TRYAGAIN;
- ldap_value_free (vals);
- }
+ char *rdnvalue=*buffer;
+ strncpy(rdnvalue,rdnval,rdnlen);
+ rdnvalue[rdnlen] = '\0';
+ *buffer += rdnlen + 1;
+ *buflen -= rdnlen + 1;
+ *rval = rdnvalue;
+ return NSS_STATUS_SUCCESS;
}
- return status;
+ else
+ return NSS_STATUS_TRYAGAIN;
}
int myldap_escape(const char *src,char *buffer,size_t buflen)