summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsldap/common/ns_connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libsldap/common/ns_connect.c')
-rw-r--r--usr/src/lib/libsldap/common/ns_connect.c935
1 files changed, 780 insertions, 155 deletions
diff --git a/usr/src/lib/libsldap/common/ns_connect.c b/usr/src/lib/libsldap/common/ns_connect.c
index ccf75a9963..514c802b34 100644
--- a/usr/src/lib/libsldap/common/ns_connect.c
+++ b/usr/src/lib/libsldap/common/ns_connect.c
@@ -38,6 +38,7 @@
#include <nsswitch.h>
#include <nss_dbdefs.h>
#include "solaris-priv.h"
+#include "solaris-int.h"
#include "ns_sldap.h"
#include "ns_internal.h"
#include "ns_cache_door.h"
@@ -54,8 +55,18 @@ extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip);
static int openConnection(LDAP **, const char *, const ns_cred_t *,
int, ns_ldap_error_t **, int, int);
-
-static mutex_t sessionPoolLock = DEFAULTMUTEX;
+/*
+ * sessionLock, wait4session, sessionTid
+ * are variables to synchronize the creation/retrieval of a connection.
+ * MTperCon is a flag to enable/disable multiple threads sharing the same
+ * connection.
+ * sessionPoolLock is a mutex lock for the connection pool.
+ */
+static mutex_t sessionLock = DEFAULTMUTEX;
+static int wait4session = 0;
+static thread_t sessionTid = 0;
+int MTperConn = 1;
+static rwlock_t sessionPoolLock = DEFAULTRWLOCK;
static Connection **sessionPool = NULL;
static int sessionPoolSize = 0;
@@ -65,10 +76,239 @@ static mutex_t nscdLock = DEFAULTMUTEX;
static int nscdChecked = 0;
static pid_t checkedPid = -1;
static int isNscd = 0;
+/*
+ * SSF values are for SASL integrity & privacy.
+ * JES DS5.2 does not support this feature but DS6 does.
+ * The values between 0 and 65535 can work with both server versions.
+ */
+#define MAX_SASL_SSF 65535
+#define MIN_SASL_SSF 0
/* Number of hostnames to allocate memory for */
#define NUMTOMALLOC 32
+/*
+ * ns_mtckey is for sharing a ldap connection among multiple
+ * threads; created by ns_ldap_init() in ns_init.c
+ */
+extern thread_key_t ns_mtckey;
+
+/* Per thread LDAP error resides in thread-specific data. */
+struct ldap_error {
+ int le_errno;
+ char *le_matched;
+ char *le_errmsg;
+};
+
+/* destructor */
+void
+ns_tsd_cleanup(void *key) {
+ struct ldap_error *le = (struct ldap_error *)key;
+
+ if (le == NULL)
+ return;
+ if (le->le_matched != NULL) {
+ ldap_memfree(le->le_matched);
+ }
+ if (le->le_errmsg != NULL) {
+ ldap_memfree(le->le_errmsg);
+ }
+ free(le);
+}
+
+/* Callback function for allocating a mutex */
+static void *
+ns_mutex_alloc(void)
+{
+ mutex_t *mutexp = NULL;
+
+ if ((mutexp = malloc(sizeof (mutex_t))) != NULL) {
+ if (mutex_init(mutexp, USYNC_THREAD, NULL) != 0) {
+ free(mutexp);
+ mutexp = NULL;
+ }
+ }
+ return (mutexp);
+}
+
+/* Callback function for freeing a mutex */
+static void
+ns_mutex_free(void *mutexp)
+{
+ (void) mutex_destroy((mutex_t *)mutexp);
+ free(mutexp);
+}
+
+/*
+ * Function for setting up thread-specific data
+ * where per thread LDAP error is stored
+ */
+static int
+tsd_setup()
+{
+ void *tsd;
+ int rc;
+
+ /* return success if TSD already set */
+ rc = thr_getspecific(ns_mtckey, &tsd);
+ if (rc == 0 && tsd != NULL)
+ return (0);
+
+ /* allocate and set TSD */
+ tsd = (void *) calloc(1, sizeof (struct ldap_error));
+ if (tsd == NULL)
+ return (-1);
+ rc = thr_setspecific(ns_mtckey, tsd);
+ if (rc != 0) { /* must be ENOMEM */
+ free(tsd);
+ return (-1);
+ }
+ return (0);
+
+
+}
+
+/* Callback function for setting the per thread LDAP error */
+/*ARGSUSED*/
+static void
+set_ld_error(int err, char *matched, char *errmsg, void *dummy)
+{
+ struct ldap_error *le;
+
+ if (thr_getspecific(ns_mtckey, (void **)&le) != 0) {
+ syslog(LOG_ERR, "set_ld_error: thr_getspecific failed. errno"
+ " %d", errno);
+ return;
+ }
+ 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;
+}
+/* Callback function for getting the per thread LDAP error */
+/*ARGSUSED*/
+static int
+get_ld_error(char **matched, char **errmsg, void *dummy)
+{
+ struct ldap_error *le;
+
+ if (thr_getspecific(ns_mtckey, (void **)&le) != 0) {
+ syslog(LOG_ERR, "get_ld_error: thr_getspecific failed. errno"
+ " %d", errno);
+ return (errno);
+ }
+ if (matched != NULL) {
+ *matched = le->le_matched;
+ }
+ if (errmsg != NULL) {
+ *errmsg = le->le_errmsg;
+ }
+ return (le->le_errno);
+}
+
+/* Callback function for setting per thread errno */
+static void
+set_errno(int err)
+{
+ errno = err;
+}
+
+/* Callback function for getting per thread errno */
+static int
+get_errno(void)
+{
+ return (errno);
+}
+
+/*
+ * set up to allow multiple threads to use the same ldap connection
+ */
+static int
+setup_mt_conn(LDAP *ld)
+{
+
+ struct ldap_thread_fns tfns;
+ struct ldap_extra_thread_fns extrafns;
+ int rc;
+
+ /*
+ * Set the function pointers for dealing with mutexes
+ * and error information
+ */
+ (void) memset(&tfns, '\0', sizeof (struct ldap_thread_fns));
+ tfns.ltf_mutex_alloc = (void *(*)(void)) ns_mutex_alloc;
+ tfns.ltf_mutex_free = (void (*)(void *)) ns_mutex_free;
+ tfns.ltf_mutex_lock = (int (*)(void *)) mutex_lock;
+ tfns.ltf_mutex_unlock = (int (*)(void *)) mutex_unlock;
+ tfns.ltf_get_errno = get_errno;
+ tfns.ltf_set_errno = set_errno;
+ tfns.ltf_get_lderrno = get_ld_error;
+ tfns.ltf_set_lderrno = set_ld_error;
+ tfns.ltf_lderrno_arg = NULL;
+
+ /*
+ * Set up this session to use those function pointers
+ */
+ rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS,
+ (void *) &tfns);
+ if (rc < 0) {
+ syslog(LOG_WARNING, "libsldap: ldap_set_option "
+ "(LDAP_OPT_THREAD_FN_PTRS)");
+ return (-1);
+ }
+
+ /*
+ * Set the function pointers for working with semaphores
+ */
+ (void) memset(&extrafns, '\0',
+ sizeof (struct ldap_extra_thread_fns));
+ extrafns.ltf_threadid_fn = (void * (*)(void))thr_self;
+ extrafns.ltf_mutex_trylock = NULL;
+ extrafns.ltf_sema_alloc = NULL;
+ extrafns.ltf_sema_free = NULL;
+ extrafns.ltf_sema_wait = NULL;
+ extrafns.ltf_sema_post = NULL;
+
+ /* Set up this session to use those function pointers */
+ rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
+ (void *) &extrafns);
+ if (rc < 0) {
+ syslog(LOG_WARNING, "libsldap: ldap_set_option "
+ "(LDAP_OPT_EXTRA_THREAD_FN_PTRS)");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+ns_setup_mt_conn_and_tsd(LDAP *ld) {
+ thread_t t = thr_self();
+ void *tsd;
+ /* set up to share this connection among threads */
+ if (MTperConn == 1) {
+ if (tsd_setup() == -1) {
+ syslog(LOG_ERR, "tid= %d: unable "
+ "to set up TSD\n", t);
+ } else {
+ if (setup_mt_conn(ld) == -1) {
+ /* multiple threads per connection not supported */
+ syslog(LOG_ERR, "tid= %d: multiple "
+ "threads per connection not "
+ "supported\n", t);
+ (void) thr_getspecific(ns_mtckey, &tsd);
+ ns_tsd_cleanup(tsd);
+ (void) thr_setspecific(ns_mtckey, NULL);
+ MTperConn = 0;
+ }
+ }
+ }
+}
/*
* Check /proc/PID/psinfo to see if this process is nscd
@@ -126,7 +366,7 @@ nscd_proc()
static int
__s_api_requestServer(const char *request, const char *server,
- ns_server_info_t *ret, ns_ldap_error_t **error)
+ ns_server_info_t *ret, ns_ldap_error_t **error, const char *addrType)
{
union {
ldap_data_t s_d;
@@ -142,7 +382,7 @@ __s_api_requestServer(const char *request, const char *server,
char **mptr, **mptr1, **cptr, **cptr1;
int mcnt, ccnt;
char **servers;
- int rc;
+ int rc, len;
if (ret == NULL || error == NULL) {
return (NS_LDAP_OP_FAILED);
@@ -157,18 +397,26 @@ __s_api_requestServer(const char *request, const char *server,
else
ireq = request;
- adata = (sizeof (ldap_call_t) + strlen(ireq) +1);
+ adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1);
if (server != NULL) {
adata += strlen(DOORLINESEP) + 1;
adata += strlen(server) + 1;
}
ndata = sizeof (space);
+ len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
- (void) strcpy(space.s_d.ldap_call.ldap_u.domainname, ireq);
+ if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
+ return (NS_LDAP_MEMORY);
+ if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >=
+ len)
+ return (NS_LDAP_MEMORY);
if (server != NULL) {
- (void) strcat(space.s_d.ldap_call.ldap_u.domainname,
- DOORLINESEP);
- (void) strcat(space.s_d.ldap_call.ldap_u.domainname, server);
+ if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
+ DOORLINESEP, len) >= len)
+ return (NS_LDAP_MEMORY);
+ if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server,
+ len) >= len)
+ return (NS_LDAP_MEMORY);
}
sptr = &space.s_d;
@@ -327,86 +575,120 @@ __s_api_requestServer(const char *request, const char *server,
return (NS_LDAP_SUCCESS);
}
-#ifdef DEBUG
/*
* printCred(): prints the credential structure
*/
static void
-printCred(FILE *fp, const ns_cred_t *cred)
+printCred(int pri, const ns_cred_t *cred)
{
- if (fp == NULL) {
- (void) fprintf(fp, "printCred: fp is NULL\n");
- return;
- }
+ thread_t t = thr_self();
+
if (cred == NULL) {
- (void) fprintf(fp, "printCred: cred is NULL\n");
+ syslog(LOG_ERR, "tid= %d: printCred: cred is NULL\n", t);
return;
}
- (void) fprintf(fp, "AuthType=%d\n", cred->auth.type);
- (void) fprintf(fp, "TlsType=%d\n", cred->auth.tlstype);
- (void) fprintf(fp, "SaslMech=%d\n", cred->auth.saslmech);
- (void) fprintf(fp, "SaslOpt=%d\n", cred->auth.saslopt);
+ syslog(pri, "tid= %d: AuthType=%d", t, cred->auth.type);
+ syslog(pri, "tid= %d: TlsType=%d", t, cred->auth.tlstype);
+ syslog(pri, "tid= %d: SaslMech=%d", t, cred->auth.saslmech);
+ syslog(pri, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt);
if (cred->hostcertpath)
- (void) fprintf(fp, "hostCertPath=%s\n", cred->hostcertpath);
+ syslog(pri, "tid= %d: hostCertPath=%s\n",
+ t, cred->hostcertpath);
if (cred->cred.unix_cred.userID)
- (void) fprintf(fp, "userID=%s\n", cred->cred.unix_cred.userID);
+ syslog(pri, "tid= %d: userID=%s\n",
+ t, cred->cred.unix_cred.userID);
if (cred->cred.unix_cred.passwd)
- (void) fprintf(fp, "passwd=%s\n", cred->cred.unix_cred.passwd);
+ syslog(pri, "tid= %d: passwd=%s\n",
+ t, cred->cred.unix_cred.passwd);
}
/*
* printConnection(): prints the connection structure
*/
static void
-printConnection(FILE *fp, Connection *con)
+printConnection(int pri, Connection *con)
{
- if (fp == NULL || con == NULL)
+ thread_t t = thr_self();
+
+ if (con == NULL)
return;
- (void) fprintf(fp, "connectionID=%d\n", con->connectionId);
- (void) fprintf(fp, "usedBit=%d\n", con->usedBit);
- (void) fprintf(fp, "threadID=%d\n", con->threadID);
+ syslog(pri, "tid= %d: connectionID=%d\n", t, con->connectionId);
+ syslog(pri, "tid= %d: shared=%d\n", t, con->shared);
+ syslog(pri, "tid= %d: usedBit=%d\n", t, con->usedBit);
+ syslog(pri, "tid= %d: threadID=%d\n", t, con->threadID);
if (con->serverAddr) {
- (void) fprintf(fp, "serverAddr=%s\n", con->serverAddr);
+ syslog(pri, "tid= %d: serverAddr=%s\n",
+ t, con->serverAddr);
}
- printCred(fp, con->auth);
- (void) fprintf(fp, "-----------------------------------------------\n");
- fflush(fp);
+ printCred(pri, con->auth);
}
-#endif /* DEBUG */
/*
- * addConnection(): inserts a connection in the connection list.
- * It will also sets use bit and the thread Id for the thread
- * using the connection for the first time.
+ * addConnection(): set up a connection so that it can be shared
+ * among multiple threads and then insert the connection in the
+ * connection list.
* Returns: -1 = failure, new Connection ID = success
+ *
+ * This function could exit with sessionLock locked. It will be
+ * be unlocked in __s_api_getConnection() when it exits without getting a
+ * connection.
*/
static int
addConnection(Connection *con)
{
- int i;
+ int i, noMTperC = 0;
+ thread_t t = thr_self();
+ struct ldap_thread_fns tfns;
+ void *tsd;
if (!con)
return (-1);
-#ifdef DEBUG
- (void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID);
-#endif /* DEBUG */
- (void) mutex_lock(&sessionPoolLock);
+
+ syslog(LOG_DEBUG, "tid= %d: Adding connection (serverAddr=%s)",
+ t, con->serverAddr);
+
+ if (MTperConn == 1) {
+ /*
+ * Make sure ld has proper thread functions and tsd
+ * is set up.
+ */
+ (void) memset(&tfns, 0, sizeof (struct ldap_thread_fns));
+ /*
+ * ldap_init sets ltf_get_lderrno and ltf_set_lderrno to NULLs.
+ * It's supposed to be overwritten by ns_setup_mt_conn_and_tsd.
+ */
+ if (ldap_get_option(con->ld, LDAP_OPT_THREAD_FN_PTRS,
+ (void *)&tfns) != 0 ||
+ tfns.ltf_get_lderrno != get_ld_error ||
+ tfns.ltf_set_lderrno != set_ld_error) {
+ MTperConn = 0;
+ noMTperC = 1;
+ } else {
+ if (thr_getspecific(ns_mtckey, &tsd) != 0 ||
+ tsd == NULL)
+ noMTperC = 1;
+ }
+
+ } else {
+ noMTperC = 1;
+ }
+
+ (void) rw_wrlock(&sessionPoolLock);
if (sessionPool == NULL) {
sessionPoolSize = SESSION_CACHE_INC;
sessionPool = calloc(sessionPoolSize,
sizeof (struct connection **));
if (!sessionPool) {
- (void) mutex_unlock(&sessionPoolLock);
+ (void) rw_unlock(&sessionPoolLock);
return (-1);
}
-#ifdef DEBUG
- (void) fprintf(stderr, "Initialized sessionPool\n");
-#endif /* DEBUG */
+
+ syslog(LOG_DEBUG, "tid= %d: Initialized sessionPool", t);
}
for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i)
;
@@ -417,26 +699,44 @@ addConnection(Connection *con)
(sessionPoolSize + SESSION_CACHE_INC) *
sizeof (Connection *));
if (!cl) {
- (void) mutex_unlock(&sessionPoolLock);
+ (void) rw_unlock(&sessionPoolLock);
return (-1);
}
(void) memset(cl + sessionPoolSize, 0,
SESSION_CACHE_INC * sizeof (struct connection *));
sessionPool = cl;
sessionPoolSize += SESSION_CACHE_INC;
-#ifdef DEBUG
- (void) fprintf(stderr, "Increased sessionPoolSize to: %d\n",
- sessionPoolSize);
-#endif /* DEBUG */
+ syslog(LOG_DEBUG, "tid: %d: Increased "
+ "sessionPoolSize to: %d\n",
+ t, sessionPoolSize);
}
sessionPool[i] = con;
- con->usedBit = B_TRUE;
- (void) mutex_unlock(&sessionPoolLock);
+ if (noMTperC == 0)
+ con->shared++;
+ else
+ con->usedBit = B_TRUE;
+
+ (void) rw_unlock(&sessionPoolLock);
+
con->connectionId = i + CONID_OFFSET;
-#ifdef DEBUG
- (void) fprintf(stderr, "Connection added [%d]\n", i);
- printConnection(stderr, con);
-#endif /* DEBUG */
+
+ syslog(LOG_DEBUG, "tid= %d: Connection added [%d]\n",
+ t, i);
+ printConnection(LOG_DEBUG, con);
+
+ /*
+ * A connection can be shared now, unlock
+ * the session mutex and let other
+ * threads try to use this connection or
+ * get their own.
+ */
+ if (wait4session != 0 && sessionTid == thr_self()) {
+ wait4session = 0;
+ sessionTid = 0;
+ syslog(LOG_DEBUG, "tid= %d: unlocking sessionLock\n", t);
+ (void) mutex_unlock(&sessionLock);
+ }
+
return (i + CONID_OFFSET);
}
@@ -453,6 +753,11 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID,
if ((conp == NULL) || (auth == NULL) || cID < CONID_OFFSET)
return (-1);
+
+ /* if a new connection is requested, no need to continue */
+ if (flags & NS_LDAP_NEW_CONN)
+ return (-1);
+
*conp = NULL;
if (sessionPool == NULL)
return (-1);
@@ -460,9 +765,9 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID,
if (id < 0 || id >= sessionPoolSize)
return (-1);
- (void) mutex_lock(&sessionPoolLock);
+ (void) rw_rdlock(&sessionPoolLock);
if (sessionPool[id] == NULL) {
- (void) mutex_unlock(&sessionPoolLock);
+ (void) rw_unlock(&sessionPoolLock);
return (-1);
}
cp = sessionPool[id];
@@ -471,11 +776,12 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID,
* Make sure the connection has the same type of authentication method
*/
if ((cp->usedBit) ||
+ (cp->notAvail) ||
(cp->auth->auth.type != auth->auth.type) ||
(cp->auth->auth.tlstype != auth->auth.tlstype) ||
(cp->auth->auth.saslmech != auth->auth.saslmech) ||
(cp->auth->auth.saslopt != auth->auth.saslopt)) {
- (void) mutex_unlock(&sessionPoolLock);
+ (void) rw_unlock(&sessionPoolLock);
return (-1);
}
if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) &&
@@ -485,18 +791,19 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID,
((cp->auth->cred.unix_cred.userID == NULL) ||
(strcasecmp(cp->auth->cred.unix_cred.userID,
auth->cred.unix_cred.userID) != 0))) {
- (void) mutex_unlock(&sessionPoolLock);
+ (void) rw_unlock(&sessionPoolLock);
return (-1);
}
+
/* An existing connection is found but it needs to be reset */
if (flags & NS_LDAP_NEW_CONN) {
- (void) mutex_unlock(&sessionPoolLock);
+ (void) rw_unlock(&sessionPoolLock);
DropConnection(cID, 0);
return (-1);
}
/* found an available connection */
cp->usedBit = B_TRUE;
- (void) mutex_unlock(&sessionPoolLock);
+ (void) rw_unlock(&sessionPoolLock);
cp->threadID = thr_self();
*conp = cp;
return (cID);
@@ -508,39 +815,111 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID,
* If serverAddr is NULL, then find a connection to any server
* as long as it matches the rest of the parameters.
* Returns: -1 = failure, the Connection ID found = success.
+ *
+ * This function could exit with sessionLock locked. It will be
+ * be unlocked in addConnection() when this thread adds the connection
+ * to the pool or in __s_api_getConnection() when it exits without getting a
+ * connection.
*/
+#define TRY_TIMES 10
static int
-findConnection(const char *serverAddr, const ns_cred_t *auth, Connection **conp)
+findConnection(int flags, const char *serverAddr,
+ const ns_cred_t *auth, Connection **conp)
{
Connection *cp;
int i;
+ int rc;
+ int try;
+#ifdef DEBUG
+ thread_t t = thr_self();
+#endif /* DEBUG */
if (auth == NULL || conp == NULL)
return (-1);
*conp = NULL;
+ /* no need to find connection if anonymous */
+ if (auth->auth.type == NS_LDAP_AUTH_NONE)
+ return (-1);
+
+ /* if a new connection is requested, no need to continue */
+ if (flags & NS_LDAP_NEW_CONN)
+ return (-1);
+
#ifdef DEBUG
- (void) fprintf(stderr, "Find connection\n");
- (void) fprintf(stderr, "Looking for ....\n");
+ (void) fprintf(stderr, "tid= %d: Find connection\n", t);
+ (void) fprintf(stderr, "tid= %d: Looking for ....\n", t);
if (serverAddr && *serverAddr)
- (void) fprintf(stderr, "serverAddr=%s\n", serverAddr);
+ (void) fprintf(stderr, "tid= %d: serverAddr=%s\n",
+ t, serverAddr);
else
- (void) fprintf(stderr, "serverAddr=NULL\n");
+ (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t);
printCred(stderr, auth);
fflush(stderr);
#endif /* DEBUG */
- if (sessionPool == NULL)
+
+ /*
+ * If multiple threads per connection not supported,
+ * no sessionPool means no connection
+ */
+ (void) rw_rdlock(&sessionPoolLock);
+ if (MTperConn == 0 && sessionPool == NULL) {
+ (void) rw_unlock(&sessionPoolLock);
return (-1);
- (void) mutex_lock(&sessionPoolLock);
+ }
+
+ /*
+ * If no connection in cache, then serialize the opening
+ * of connections. Make sure only one is being opened
+ * at a time. Otherwise, we may end up with more
+ * connections than we want (if multiple threads get
+ * here at the same time)
+ */
+ if (sessionPool == NULL) {
+ (void) rw_unlock(&sessionPoolLock);
+ (void) mutex_lock(&sessionLock);
+ if (sessionPool == NULL) {
+ wait4session = 1;
+ sessionTid = thr_self();
+#ifdef DEBUG
+ (void) fprintf(stderr, "tid= %d: get "
+ "connection ... \n", t);
+ fflush(stderr);
+#endif /* DEBUG */
+ /*
+ * Exit with sessionLock locked. It will be
+ * be unlocked in addConnection() when this
+ * thread adds the connection to the pool or
+ * in __s_api_getConnection() when it exits
+ * without getting a connection.
+ */
+ return (-1);
+ }
+
+#ifdef DEBUG
+ (void) fprintf(stderr, "tid= %d: session pool not empty\n", t);
+ fflush(stderr);
+#endif /* DEBUG */
+ /*
+ * connection pool is not empty, check to see if
+ * one can be shared.
+ */
+ (void) mutex_unlock(&sessionLock);
+ (void) rw_rdlock(&sessionPoolLock);
+ }
+ try = 0;
+ check_again:
+
for (i = 0; i < sessionPoolSize; ++i) {
if (sessionPool[i] == NULL)
continue;
cp = sessionPool[i];
#ifdef DEBUG
- (void) fprintf(stderr, "checking connection [%d] ....\n", i);
+ (void) fprintf(stderr, "tid= %d: checking connection "
+ "[%d] ....\n", t, i);
printConnection(stderr, cp);
#endif /* DEBUG */
- if ((cp->usedBit) ||
+ if ((cp->usedBit) || (cp->notAvail) ||
(cp->auth->auth.type != auth->auth.type) ||
(cp->auth->auth.tlstype != auth->auth.tlstype) ||
(cp->auth->auth.saslmech != auth->auth.saslmech) ||
@@ -560,18 +939,89 @@ findConnection(const char *serverAddr, const ns_cred_t *auth, Connection **conp)
auth->cred.unix_cred.passwd) != 0))))
continue;
/* found an available connection */
- cp->usedBit = B_TRUE;
- (void) mutex_unlock(&sessionPoolLock);
- cp->threadID = thr_self();
+ if (MTperConn == 0)
+ cp->usedBit = B_TRUE;
+ else {
+ /* allocate TSD for per thread ldap error */
+ rc = tsd_setup();
+
+ /* if we got TSD, this connection is shared */
+ if (rc != -1)
+ cp->shared++;
+ else if (cp->shared == 0) {
+ cp->usedBit = B_TRUE;
+ cp->threadID = thr_self();
+ (void) rw_unlock(&sessionPoolLock);
+ return (-1);
+ }
+ }
+ (void) rw_unlock(&sessionPoolLock);
+
*conp = cp;
#ifdef DEBUG
- (void) fprintf(stderr, "Connection found cID=%d\n", i);
+ (void) fprintf(stderr, "tid= %d: Connection found "
+ "cID=%d, shared =%d\n", t, i, cp->shared);
fflush(stderr);
#endif /* DEBUG */
return (i + CONID_OFFSET);
}
- (void) mutex_unlock(&sessionPoolLock);
- return (-1);
+ (void) rw_unlock(&sessionPoolLock);
+
+ /*
+ * If multiple threads per connection not supported,
+ * we are done, just return -1 to tell the caller to
+ * proceed with opening a connection
+ */
+ if (MTperConn == 0)
+ return (-1);
+
+ /*
+ * No connection can be shared, test to see if
+ * one is being opened. If trylock returns
+ * EBUSY then it is, so wait until the opening
+ * is done and try to see if the new connection
+ * can be shared.
+ */
+ rc = mutex_trylock(&sessionLock);
+ if (rc == EBUSY) {
+ (void) mutex_lock(&sessionLock);
+ (void) mutex_unlock(&sessionLock);
+ (void) rw_rdlock(&sessionPoolLock);
+#ifdef DEBUG
+ (void) fprintf(stderr, "tid= %d: check session "
+ "pool again\n", t);
+ fflush(stderr);
+#endif /* DEBUG */
+ if (try < TRY_TIMES) {
+ try++;
+ goto check_again;
+ } else {
+ syslog(LOG_WARNING, "libsldap: mutex_trylock "
+ "%d times. Stop.", TRY_TIMES);
+ return (-1);
+ }
+ } else if (rc == 0) {
+ /*
+ * No connection can be shared, none being opened,
+ * exit with sessionLock locked to open one. The
+ * mutex will be unlocked in addConnection() when
+ * this thread adds the new connection to the pool
+ * or in __s_api_getConnection() when it exits
+ * without getting a connection.
+ */
+ wait4session = 1;
+ sessionTid = thr_self();
+#ifdef DEBUG
+ (void) fprintf(stderr, "tid= %d: no connection found, "
+ "none being opened, get connection ...\n", t);
+ fflush(stderr);
+#endif /* DEBUG */
+ return (-1);
+ } else {
+ syslog(LOG_WARNING, "libsldap: mutex_trylock unexpected "
+ "error", rc);
+ return (-1);
+ }
}
/*
@@ -607,7 +1057,7 @@ static int
makeConnection(Connection **conp, const char *serverAddr,
const ns_cred_t *auth, ConnectionID *cID, int timeoutSec,
ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd,
- int nopasswd_acct_mgmt, char ***badsrvrs)
+ int nopasswd_acct_mgmt, int flags, char ***badsrvrs)
{
Connection *con = NULL;
ConnectionID id;
@@ -618,7 +1068,9 @@ makeConnection(Connection **conp, const char *serverAddr,
LDAP *ld = NULL;
int passwd_mgmt = 0;
int totalbad = 0; /* Number of servers contacted unsuccessfully */
- short memerr = 0; /* Variable for tracking memory allocation errors */
+ short memerr = 0; /* Variable for tracking memory allocation */
+ char *serverAddrType = NULL;
+
if (conp == NULL || errorp == NULL || auth == NULL)
return (NS_LDAP_INVALID_PARAM);
@@ -628,10 +1080,11 @@ makeConnection(Connection **conp, const char *serverAddr,
sinfo.controls = NULL;
sinfo.saslMechanisms = NULL;
- if ((id = findConnection(serverAddr, auth, &con)) != -1) {
+ if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) {
/* connection found in cache */
#ifdef DEBUG
- (void) fprintf(stderr, "connection found in cache %d\n", id);
+ (void) fprintf(stderr, "tid= %d: connection found in "
+ "cache %d\n", thr_self(), id);
fflush(stderr);
#endif /* DEBUG */
*cID = id;
@@ -639,21 +1092,26 @@ makeConnection(Connection **conp, const char *serverAddr,
return (NS_LDAP_SUCCESS);
}
+ if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI)
+ serverAddrType = NS_CACHE_ADDR_HOSTNAME;
+ else
+ serverAddrType = NS_CACHE_ADDR_IP;
+
if (serverAddr) {
- rc = openConnection(&ld, serverAddr, auth, timeoutSec, errorp,
+ rc = __s_api_requestServer(NS_CACHE_NEW, serverAddr,
+ &sinfo, errorp, serverAddrType);
+ if (rc != NS_LDAP_SUCCESS || sinfo.server == NULL) {
+ (void) snprintf(errmsg, sizeof (errmsg),
+ gettext("makeConnection: unable to get "
+ "server information for %s"), serverAddr);
+ syslog(LOG_ERR, "libsldap: %s", errmsg);
+ return (NS_LDAP_OP_FAILED);
+ }
+ rc = openConnection(&ld, sinfo.server, auth, timeoutSec, errorp,
fail_if_new_pwd_reqd, passwd_mgmt);
if (rc == NS_LDAP_SUCCESS || rc ==
NS_LDAP_SUCCESS_WITH_INFO) {
exit_rc = rc;
- rc = __s_api_requestServer(NS_CACHE_NEW, serverAddr,
- &sinfo, errorp);
- if (rc != NS_LDAP_SUCCESS || sinfo.server == NULL) {
- (void) snprintf(errmsg, sizeof (errmsg),
- gettext("makeConnection: unable to get "
- "server information for %s"), serverAddr);
- syslog(LOG_ERR, "libsldap: %s", errmsg);
- return (NS_LDAP_OP_FAILED);
- }
goto create_con;
} else {
return (rc);
@@ -666,7 +1124,8 @@ makeConnection(Connection **conp, const char *serverAddr,
hReq = NS_CACHE_NEW;
else
hReq = NS_CACHE_NEXT;
- rc = __s_api_requestServer(hReq, host, &sinfo, errorp);
+ rc = __s_api_requestServer(hReq, host, &sinfo, errorp,
+ serverAddrType);
if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) ||
(host && (strcasecmp(host, sinfo.server) == 0))) {
/* Log the error */
@@ -851,6 +1310,7 @@ create_con:
}
con->threadID = thr_self();
+
con->ld = ld;
if ((id = addConnection(con)) == -1) {
freeConnection(con);
@@ -866,7 +1326,8 @@ create_con:
return (NS_LDAP_MEMORY);
}
#ifdef DEBUG
- (void) fprintf(stderr, "connection added into cache %d\n", id);
+ (void) fprintf(stderr, "tid= %d: connection added into "
+ "cache %d\n", thr_self(), id);
fflush(stderr);
#endif /* DEBUG */
*cID = id;
@@ -884,42 +1345,86 @@ _DropConnection(ConnectionID cID, int flag, int fini)
{
Connection *cp;
int id;
- int use_mutex = !fini;
+ int use_lock = !fini;
+#ifdef DEBUG
+ thread_t t = thr_self();
+#endif /* DEBUG */
id = cID - CONID_OFFSET;
if (id < 0 || id >= sessionPoolSize)
return;
#ifdef DEBUG
- (void) fprintf(stderr,
- "Dropping connection cID=%d flag=0x%x\n", cID, flag);
+ (void) fprintf(stderr, "tid= %d: "
+ "Dropping connection cID=%d flag=0x%x, fini = %d\n",
+ t, cID, flag, fini);
fflush(stderr);
#endif /* DEBUG */
- if (use_mutex)
- (void) mutex_lock(&sessionPoolLock);
+ if (use_lock)
+ (void) rw_wrlock(&sessionPoolLock);
cp = sessionPool[id];
/* sanity check before removing */
- if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) {
- if (use_mutex)
- (void) mutex_unlock(&sessionPoolLock);
+ if (!cp || (!fini && !cp->shared && (!cp->usedBit ||
+ cp->threadID != thr_self()))) {
+#ifdef DEBUG
+ if (cp == NULL)
+ (void) fprintf(stderr, "tid= %d: no "
+ "need to remove (fini = %d, cp = %p)\n", t,
+ fini, cp);
+ else
+ (void) fprintf(stderr, "tid= %d: no "
+ "need to remove (fini = %d, cp = %p, shared = %d)\n",
+ t, fini, cp, cp->shared);
+ fflush(stderr);
+#endif /* DEBUG */
+ if (use_lock)
+ (void) rw_unlock(&sessionPoolLock);
return;
}
if (!fini &&
- ((flag & NS_LDAP_NEW_CONN) == 0) &&
- ((flag & NS_LDAP_KEEP_CONN) || nscd_proc())) {
+ ((flag & NS_LDAP_NEW_CONN) == 0) && !cp->notAvail &&
+ ((flag & NS_LDAP_KEEP_CONN) ||
+ (MTperConn == 0 && nscd_proc()) ||
+ MTperConn)) {
+#ifdef DEBUG
+ (void) fprintf(stderr, "tid= %d: keep alive (fini = %d "
+ "shared = %d)\n", t, fini, cp->shared);
+#endif /* DEBUG */
/* release Connection (keep alive) */
+ if (cp->shared)
+ cp->shared--;
cp->usedBit = B_FALSE;
cp->threadID = 0; /* unmark the threadID */
- if (use_mutex)
- (void) mutex_unlock(&sessionPoolLock);
+ if (use_lock)
+ (void) rw_unlock(&sessionPoolLock);
} else {
/* delete Connection (disconnect) */
- sessionPool[id] = NULL;
- if (use_mutex)
- (void) mutex_unlock(&sessionPoolLock);
- (void) ldap_unbind(cp->ld);
- freeConnection(cp);
+ if (cp->shared > 0) {
+#ifdef DEBUG
+ (void) fprintf(stderr, "tid= %d: Connection no "
+ "longer available (fini = %d, shared = %d)\n",
+ t, fini, cp->shared);
+ fflush(stderr);
+#endif /* DEBUG */
+ cp->shared--;
+ cp->notAvail = 1;
+ }
+
+ if (cp->shared <= 0) {
+#ifdef DEBUG
+ (void) fprintf(stderr, "tid= %d: unbind "
+ "(fini = %d, shared = %d)\n",
+ t, fini, cp->shared);
+ fflush(stderr);
+#endif /* DEBUG */
+ sessionPool[id] = NULL;
+ (void) ldap_unbind(cp->ld);
+ freeConnection(cp);
+ }
+
+ if (use_lock)
+ (void) rw_unlock(&sessionPoolLock);
}
}
@@ -1189,16 +1694,17 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
int errnum = 0;
LDAPMessage *resultMsg;
int msgId;
- int useSSL = 0;
+ int useSSL = 0, port = 0;
struct timeval tv;
AuthType_t bindType;
int timeoutMilliSec = timeoutSec * 1000;
struct berval cred;
char *sslServerAddr;
char *s1;
- char *errmsg;
+ char *errmsg, *end = NULL;
LDAPControl **controls;
- int pwd_rc;
+ int pwd_rc, min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF;
+ ns_sasl_cb_param_t sasl_param;
*errorp = NULL;
*ldp = NULL;
@@ -1246,7 +1752,8 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
const char *hostcertpath;
char *alloc_hcp = NULL;
#ifdef DEBUG
- (void) fprintf(stderr, "+++TLS transport\n");
+ (void) fprintf(stderr, "tid= %d: +++TLS transport\n",
+ thr_self());
#endif /* DEBUG */
if (prldap_set_session_option(NULL, NULL,
@@ -1324,15 +1831,40 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
}
} else {
#ifdef DEBUG
- (void) fprintf(stderr, "+++Unsecure transport\n");
+ (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n",
+ thr_self());
#endif /* DEBUG */
- /* Warning message IF cannot connect to host(s) */
- if ((ld = ldap_init((char *)serverAddr, LDAP_PORT)) == NULL) {
+ port = LDAP_PORT;
+ if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI &&
+ (end = strchr(serverAddr, ':')) != NULL) {
+ /*
+ * The IP is converted to hostname so it's a
+ * hostname:port up to this point.
+ *
+ * libldap passes hostname:port to the sasl layer.
+ * The ldap service principal is constructed as
+ * ldap/hostname:port@REALM. Kerberos authentication
+ * will fail. So it needs to be parsed to construct
+ * a valid principal ldap/hostname@REALM.
+ *
+ * For useSSL case above, it already parses port so
+ * no need to parse serverAddr
+ */
+ *end = '\0';
+ port = atoi(end + 1);
+ }
+
+ /* Warning message IF cannot connect to host(s) */
+ if ((ld = ldap_init((char *)serverAddr, port)) == NULL) {
char *p = strerror(errno);
MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
strdup(p), NULL);
+ if (end)
+ *end = ':';
return (NS_LDAP_INTERNAL);
} else {
+ if (end)
+ *end = ':';
/* check and avoid gethostname recursion */
if (ldap_in_hosts_switch() > 0 &&
! __s_api_isipv4((char *)serverAddr) &&
@@ -1340,21 +1872,22 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
/* host: ldap - found, attempt to recover */
if (ldap_set_option(ld, LDAP_X_OPT_DNS_SKIPDB,
"ldap") != 0) {
- (void) snprintf(errstr, sizeof (errstr),
- gettext("openConnection: "
- "unrecoverable gethostname "
- "recursion detected "
- "in /etc/nsswitch.conf"));
- MKERROR(LOG_WARNING, *errorp,
- LDAP_CONNECT_ERROR,
- strdup(errstr), NULL);
- (void) ldap_unbind(ld);
- return (NS_LDAP_INTERNAL);
+ (void) snprintf(errstr, sizeof (errstr),
+ gettext("openConnection: "
+ "unrecoverable gethostname "
+ "recursion detected "
+ "in /etc/nsswitch.conf"));
+ MKERROR(LOG_WARNING, *errorp,
+ LDAP_CONNECT_ERROR,
+ strdup(errstr), NULL);
+ (void) ldap_unbind(ld);
+ return (NS_LDAP_INTERNAL);
}
}
}
}
+ ns_setup_mt_conn_and_tsd(ld);
(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion);
(void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
/*
@@ -1377,7 +1910,8 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
switch (bindType) {
case NS_LDAP_AUTH_NONE:
#ifdef DEBUG
- (void) fprintf(stderr, "+++Anonymous bind\n");
+ (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n",
+ thr_self());
#endif /* DEBUG */
break;
case NS_LDAP_AUTH_SIMPLE:
@@ -1394,7 +1928,8 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
}
#ifdef DEBUG
- (void) fprintf(stderr, "+++Simple bind\n");
+ (void) fprintf(stderr, "tid= %d: +++Simple bind\n",
+ thr_self());
#endif /* DEBUG */
msgId = ldap_simple_bind(ld, binddn, passwd);
@@ -1462,31 +1997,35 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
break;
case NS_LDAP_AUTH_SASL:
- /* We don't support any sasl options yet */
- if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE) {
+ if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE &&
+ auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
(void) sprintf(errstr,
gettext("openConnection: SASL options are "
- "not supported (%d)"), auth->auth.saslopt);
+ "not supported (%d) for non-GSSAPI sasl bind"),
+ auth->auth.saslopt);
MKERROR(LOG_WARNING, *errorp,
LDAP_AUTH_METHOD_NOT_SUPPORTED,
strdup(errstr), NULL);
(void) ldap_unbind(ld);
return (NS_LDAP_INTERNAL);
}
- binddn = auth->cred.unix_cred.userID;
- passwd = auth->cred.unix_cred.passwd;
- if (passwd == NULL || *passwd == '\0' ||
- binddn == NULL || *binddn == '\0') {
- (void) sprintf(errstr,
+ if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
+ binddn = auth->cred.unix_cred.userID;
+ passwd = auth->cred.unix_cred.passwd;
+ if (passwd == NULL || *passwd == '\0' ||
+ binddn == NULL || *binddn == '\0') {
+ (void) sprintf(errstr,
gettext("openConnection: missing credentials "
"for SASL bind"));
- MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS,
- strdup(errstr), NULL);
- (void) ldap_unbind(ld);
- return (NS_LDAP_INTERNAL);
+ MKERROR(LOG_WARNING, *errorp,
+ LDAP_INVALID_CREDENTIALS,
+ strdup(errstr), NULL);
+ (void) ldap_unbind(ld);
+ return (NS_LDAP_INTERNAL);
+ }
+ cred.bv_val = passwd;
+ cred.bv_len = strlen(passwd);
}
- cred.bv_val = passwd;
- cred.bv_len = strlen(passwd);
switch (auth->auth.saslmech) {
case NS_LDAP_SASL_CRAM_MD5:
@@ -1584,6 +2123,47 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
free(digest_md5_name);
break;
+ case NS_LDAP_SASL_GSSAPI:
+ if (sasl_gssapi_inited == 0) {
+ rc = __s_api_sasl_gssapi_init();
+ if (rc != NS_LDAP_SUCCESS) {
+ (void) snprintf(errstr, sizeof (errstr),
+ gettext("openConnection: "
+ "GSSAPI initialization "
+ "failed"));
+ (void) ldap_unbind(ld);
+ MKERROR(LOG_WARNING, *errorp, rc,
+ strdup(errstr), NULL);
+ return (rc);
+ }
+ }
+ (void) memset(&sasl_param, 0,
+ sizeof (ns_sasl_cb_param_t));
+ sasl_param.authid = NULL;
+ sasl_param.authzid = "";
+ (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN,
+ (void *)&min_ssf);
+ (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX,
+ (void *)&max_ssf);
+
+ rc = ldap_sasl_interactive_bind_s(
+ ld, NULL, "GSSAPI",
+ NULL, NULL, LDAP_SASL_INTERACTIVE,
+ __s_api_sasl_bind_callback,
+ &sasl_param);
+
+ if (rc != LDAP_SUCCESS) {
+ (void) snprintf(errstr, sizeof (errstr),
+ gettext("openConnection: "
+ "GSSAPI bind failed "
+ "- %d %s"), rc, ldap_err2string(rc));
+ (void) ldap_unbind(ld);
+ MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
+ strdup(errstr), NULL);
+ return (NS_LDAP_INTERNAL);
+ }
+
+ break;
default:
(void) ldap_unbind(ld);
(void) sprintf(errstr,
@@ -1648,12 +2228,11 @@ __s_api_getDefaultAuth(
return (NS_LDAP_INVALID_PARAM);
}
-
/*
- * Do not differentiate between (proxy/self) at this time, but
- * reject self credential levels at this time
+ * credential level "self" can work with auth method sasl/GSSAPI only
*/
- if (cLevel && *cLevel == NS_LDAP_CRED_SELF)
+ if (cLevel && *cLevel == NS_LDAP_CRED_SELF &&
+ aMethod->saslmech != NS_LDAP_SASL_GSSAPI)
return (NS_LDAP_INVALID_PARAM);
*authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
@@ -1674,7 +2253,7 @@ __s_api_getDefaultAuth(
(aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) {
getUid++;
getPasswd++;
- } else {
+ } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) {
(void) __ns_ldap_freeCred(authp);
*authp = NULL;
return (NS_LDAP_INVALID_PARAM);
@@ -1845,7 +2424,7 @@ __s_api_getConnection(
int sec = 1;
ns_cred_t *authp = NULL;
ns_cred_t anon;
- int version = NS_LDAP_V2;
+ int version = NS_LDAP_V2, self_gssapi_only = 0;
void **paramVal = NULL;
char **badSrvrs = NULL; /* List of problem hostnames */
@@ -1941,16 +2520,20 @@ __s_api_getConnection(
/* using specified auth method */
rc = makeConnection(&con, server, cred,
sessionId, timeoutSec, errorp,
- fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
- &badSrvrs);
+ fail_if_new_pwd_reqd,
+ nopasswd_acct_mgmt, flags, &badSrvrs);
if (rc == NS_LDAP_SUCCESS ||
rc == NS_LDAP_SUCCESS_WITH_INFO) {
*session = con;
break;
}
} else {
+ self_gssapi_only = __s_api_self_gssapi_only_get();
/* for every cred level */
for (cNext = cLevel; *cNext != NULL; cNext++) {
+ if (self_gssapi_only &&
+ **cNext != NS_LDAP_CRED_SELF)
+ continue;
if (**cNext == NS_LDAP_CRED_ANON) {
/*
* make connection anonymously
@@ -1964,7 +2547,8 @@ __s_api_getConnection(
rc = makeConnection(&con, server, &anon,
sessionId, timeoutSec, errorp,
fail_if_new_pwd_reqd,
- nopasswd_acct_mgmt, &badSrvrs);
+ nopasswd_acct_mgmt, flags,
+ &badSrvrs);
if (rc == NS_LDAP_SUCCESS ||
rc ==
NS_LDAP_SUCCESS_WITH_INFO) {
@@ -1975,6 +2559,22 @@ __s_api_getConnection(
}
/* for each cred level */
for (aNext = aMethod; *aNext != NULL; aNext++) {
+ if (self_gssapi_only &&
+ (*aNext)->saslmech !=
+ NS_LDAP_SASL_GSSAPI)
+ continue;
+ /*
+ * self coexists with sasl/GSSAPI only
+ * and non-self coexists with non-gssapi
+ * only
+ */
+ if ((**cNext == NS_LDAP_CRED_SELF &&
+ (*aNext)->saslmech !=
+ NS_LDAP_SASL_GSSAPI) ||
+ (**cNext != NS_LDAP_CRED_SELF &&
+ (*aNext)->saslmech ==
+ NS_LDAP_SASL_GSSAPI))
+ continue;
/* make connection and authenticate */
/* with default credentials */
authp = NULL;
@@ -1994,7 +2594,8 @@ __s_api_getConnection(
rc = makeConnection(&con, server, authp,
sessionId, timeoutSec, errorp,
fail_if_new_pwd_reqd,
- nopasswd_acct_mgmt, &badSrvrs);
+ nopasswd_acct_mgmt, flags,
+ &badSrvrs);
(void) __ns_ldap_freeCred(&authp);
if (rc == NS_LDAP_SUCCESS ||
rc ==
@@ -2015,6 +2616,30 @@ __s_api_getConnection(
}
done:
+ /*
+ * If unable to get a connection, and this is
+ * the thread opening the shared connection,
+ * unlock the session mutex and let other
+ * threads try to get their own connection.
+ */
+ if (wait4session != 0 && sessionTid == thr_self()) {
+ wait4session = 0;
+ sessionTid = 0;
+#ifdef DEBUG
+ (void) fprintf(stderr, "tid= %d: __s_api_getConnection: "
+ "unlocking sessionLock \n", thr_self());
+ fflush(stderr);
+#endif /* DEBUG */
+ (void) mutex_unlock(&sessionLock);
+ }
+ if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) {
+ /*
+ * self_gssapi_only is true but no self/sasl/gssapi is
+ * configured
+ */
+ rc = NS_LDAP_CONFIG;
+ }
+
(void) __ns_ldap_freeParam((void ***)&aMethod);
(void) __ns_ldap_freeParam((void ***)&cLevel);
@@ -2038,7 +2663,7 @@ _free_sessionPool()
{
int id;
- (void) mutex_lock(&sessionPoolLock);
+ (void) rw_wrlock(&sessionPoolLock);
if (sessionPool != NULL) {
for (id = 0; id < sessionPoolSize; id++)
_DropConnection(id + CONID_OFFSET, 0, 1);
@@ -2046,5 +2671,5 @@ _free_sessionPool()
sessionPool = NULL;
sessionPoolSize = 0;
}
- (void) mutex_unlock(&sessionPoolLock);
+ (void) rw_unlock(&sessionPoolLock);
}