# HG changeset patch # User Julian Pullen # Date 1254488631 -3600 # Node ID c76698327301d0d3a6ad4e76313b2fe73c216c78 # Parent ecc602d2d4976b435647cf2446a911d2ede6d30a 6822695 libadutils does not setup the mutlti threading routines for using LDAP (libldap5) diff -r ecc602d2d497 -r c76698327301 usr/src/lib/libadutils/Makefile.com --- a/usr/src/lib/libadutils/Makefile.com Thu Oct 01 15:01:08 2009 -0700 +++ b/usr/src/lib/libadutils/Makefile.com Fri Oct 02 14:03:51 2009 +0100 @@ -25,18 +25,21 @@ LIBRARY = libadutils.a VERS = .1 -OBJECTS = adutils.o addisc.o -LINT_OBJECTS = adutils.o addisc.o +OBJECTS = adutils.o addisc.o adutils_threadfuncs.o +LINT_OBJECTS = adutils.o addisc.o adutils_threadfuncs.o include ../../Makefile.lib +C99MODE= -xc99=%all +C99LMODE= -Xc99=%all + LIBS = $(DYNLIB) $(LINTLIB) LDLIBS += -lc -lldap -lresolv -lsocket -lnsl SRCDIR = ../common $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) CFLAGS += $(CCVERBOSE) -CPPFLAGS += -D_REENTRANT -I$(SRCDIR) +CPPFLAGS += -D_REENTRANT -I$(SRCDIR) -I$(SRC)/lib/libldap5/include/ldap lint := OBJECTS = $(LINT_OBJECTS) diff -r ecc602d2d497 -r c76698327301 usr/src/lib/libadutils/common/addisc.c --- a/usr/src/lib/libadutils/common/addisc.c Thu Oct 01 15:01:08 2009 -0700 +++ b/usr/src/lib/libadutils/common/addisc.c Fri Oct 02 14:03:51 2009 +0100 @@ -834,7 +834,6 @@ ldversion = LDAP_VERSION3; (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion); - (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); @@ -845,6 +844,14 @@ (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); + rc = adutils_set_thread_functions(ld); + if (rc != LDAP_SUCCESS) { + /* Error has already been logged */ + (void) ldap_unbind(ld); + ld = NULL; + continue; + } + rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, saslmech, NULL, NULL, saslflags, &saslcallback, NULL /* defaults */); diff -r ecc602d2d497 -r c76698327301 usr/src/lib/libadutils/common/adutils.c --- a/usr/src/lib/libadutils/common/adutils.c Thu Oct 01 15:01:08 2009 -0700 +++ b/usr/src/lib/libadutils/common/adutils.c Fri Oct 02 14:03:51 2009 +0100 @@ -615,6 +615,15 @@ (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); + + rc = adutils_set_thread_functions(adh->ld); + if (rc != LDAP_SUCCESS) { + /* Error has already been logged */ + (void) ldap_unbind(adh->ld); + adh->ld = NULL; + goto out; + } + rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */, adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback, NULL); diff -r ecc602d2d497 -r c76698327301 usr/src/lib/libadutils/common/adutils_impl.h --- a/usr/src/lib/libadutils/common/adutils_impl.h Thu Oct 01 15:01:08 2009 -0700 +++ b/usr/src/lib/libadutils/common/adutils_impl.h Fri Oct 02 14:03:51 2009 +0100 @@ -155,6 +155,8 @@ int saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts); +int adutils_set_thread_functions(LDAP *ld); + /* Global logger function */ extern adutils_logger logger; diff -r ecc602d2d497 -r c76698327301 usr/src/lib/libadutils/common/adutils_threadfuncs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libadutils/common/adutils_threadfuncs.c Fri Oct 02 14:03:51 2009 +0100 @@ -0,0 +1,276 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Functions for managing thread-local storage for LDAP, and in particular + * for managing storage of the LDAP error state. + */ + +#include +#include +#include +#include +#include +#include +#include "solaris-int.h" /* This is a libladp5 private include file */ + /* which has the defintion for */ + /* struct ldap_extra_thread_fns */ +#include "adutils_impl.h" + +struct adutils_lderrno { + int le_errno; + char *le_matched; + char *le_errmsg; +}; + +static void *adutils_mutex_alloc(void); +static void adutils_mutex_free(void *mutexp); +static int adutils_get_errno(void); +static void adutils_set_errno(int err); +static void adutils_set_lderrno(int err, char *matched, char *errmsg, + void *dummy); +static int adutils_get_lderrno(char **matched, char **errmsg, void *dummy); +static void adutils_lderrno_destructor(void *tsd); + +static pthread_key_t adutils_lderrno_key = PTHREAD_ONCE_KEY_NP; + +static struct ldap_thread_fns thread_fns = { + .ltf_mutex_alloc = adutils_mutex_alloc, + .ltf_mutex_free = adutils_mutex_free, + .ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock, + .ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock, + .ltf_get_errno = adutils_get_errno, + .ltf_set_errno = adutils_set_errno, + .ltf_get_lderrno = adutils_get_lderrno, + .ltf_set_lderrno = adutils_set_lderrno, + .ltf_lderrno_arg = NULL +}; + +struct ldap_extra_thread_fns extra_thread_fns = { + .ltf_threadid_fn = (void * (*)(void))pthread_self +}; + + +/* + * Set up thread management functions for the specified LDAP session. + * Returns either LDAP_SUCCESS or -1. + */ +int +adutils_set_thread_functions(LDAP *ld) +{ + int rc; + + if (adutils_lderrno_key == PTHREAD_ONCE_KEY_NP) { + if ((rc = pthread_key_create_once_np(&adutils_lderrno_key, + adutils_lderrno_destructor)) != 0) { + logger(LOG_ERR, "adutils_set_thread_functions() " + "pthread_key_create_once_np failed (%s)", + strerror(rc)); + rc = -1; + return (rc); + } + } + + rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS, + &thread_fns); + if (rc != LDAP_SUCCESS) { + logger(LOG_ERR, + "ldap_set_option LDAP_OPT_THREAD_FN_PTRS failed"); + return (rc); + } + + rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS, + &extra_thread_fns); + if (rc != LDAP_SUCCESS) { + logger(LOG_ERR, + "ldap_set_option LDAP_OPT_EXTRA_THREAD_FN_PTRS failed"); + return (rc); + } + return (rc); +} + +/* + * Allocate a mutex. + */ +static +void * +adutils_mutex_alloc(void) +{ + pthread_mutex_t *mutexp; + int rc; + + mutexp = malloc(sizeof (pthread_mutex_t)); + if (mutexp == NULL) { + logger(LOG_ERR, + "adutils_mutex_alloc: malloc failed (%s)", + strerror(errno)); + return (NULL); + } + + rc = pthread_mutex_init(mutexp, NULL); + if (rc != 0) { + logger(LOG_ERR, + "adutils_mutex_alloc: " + "pthread_mutex_init failed (%s)", + strerror(rc)); + free(mutexp); + return (NULL); + } + return (mutexp); +} + +/* + * Free a mutex. + */ +static +void +adutils_mutex_free(void *mutexp) +{ + (void) pthread_mutex_destroy((pthread_mutex_t *)mutexp); + free(mutexp); +} + +/* + * Get the thread's local errno. + */ +static +int +adutils_get_errno(void) +{ + return (errno); +} + +/* + * Set the thread's local errno. + */ +static +void +adutils_set_errno(int err) +{ + errno = err; +} + +/* + * Get a pointer to the thread's local LDAP error state structure. + * Lazily allocate the thread-local storage, so that we don't need + * initialization when each thread starts. + */ +static +struct adutils_lderrno * +adutils_get_lderrno_struct(void) +{ + struct adutils_lderrno *le; + int rc; + + le = pthread_getspecific(adutils_lderrno_key); + if (le == NULL) { + le = calloc(1, sizeof (*le)); + if (le == NULL) { + logger(LOG_ERR, + "adutils_get_lderrno_struct: calloc failed (%s)", + strerror(errno)); + return (NULL); + } + rc = pthread_setspecific(adutils_lderrno_key, le); + if (rc != 0) { + logger(LOG_ERR, + "adutils_get_lderrno_struct: " + "pthread_setspecific failed (%s)", + strerror(rc)); + free(le); + return (NULL); + } + } + + return (le); +} + +/* + * Store an error report in the thread's local LDAP error state structure. + */ +static +void +adutils_set_lderrno(int err, char *matched, char *errmsg, void *dummy) +{ + NOTE(ARGUNUSED(dummy)) + struct adutils_lderrno *le; + + le = adutils_get_lderrno_struct(); + if (le != NULL) { + le->le_errno = err; + if (le->le_matched != NULL) + ldap_memfree(le->le_matched); + le->le_matched = matched; + if (le->le_errmsg != NULL) + ldap_memfree(le->le_errmsg); + le->le_errmsg = errmsg; + } +} + +/* + * Retrieve an error report from the thread's local LDAP error state structure. + */ +static +int +adutils_get_lderrno(char **matched, char **errmsg, void *dummy) +{ + NOTE(ARGUNUSED(dummy)) + struct adutils_lderrno *le; + static struct adutils_lderrno empty = { LDAP_SUCCESS, NULL, NULL }; + + le = adutils_get_lderrno_struct(); + if (le == NULL) + le = ∅ + + if (matched != NULL) + *matched = le->le_matched; + if (errmsg != NULL) + *errmsg = le->le_errmsg; + return (le->le_errno); +} + +/* + * Free the thread's local LDAP error state structure. + */ +static +void +adutils_lderrno_destructor(void *tsd) +{ + struct adutils_lderrno *le = tsd; + + if (le == NULL) + return; + + if (le->le_matched != NULL) { + ldap_memfree(le->le_matched); + le->le_matched = NULL; + } + if (le->le_errmsg != NULL) { + ldap_memfree(le->le_errmsg); + le->le_errmsg = NULL; + } + free(le); +}