diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /ldapaddressbook/libldapsearch.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'ldapaddressbook/libldapsearch.c')
| -rw-r--r-- | ldapaddressbook/libldapsearch.c | 449 | 
1 files changed, 449 insertions, 0 deletions
| diff --git a/ldapaddressbook/libldapsearch.c b/ldapaddressbook/libldapsearch.c new file mode 100644 index 0000000..71ef2ed --- /dev/null +++ b/ldapaddressbook/libldapsearch.c @@ -0,0 +1,449 @@ +/* +** Copyright 2006, Double Precision Inc. +** +** See COPYING for distribution information. +*/ + +#include "libldapsearch.h" +#include <stdlib.h> +#include <errno.h> +#include <time.h> +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +#  include <sys/time.h> +# else +#  include <time.h> +# endif +#endif + +/* +** Allocate and deallocate the ldapsearch struct. +*/ + +struct ldapsearch *l_search_alloc(const char *host, +				  int port, +				  const char *userid, +				  const char *password, +				  const char *base) +{ +	char *buf; + +	struct ldapsearch *p=(struct ldapsearch *) +		malloc(sizeof(struct ldapsearch)); + +	if (!p) +		return NULL; + +	if ((p->base=strdup(base)) == NULL) +	{ +		free(p); +		return NULL; +	} + +	if ((buf=malloc(strlen(host)+100)) == NULL) +	{ +		free(p->base); +		free(p); +		return NULL; +	} + +	sprintf(buf, "ldap://%s:%d", host, port); + +	if (ldap_initialize(&p->handle, buf) != LDAP_SUCCESS) +	{ +		free(buf); +		free(p->base); +		free(p); +		return NULL; +	} +	free(buf); + +	if (userid && *userid) +	{ +		struct berval cred; + +		cred.bv_len=password && *password ? strlen(password):0; +		cred.bv_val=password && *password ? (char *)password:NULL; + +		if (ldap_sasl_bind_s(p->handle, userid, NULL, &cred, NULL, +				     NULL, NULL)) +		{ +			l_search_free(p); +			errno=EPERM; +			return NULL; +		} +	} + +	return p; +} + +void l_search_free(struct ldapsearch *s) +{ +	if (s->handle) +		ldap_unbind_ext(s->handle, NULL, NULL); +	free(s->base); +	free(s); +} + +/* +** See RFC 2254 section 4. +*/ + +static char *encode_key(const char *lookupkey) +{ +	const char *cp; + +	char *p=NULL, *q; +	int pass; +	size_t l=0; + +	for (pass=0; pass<2; pass++) +	{ +		if (pass) +		{ +			p=malloc(l); +			if (!p) +				return NULL; +		} +		l=1; +		q=p; +		for (cp=lookupkey; *cp; cp++) +		{ +			const char *h; + +			switch (*cp) { +			case '*': +				h="\\2a"; +				break; +			case '(': +				h="\\28"; +				break; +			case ')': +				h="\\29"; +				break; +			case '\\': +				h="\\5c"; +				break; +			default: +				if (pass) +					*q++= *cp; +				++l; +				continue; +			} + +			if (pass) +				while ((*q++ = *h++) != 0) +					; +			l += 3; +		} +		if (pass) +			*q=0; +	} +	return p; +} + +/* +** Insert lookup key into the search filter. +*/ + +static char *make_search_key(const char *filter, const char *lookupkey) +{ +	size_t l=strlen(filter)+1; +	char *p, *q; +	const char *cp; + +	for (cp=filter; *cp; cp++) +		if (*cp == '@') +			l += strlen(lookupkey); + +	p=malloc(l); +	if (!p) +		return NULL; + +	for (q=p, cp=filter; *cp; cp++) +	{ +		if (*cp == '@') +		{ +			const char *k=lookupkey; + +			while ( (*q++ = *k++ ) != 0) +				; +			--q; +			continue; +		} +		*q++ = *cp; +	} +	*q=0; +	return p; +} + +static int l_search_do_filter(struct ldapsearch *s, + +			      int (*callback_func)(const char *utf8_name, +						   const char *address, +						   void *callback_arg), +			      void *callback_arg, + +			      const char *filter, +			      const char *lookup_key, +			      int *found); + + +int l_search_do(struct ldapsearch *s, +		const char *lookupkey, + +		int (*callback_func)(const char *utf8_name, +				     const char *address, +				     void *callback_arg), +		void *callback_arg) +{ +	char *k; +	const char *filter; +	int rc_code; +	int found; + +	k=encode_key(lookupkey); +	if (!k) +		return -1; + +	filter=getenv("LDAP_SEARCH_FILTER_EXACT"); +	if (!filter) +		filter="(|(uid=@)(sn=@)(cn=@))"; + +	rc_code=l_search_do_filter(s, callback_func, callback_arg, +				   filter, k, &found); + +	if (rc_code == 0 && !found) +	{ +		filter=getenv("LDAP_SEARCH_FILTER_APPROX"); +		if (!filter) +			filter="(|(uid=@*)(sn=@*)(mail=@*)(cn=@*))"; + +		rc_code=l_search_do_filter(s, callback_func, callback_arg, +					   filter, k, &found); +	} +	free(k); +	return rc_code; +} + +static int l_search_do_filter(struct ldapsearch *s, +			      int (*callback_func)(const char *utf8_name, +						   const char *address, +						   void *callback_arg), +			      void *callback_arg, +			      const char *filter, +			      const char *lookup_key, +			      int *found) +{ +	char *kk; +	struct timeval tv; +	LDAPMessage *result; +	char *attrs[3]; +	int rc_code=0; +	int msgidp; + +	*found=0; + +	kk=make_search_key(filter, lookup_key); + +	if (!kk) +		return -1; + +	if (s->handle == NULL) +	{ +		errno=ETIMEDOUT;  /* Timeout previously */ +		return -1; +	} + + +	attrs[0]="cn"; +	attrs[1]="mail"; +	attrs[2]=NULL; + +	tv.tv_sec=60*60; +	tv.tv_usec=0; + +	if (ldap_search_ext(s->handle, s->base, LDAP_SCOPE_SUBTREE, +			    kk, attrs, 0, NULL, NULL, &tv, 1000000, &msgidp) +	    != LDAP_SUCCESS) +		return -1; + +	do +	{ +		int rc; +		LDAPMessage *msg; + +		const char *timeout=getenv("LDAP_SEARCH_TIMEOUT"); + +		tv.tv_sec=atoi(timeout ? timeout:"30"); +		tv.tv_usec=0; + +		rc=ldap_result(s->handle, msgidp, 0, &tv, &result); + +		if (rc <= 0) +		{ +			if (rc == 0) +				errno=ETIMEDOUT; + +			ldap_unbind_ext(s->handle, NULL, NULL); +			s->handle=NULL; +			rc_code= -1; +			break; +		} + +		if (rc == LDAP_RES_SEARCH_RESULT) +		{ +			ldap_msgfree(result); +			break; /* End of search */ +		} + +		if (rc != LDAP_RES_SEARCH_ENTRY) +		{ +			ldap_msgfree(result); +			continue; +		} + +		for (msg=ldap_first_message(s->handle, result); msg; +		     msg=ldap_next_message(s->handle, msg)) +		{ +			struct berval **n_val= +				ldap_get_values_len(s->handle, msg, "cn"); +			struct berval **a_val= +				ldap_get_values_len(s->handle, msg, "mail"); + +			if (n_val && a_val) +			{ +				size_t i, j; + +				for (i=0; n_val[i]; i++) +					for (j=0; a_val[j]; j++) +					{ +						char *p=malloc(n_val[i]->bv_len +							       +1); +						char *q=malloc(a_val[j]->bv_len +							       +1); + +						if (!p || !q) +						{ +							if (p) free(p); +							if (q) free(q); +							rc_code= -1; +							break; +						} + +						memcpy(p, n_val[i]->bv_val, +						       n_val[i]->bv_len); +						p[n_val[i]->bv_len]=0; + +						memcpy(q, a_val[j]->bv_val, +						       a_val[j]->bv_len); +						q[a_val[j]->bv_len]=0; + +						rc_code=(*callback_func) +							(p, q, callback_arg); +						free(p); +						free(q); +						if (rc_code) +							break; +						*found=1; +					} +			} +			if (n_val) +				ldap_value_free_len(n_val); +			if (a_val) +				ldap_value_free_len(a_val); +		} + +		ldap_msgfree(result); +	} while (rc_code == 0); +	return rc_code; +} + +int l_search_ping(struct ldapsearch *s) +{ +	char *attrs[2]; +	struct timeval tv; +	LDAPMessage *result; +	int rc; +	int msgid; + +	if (s->handle == NULL) +	{ +		errno=ETIMEDOUT;  /* Timeout previously */ +		return -1; +	} + +	attrs[0]="objectClass"; +	attrs[1]=NULL; + +	tv.tv_sec=60*60; +	tv.tv_usec=0; + +	if (ldap_search_ext(s->handle, s->base, LDAP_SCOPE_BASE, +			    "objectClass=*", attrs, 0, NULL, NULL, &tv, +			    1000000, &msgid) < 0) +		return -1; + +	do +	{ +		const char *timeout=getenv("LDAP_SEARCH_TIMEOUT"); + +		tv.tv_sec=atoi(timeout ? timeout:"30"); +		tv.tv_usec=0; + +		rc=ldap_result(s->handle, msgid, 0, &tv, &result); + +		if (rc <= 0) +		{ +			if (rc == 0) +				errno=ETIMEDOUT; + +			ldap_unbind_ext(s->handle, NULL, NULL); +			s->handle=NULL; + +			return -1; +		} + +		ldap_msgfree(result); +	} while (rc != LDAP_RES_SEARCH_RESULT); +	return 0; +} + +#if 0 + +#include <stdio.h> + +static int cb(const char *utf8_name, +	      const char *address, +	      void *callback_arg) +{ +	printf("\"%s\" <%s>\n", utf8_name, address); +	return 0; +} + +int main(int argc, char **argv) +{ +	struct ldapsearch *s=l_search_alloc("localhost", 389, +					    "dc=courier-mta,dc=com"); +	int n; + +	if (!s) +	{ +		perror("l_search_alloc"); +		exit(1); +	} + +	for (n=1; n<argc; n++) +	{ +		if (l_search_do(s, argv[n], cb, NULL) != 0) +		{ +			printf("l_search_do: error\n"); +		} +	} +	l_search_free(s); +	return 0; +} +#endif | 
