summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsldap
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libsldap')
-rw-r--r--usr/src/lib/libsldap/Makefile.com12
-rw-r--r--usr/src/lib/libsldap/common/llib-lsldap53
-rw-r--r--usr/src/lib/libsldap/common/mapfile-vers6
-rw-r--r--usr/src/lib/libsldap/common/ns_cache_door.h9
-rw-r--r--usr/src/lib/libsldap/common/ns_common.c16
-rw-r--r--usr/src/lib/libsldap/common/ns_config.c49
-rw-r--r--usr/src/lib/libsldap/common/ns_connect.c935
-rw-r--r--usr/src/lib/libsldap/common/ns_init.c21
-rw-r--r--usr/src/lib/libsldap/common/ns_internal.h65
-rw-r--r--usr/src/lib/libsldap/common/ns_reads.c28
-rw-r--r--usr/src/lib/libsldap/common/ns_sasl.c580
-rw-r--r--usr/src/lib/libsldap/common/ns_sldap.h29
-rw-r--r--usr/src/lib/libsldap/common/ns_writes.c6
-rw-r--r--usr/src/lib/libsldap/req.flg1
14 files changed, 1615 insertions, 195 deletions
diff --git a/usr/src/lib/libsldap/Makefile.com b/usr/src/lib/libsldap/Makefile.com
index ce3a899fec..244c974085 100644
--- a/usr/src/lib/libsldap/Makefile.com
+++ b/usr/src/lib/libsldap/Makefile.com
@@ -22,8 +22,9 @@
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
+#ident "%Z%%M% %I% %E% SMI"
#
+# lib/libsldap/Makefile.com
LIBRARY= libsldap.a
VERS= .1
@@ -32,7 +33,7 @@ SLDAPOBJ= ns_common.o ns_reads.o ns_writes.o \
ns_connect.o ns_config.o ns_error.o \
ns_cache_door.o ns_getalias.o ns_trace.o \
ns_init.o ns_crypt.o ns_confmgr.o \
- ns_mapping.o ns_wrapper.o
+ ns_mapping.o ns_wrapper.o ns_sasl.o
OBJECTS= $(SLDAPOBJ)
@@ -41,13 +42,14 @@ include ../../Makefile.lib
SRCS = $(SLDAPOBJ:%.o=../common/%.c)
LIBS = $(DYNLIB) $(LINTLIB)
$(LINTLIB):= SRCS=../common/llib-lsldap
-LDLIBS += -lnsl -lldap -lc
+LDLIBS += -lnsl -lldap -lscf -lc
SRCDIR = ../common
CFLAGS += $(CCVERBOSE)
-LOCFLAGS += -D_REENTRANT -DSUNW_OPTIONS -DTHREAD_SUNOS5_LWP
-CPPFLAGS += -I../common -I$(SRC)/lib/libldap5/include/ldap -I/usr/include/mps $(LOCFLAGS)
+LOCFLAGS += -D_REENTRANT -DSUNW_OPTIONS
+CPPFLAGS += -I../common -I$(SRC)/lib/libldap5/include/ldap \
+ -I/usr/include/mps $(LOCFLAGS)
LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN
LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN
diff --git a/usr/src/lib/libsldap/common/llib-lsldap b/usr/src/lib/libsldap/common/llib-lsldap
index 6114809d89..466116a856 100644
--- a/usr/src/lib/libsldap/common/llib-lsldap
+++ b/usr/src/lib/libsldap/common/llib-lsldap
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -23,7 +22,7 @@
/* PROTOLIB1 */
/*
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -186,3 +185,49 @@ char *__s_api_get_canonical_name(
ns_ldap_entry_t *entry,
ns_ldap_attr_t *attrptr,
int case_ignore);
+
+void __ns_ldap_setServer(
+ int set);
+
+ns_ldap_error_t *__ns_ldap_LoadConfiguration(
+ void);
+
+ns_ldap_error_t *__ns_ldap_DumpConfiguration(
+ char *file);
+
+ns_ldap_error_t *__ns_ldap_DumpLdif(
+ char *filename);
+
+ns_ldap_error_t *__ns_ldap_print_config(
+ int verbose);
+
+void __ns_ldap_default_config(
+ void);
+
+int __ns_ldap_download(
+ const char *profile,
+ char *addr,
+ char *baseDN,
+ ns_ldap_error_t **errorp);
+
+int __ns_ldap_check_dns_preq(
+ int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ const char *fname,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp);
+
+int __ns_ldap_check_gssapi_preq(
+ int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp);
+
+int __ns_ldap_check_all_preq(
+ int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp);
diff --git a/usr/src/lib/libsldap/common/mapfile-vers b/usr/src/lib/libsldap/common/mapfile-vers
index 37fd9dd2be..18a1ddd867 100644
--- a/usr/src/lib/libsldap/common/mapfile-vers
+++ b/usr/src/lib/libsldap/common/mapfile-vers
@@ -32,6 +32,12 @@ SUNWprivate_1.1 {
global:
__ns_ldap_getAcctMgmt;
__s_api_get_canonical_name;
+ __ns_ldap_getAttrStruct;
+ __ns_ldap_self_gssapi_config;
+ __ns_ldap_self_gssapi_only_set;
+ __ns_ldap_check_dns_preq;
+ __ns_ldap_check_gssapi_preq;
+ __ns_ldap_check_all_preq;
} SUNWprivate_1.0;
SUNWprivate_1.0 {
diff --git a/usr/src/lib/libsldap/common/ns_cache_door.h b/usr/src/lib/libsldap/common/ns_cache_door.h
index 21d32b5292..d6c9e3a56e 100644
--- a/usr/src/lib/libsldap/common/ns_cache_door.h
+++ b/usr/src/lib/libsldap/common/ns_cache_door.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -164,6 +163,8 @@ typedef union {
#define NS_CACHE_NORESP "1"
#define NS_CACHE_NEXT "2"
#define NS_CACHE_WRITE "3"
+#define NS_CACHE_ADDR_HOSTNAME "H"
+#define NS_CACHE_ADDR_IP "I"
/*
* GETCACHE/SETCACHE data flags
diff --git a/usr/src/lib/libsldap/common/ns_common.c b/usr/src/lib/libsldap/common/ns_common.c
index 2089509afc..1244b22710 100644
--- a/usr/src/lib/libsldap/common/ns_common.c
+++ b/usr/src/lib/libsldap/common/ns_common.c
@@ -2223,16 +2223,24 @@ __s_api_removeServer(const char *server)
(void) memset(ret, 0, sizeof (ns_server_info_t));
(void) memset(space.s_b, 0, DOORBUFFERSIZE);
- adata = (sizeof (ldap_call_t) + strlen(ireq) +1);
+ adata = (sizeof (ldap_call_t) + strlen(ireq) +
+ strlen(NS_CACHE_ADDR_IP) + 1);
adata += strlen(DOORLINESEP) + 1;
adata += strlen(server) + 1;
ndata = sizeof (space);
space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
- (void) strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len);
- (void) strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len);
- (void) strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len);
+ if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
+ return (-1);
+ if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
+ NS_CACHE_ADDR_IP, len) >= len)
+ return (-1);
+ if (strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len) >=
+ len)
+ return (-1);
+ if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len) >= len)
+ return (-1);
sptr = &space.s_d;
/* try to remove the server via the door interface */
diff --git a/usr/src/lib/libsldap/common/ns_config.c b/usr/src/lib/libsldap/common/ns_config.c
index 1e52104c6c..fb24f7721b 100644
--- a/usr/src/lib/libsldap/common/ns_config.c
+++ b/usr/src/lib/libsldap/common/ns_config.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -140,6 +139,7 @@ static ns_enum_map ns_auth_enum_v2[] = {
{ ENUM2INT(NS_LDAP_EA_SASL_DIGEST_MD5_CONF),
"sasl/DIGEST-MD5:auth-conf" },
{ ENUM2INT(NS_LDAP_EA_SASL_EXTERNAL), "sasl/EXTERNAL" },
+ { ENUM2INT(NS_LDAP_EA_SASL_GSSAPI), "sasl/GSSAPI" },
{ ENUM2INT(NS_LDAP_EA_TLS_NONE), "tls:none" },
{ ENUM2INT(NS_LDAP_EA_TLS_SIMPLE), "tls:simple" },
{ ENUM2INT(NS_LDAP_EA_TLS_SASL_CRAM_MD5), "tls:sasl/CRAM-MD5" },
@@ -1005,7 +1005,7 @@ __s_api_crosscheck(ns_config_t *ptr, char *errstr, int check_dn)
int i, len, cnt;
const char *begin;
char **ppc;
- int *pi;
+ int *pi, self, gssapi;
if (ptr == NULL)
@@ -1171,7 +1171,38 @@ __s_api_crosscheck(ns_config_t *ptr, char *errstr, int check_dn)
}
ptr->paramList[NS_LDAP_EXP_P].ns_tm = tm;
}
-
+ /*
+ * If credential level self is defined, there should be
+ * at least an auth method sasl/GSSAPI and vice versa.
+ */
+ self = 0;
+ cnt = ptr->paramList[NS_LDAP_CREDENTIAL_LEVEL_P].ns_acnt;
+ for (i = 0; i < cnt; i++) {
+ if (ptr->paramList[NS_LDAP_CREDENTIAL_LEVEL_P].ns_pi[i] ==
+ NS_LDAP_CRED_SELF)
+ self++;
+ }
+ gssapi = 0;
+ cnt = ptr->paramList[NS_LDAP_AUTH_P].ns_acnt;
+ for (i = 0; i < cnt; i++) {
+ if (ptr->paramList[NS_LDAP_AUTH_P].ns_pi[i] ==
+ NS_LDAP_EA_SASL_GSSAPI)
+ gssapi++;
+ }
+ if (gssapi == 0 && self > 0) {
+ (void) snprintf(errstr, MAXERROR,
+ gettext("Configuration Error: "
+ "Credential level self requires "
+ "authentication method sasl/GSSAPI"));
+ return (NS_PARSE_ERR);
+ }
+ if (gssapi > 0 && self == 0) {
+ (void) snprintf(errstr, MAXERROR,
+ gettext("Configuration Error: "
+ "Authentication method sasl/GSSAPI "
+ "requires credential level self"));
+ return (NS_PARSE_ERR);
+ }
return (NS_SUCCESS);
}
@@ -3453,6 +3484,12 @@ __s_api_AuthEnumtoStruct(const EnumAuthType_t i)
ap->type = NS_LDAP_AUTH_SASL;
ap->saslmech = NS_LDAP_SASL_EXTERNAL;
break;
+ case NS_LDAP_EA_SASL_GSSAPI:
+ ap->type = NS_LDAP_AUTH_SASL;
+ ap->saslmech = NS_LDAP_SASL_GSSAPI;
+ ap->saslopt = NS_LDAP_SASLOPT_INT |
+ NS_LDAP_SASLOPT_PRIV;
+ break;
case NS_LDAP_EA_TLS_NONE:
ap->type = NS_LDAP_AUTH_TLS;
ap->tlstype = NS_LDAP_TLS_NONE;
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);
}
diff --git a/usr/src/lib/libsldap/common/ns_init.c b/usr/src/lib/libsldap/common/ns_init.c
index e95a99375f..e9b6842210 100644
--- a/usr/src/lib/libsldap/common/ns_init.c
+++ b/usr/src/lib/libsldap/common/ns_init.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,11 +27,25 @@
#include "ns_sldap.h"
#include "ns_internal.h"
+#include <syslog.h>
#pragma init(ns_ldap_init)
+thread_key_t ns_mtckey;
+
static void
ns_ldap_init()
{
get_environment(); /* load environment debugging options */
+
+ /*
+ * ns_mtckey is needed to allow the sharing of an
+ * ldap connection among multiple threads. Used
+ * mainly in ns_connect.c.
+ */
+ if (thr_keycreate(&ns_mtckey, ns_tsd_cleanup) != 0) {
+ syslog(LOG_ERR, "libsldap: unable to create the thread "
+ "key needed for sharing ldap connections");
+ MTperConn = 0;
+ }
}
diff --git a/usr/src/lib/libsldap/common/ns_internal.h b/usr/src/lib/libsldap/common/ns_internal.h
index 07fc60149e..699cb1dfa0 100644
--- a/usr/src/lib/libsldap/common/ns_internal.h
+++ b/usr/src/lib/libsldap/common/ns_internal.h
@@ -474,7 +474,7 @@ typedef enum EnumAuthType {
NS_LDAP_EA_SASL_DIGEST_MD5_INT = 5,
NS_LDAP_EA_SASL_DIGEST_MD5_CONF = 6,
NS_LDAP_EA_SASL_EXTERNAL = 7,
- NS_LDAP_EA_SASL_GSSAPI = 8, /* unsupported */
+ NS_LDAP_EA_SASL_GSSAPI = 8,
NS_LDAP_EA_SASL_SPNEGO = 9, /* unsupported */
NS_LDAP_EA_TLS_NONE = 10,
NS_LDAP_EA_TLS_SIMPLE = 11,
@@ -549,9 +549,15 @@ typedef int ConnectionID;
*/
typedef struct connection {
ConnectionID connectionId;
- boolean_t usedBit;
+ boolean_t usedBit; /* true if only used by */
+ /* one thread and not shared */
+ /* by other threads */
+ boolean_t notAvail; /* not sharable, delete */
+ /* when shared == 0 */
+ int shared; /* number of threads */
+ /* using this connection */
char *serverAddr;
- ns_cred_t *auth;
+ ns_cred_t *auth;
LDAP *ld;
thread_t threadID; /* thread ID using it */
struct ns_ldap_cookie *cookieInfo;
@@ -664,6 +670,23 @@ typedef struct ns_server_info {
} ns_server_info_t;
/*
+ * sasl callback function parameters
+ */
+typedef struct ns_sasl_cb_param {
+ char *mech;
+ char *authid;
+ char *authzid;
+ char *passwd;
+ char *realm;
+} ns_sasl_cb_param_t;
+
+/* self/sasl/gssapi variable */
+extern int sasl_gssapi_inited;
+
+/* Multiple threads per connection variable */
+extern int MTperConn;
+
+/*
* INTERNAL GLOBAL DEFINITIONS AND FUNCTION DECLARATIONS
*/
@@ -748,6 +771,29 @@ ns_ldap_error_t *__ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname);
ns_ldap_error_t *__ns_ldap_DumpConfiguration(char *filename);
ns_ldap_error_t *__ns_ldap_DumpLdif(char *filename);
int __ns_ldap_cache_ping();
+ns_ldap_error_t *__ns_ldap_print_config(int);
+void __ns_ldap_default_config();
+int __ns_ldap_download(const char *, char *, char *,
+ ns_ldap_error_t **);
+int
+__ns_ldap_check_dns_preq(int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ const char *fname,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp);
+int
+__ns_ldap_check_gssapi_preq(int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp);
+int
+__ns_ldap_check_all_preq(int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp);
/* internal un-exposed APIs */
ns_cred_t *__ns_ldap_dupAuth(const ns_cred_t *authp);
@@ -804,6 +850,19 @@ int __s_api_contain_account_usable_control_oid(char **oids);
char *__s_api_get_canonical_name(ns_ldap_entry_t *entry,
ns_ldap_attr_t *attrptr, int case_ignore);
+/* self/sasl/gssapi functions */
+int __s_api_sasl_bind_callback(
+ LDAP *ld,
+ unsigned flags,
+ void *defaults,
+ void *in);
+
+int __s_api_self_gssapi_only_get(void);
+int __s_api_sasl_gssapi_init(void);
+
+/* Multiple threads per connection functions */
+void ns_tsd_cleanup(void *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libsldap/common/ns_reads.c b/usr/src/lib/libsldap/common/ns_reads.c
index 8db18695c4..3239ab9a55 100644
--- a/usr/src/lib/libsldap/common/ns_reads.c
+++ b/usr/src/lib/libsldap/common/ns_reads.c
@@ -2220,10 +2220,18 @@ search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
LDAP_ERROR;
}
if (cookie->connectionId > -1) {
- DropConnection(
+ /*
+ * NS_LDAP_NEW_CONN
+ * indicates that the
+ * connection should
+ * be deleted, not
+ * kept alive
+ */
+ DropConnection(
cookie->connectionId,
NS_LDAP_NEW_CONN);
- cookie->connectionId = -1;
+ cookie->connectionId =
+ -1;
}
}
break;
@@ -3022,7 +3030,7 @@ __ns_ldap_auth(const ns_cred_t *auth,
if (!auth)
return (NS_LDAP_INVALID_PARAM);
- rc = __s_api_getConnection(NULL, flags,
+ rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN,
auth, &connectionId, &conp, errorp,
do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt);
if (rc == NS_LDAP_OP_FAILED && *errorp)
@@ -3047,6 +3055,20 @@ __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
return (NULL);
}
+ns_ldap_attr_t *
+__ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname)
+{
+ int i;
+
+ if (entry == NULL)
+ return (NULL);
+ for (i = 0; i < entry->attr_count; i++) {
+ if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
+ return (entry->attr_pair[i]);
+ }
+ return (NULL);
+}
+
/*ARGSUSED*/
int
diff --git a/usr/src/lib/libsldap/common/ns_sasl.c b/usr/src/lib/libsldap/common/ns_sasl.c
new file mode 100644
index 0000000000..fc708b735a
--- /dev/null
+++ b/usr/src/lib/libsldap/common/ns_sasl.c
@@ -0,0 +1,580 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <thread.h>
+#include <synch.h>
+#include <sasl/sasl.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <libscf.h>
+#include <libintl.h>
+#include <locale.h>
+#include "ns_sldap.h"
+#include "ns_internal.h"
+
+static int self_gssapi_only = 0;
+static mutex_t self_gssapi_only_lock = DEFAULTMUTEX;
+
+#define DNS_FMRI "svc:/network/dns/client:default"
+#define MSGSIZE 256
+
+#define NSSWITCH_CONF "/etc/nsswitch.conf"
+
+/*
+ * Error Handling
+ */
+#define CLIENT_FPRINTF if (mode_verbose && !mode_quiet) (void) fprintf
+
+/*
+ * One time initializtion
+ */
+int sasl_gssapi_inited = 0;
+static mutex_t sasl_gssapi_lock = DEFAULTMUTEX;
+int
+__s_api_sasl_gssapi_init(void) {
+ int rc = NS_LDAP_SUCCESS;
+ (void) mutex_lock(&sasl_gssapi_lock);
+ if (!sasl_gssapi_inited) {
+ if (getuid() == 0) {
+ if (system(
+ "/usr/sbin/cryptoadm disable metaslot")
+ == 0) {
+ syslog(LOG_WARNING,
+ "libsldap: Metaslot disabled "
+ "for self credential mode");
+ sasl_gssapi_inited = 1;
+ } else {
+ syslog(LOG_ERR,
+ "libsldap: Can't disable "
+ "Metaslot for self credential "
+ "mode");
+ rc = NS_LDAP_INTERNAL;
+ }
+ }
+ }
+ (void) mutex_unlock(&sasl_gssapi_lock);
+
+ return (rc);
+}
+
+/*
+ * nscd calls this function to set self_gssapi_only flag so libsldap performs
+ * sasl/GSSAPI bind only. Also see comments of __ns_ldap_self_gssapi_config.
+ *
+ * Input: flag 0 use any kind of connection
+ * 1 use self/gssapi connection only
+ */
+void
+__ns_ldap_self_gssapi_only_set(int flag) {
+ (void) mutex_lock(&self_gssapi_only_lock);
+ self_gssapi_only = flag;
+ (void) mutex_unlock(&self_gssapi_only_lock);
+}
+/*
+ * Get the flag value of self_gssapi_only
+ */
+int
+__s_api_self_gssapi_only_get(void) {
+ int flag;
+ (void) mutex_lock(&self_gssapi_only_lock);
+ flag = self_gssapi_only;
+ (void) mutex_unlock(&self_gssapi_only_lock);
+ return (flag);
+}
+/*
+ * nscd calls this function to detect the current native ldap configuration.
+ * The output are
+ * NS_LDAP_SELF_GSSAPI_CONFIG_NONE: No credential level self and
+ * no authentication method sasl/GSSAPI is
+ * configured.
+ * NS_LDAP_SELF_GSSAPI_CONFIG_ONLY: Only credential level self and
+ * authentication method sasl/GSSAPI are
+ * configured.
+ * NS_LDAP_SELF_GSSAPI_CONFIG_MIXED: More than one credential level are
+ * configured, including self.
+ * More than one authentication method
+ * are configured, including sasl/GSSAPI.
+ *
+ * __s_api_crosscheck makes sure self and sasl/GSSAPI pair up if they do
+ * get configured.
+ *
+ * When nscd detects it's MIXED case, it calls __ns_ldap_self_gssapi_only_set
+ * to force libsldap to do sasl/GSSAPI bind only for per-user lookup.
+ *
+ * Return: NS_LDAP_SUCCESS
+ * OTHERWISE - FAILURE
+ *
+ * Output: config. See comments above.
+ *
+ */
+int
+__ns_ldap_self_gssapi_config(ns_ldap_self_gssapi_config_t *config) {
+ int self = 0, other_level = 0, gssapi = 0, other_method = 0;
+ ns_auth_t **aMethod = NULL, **aNext = NULL;
+ int **cLevel = NULL, **cNext = NULL, rc;
+ ns_ldap_error_t *errp = NULL;
+
+ if (config == NULL)
+ return (NS_LDAP_INVALID_PARAM);
+ else
+ *config = NS_LDAP_SELF_GSSAPI_CONFIG_NONE;
+
+ /* Get the credential level list */
+ if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
+ (void ***)&cLevel, &errp)) != NS_LDAP_SUCCESS) {
+ if (errp)
+ (void) __ns_ldap_freeError(&errp);
+ if (cLevel)
+ (void) __ns_ldap_freeParam((void ***)&cLevel);
+ return (rc);
+ }
+ if (errp)
+ (void) __ns_ldap_freeError(&errp);
+ /* Get the authentication method list */
+ if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P,
+ (void ***)&aMethod, &errp)) != NS_LDAP_SUCCESS) {
+ if (errp)
+ (void) __ns_ldap_freeError(&errp);
+ if (cLevel)
+ (void) __ns_ldap_freeParam((void ***)&cLevel);
+ if (aMethod)
+ (void) __ns_ldap_freeParam((void ***)&aMethod);
+ return (rc);
+ }
+ if (errp)
+ (void) __ns_ldap_freeError(&errp);
+
+ if (cLevel == NULL || aMethod == NULL) {
+ if (cLevel)
+ (void) __ns_ldap_freeParam((void ***)&cLevel);
+ if (aMethod)
+ (void) __ns_ldap_freeParam((void ***)&aMethod);
+ return (NS_LDAP_SUCCESS);
+ }
+
+ for (cNext = cLevel; *cNext != NULL; cNext++) {
+ if (**cNext == NS_LDAP_CRED_SELF)
+ self++;
+ else
+ other_level++;
+ }
+ for (aNext = aMethod; *aNext != NULL; aNext++) {
+ if ((*aNext)->saslmech == NS_LDAP_SASL_GSSAPI)
+ gssapi++;
+ else
+ other_method++;
+ }
+
+ if (self > 0 && gssapi > 0) {
+ if (other_level == 0 && other_method == 0)
+ *config = NS_LDAP_SELF_GSSAPI_CONFIG_ONLY;
+ else
+ *config = NS_LDAP_SELF_GSSAPI_CONFIG_MIXED;
+ }
+
+ if (cLevel)
+ (void) __ns_ldap_freeParam((void ***)&cLevel);
+ if (aMethod)
+ (void) __ns_ldap_freeParam((void ***)&aMethod);
+ return (NS_LDAP_SUCCESS);
+}
+
+int
+__s_api_sasl_bind_callback(
+ /* LINTED E_FUNC_ARG_UNUSED */
+ LDAP *ld,
+ /* LINTED E_FUNC_ARG_UNUSED */
+ unsigned flags,
+ void *defaults,
+ void *in)
+{
+ char *ret = NULL;
+ sasl_interact_t *interact = in;
+ ns_sasl_cb_param_t *cred = (ns_sasl_cb_param_t *)defaults;
+
+
+ while (interact->id != SASL_CB_LIST_END) {
+
+ switch (interact->id) {
+
+ case SASL_CB_GETREALM:
+ ret = cred->realm;
+ break;
+ case SASL_CB_AUTHNAME:
+ ret = cred->authid;
+ break;
+ case SASL_CB_PASS:
+ ret = cred->passwd;
+ break;
+ case SASL_CB_USER:
+ ret = cred->authzid;
+ break;
+ case SASL_CB_NOECHOPROMPT:
+ case SASL_CB_ECHOPROMPT:
+ default:
+ break;
+ }
+
+ if (ret) {
+ interact->result = strdup(ret);
+ if (interact->result == NULL)
+ return (LDAP_NO_MEMORY);
+
+ interact->len = strlen(ret);
+ } else {
+ interact->result = NULL;
+ interact->len = 0;
+ }
+ interact++;
+ }
+
+ return (LDAP_SUCCESS);
+}
+
+/*
+ * Find "dbase: service1 [...] services2" in fname and return
+ * " service1 [...] services2"
+ * e.g.
+ * Find "hosts: files dns" and return " files dns"
+ */
+static char *
+__ns_nsw_getconfig(const char *dbase, const char *fname, int *errp)
+{
+ FILE *fp = NULL;
+ char *linep, *retp = NULL;
+ char lineq[BUFSIZ], db_colon[BUFSIZ];
+
+ if ((fp = fopen(fname, "rF")) == NULL) {
+ *errp = NS_LDAP_CONFIG;
+ return (NULL);
+ }
+ *errp = NS_LDAP_SUCCESS;
+
+ while (linep = fgets(lineq, BUFSIZ, fp)) {
+ char *tokenp, *comment;
+
+ /*
+ * Ignore portion of line following the comment character '#'.
+ */
+ if ((comment = strchr(linep, '#')) != NULL) {
+ *comment = '\0';
+ }
+ if ((*linep == '\0') || isspace(*linep)) {
+ continue;
+ }
+ (void) snprintf(db_colon, BUFSIZ, "%s:", dbase);
+ if ((tokenp = strstr(linep, db_colon)) == NULL) {
+ continue; /* ignore this line */
+ } else {
+ /* skip "dbase:" */
+ retp = strdup(tokenp + strlen(db_colon));
+ if (retp == NULL)
+ *errp = NS_LDAP_MEMORY;
+ }
+ }
+
+ (void) fclose(fp);
+ return (retp);
+}
+/*
+ * Test the configurations of the "hosts" and "ipnodes"
+ * dns has to be present and appear before ldap
+ * e.g.
+ * "dns" , "dns files" "dns ldap files", "files dns" are allowed.
+ *
+ * Kerberos requires dns or it'd fail.
+ */
+static int
+test_dns_nsswitch(int foreground,
+ const char *fname,
+ ns_ldap_error_t **errpp) {
+ int ldap, dns, i, pserr, rc = NS_LDAP_SUCCESS;
+ char *db[3] = {"hosts", "ipnodes", NULL};
+ char buf[MSGSIZE], *conf = NULL, *token = NULL, *last = NULL;
+
+ for (i = 0; db[i] != NULL; i++) {
+ conf = __ns_nsw_getconfig(db[i], fname, &pserr);
+
+ if (conf == NULL) {
+ (void) snprintf(buf, MSGSIZE,
+ gettext("Parsing %s to find \"%s:\" "
+ "failed. err: %d"),
+ fname, db[i], pserr);
+ if (foreground) {
+ (void) fprintf(stderr, "%s\n", buf);
+ } else {
+ MKERROR(LOG_ERR, *errpp, NS_LDAP_CONFIG,
+ strdup(buf), NS_LDAP_MEMORY);
+ }
+ return (pserr);
+ }
+ ldap = dns = 0;
+ token = strtok_r(conf, " ", &last);
+ while (token != NULL) {
+ if (strncmp(token, "dns", 3) == 0) {
+ if (ldap) {
+ (void) snprintf(buf, MSGSIZE,
+ gettext("%s: ldap can't appear "
+ "before dns"), db[i]);
+ if (foreground) {
+ (void) fprintf(stderr,
+ "start: %s\n",
+ buf);
+ } else {
+ MKERROR(LOG_ERR, *errpp,
+ NS_LDAP_CONFIG,
+ strdup(buf),
+ NS_LDAP_MEMORY);
+ }
+ free(conf);
+ return (NS_LDAP_CONFIG);
+ } else {
+ dns++;
+ }
+ } else if (strncmp(token, "ldap", 4) == 0) {
+ ldap++;
+ }
+ /* next token */
+ token = strtok_r(NULL, " ", &last);
+ }
+ if (conf) {
+ free(conf);
+ conf = NULL;
+ }
+ if (!dns) {
+ (void) snprintf(buf, MSGSIZE,
+ gettext("%s: dns is not defined in "
+ "%s"), db[i], fname);
+ if (foreground) {
+ (void) fprintf(stderr, "start: %s\n", buf);
+ } else {
+ MKERROR(LOG_ERR, *errpp, NS_LDAP_CONFIG,
+ strdup(buf), NS_LDAP_MEMORY);
+ }
+ rc = NS_LDAP_CONFIG;
+ break;
+ }
+ }
+ return (rc);
+}
+
+static boolean_t
+is_service(const char *fmri, const char *state) {
+ char *st;
+ boolean_t result = B_FALSE;
+
+ if ((st = smf_get_state(fmri)) != NULL) {
+ if (strcmp(st, state) == 0)
+ result = B_TRUE;
+ free(st);
+ }
+ return (result);
+}
+
+
+/*
+ * This function checks dns prerequisites for sasl/GSSAPI bind.
+ * It's called only if config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY ||
+ * config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED.
+ */
+int
+__ns_ldap_check_dns_preq(int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ const char *fname,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp) {
+
+ char buf[MSGSIZE];
+ int retcode = NS_LDAP_SUCCESS;
+ int loglevel;
+
+ if (errpp)
+ *errpp = NULL;
+ else
+ return (NS_LDAP_INVALID_PARAM);
+
+ if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
+ /* Shouldn't happen. Check this value just in case */
+ return (NS_LDAP_SUCCESS);
+
+ if ((retcode = test_dns_nsswitch(foreground, fname, errpp)) !=
+ NS_LDAP_SUCCESS)
+ return (retcode);
+
+ if (is_service(DNS_FMRI, SCF_STATE_STRING_ONLINE)) {
+ if (foreground) {
+ CLIENT_FPRINTF(stdout, "start: %s\n",
+ gettext("DNS client is enabled"));
+ } else {
+ syslog(LOG_INFO, "%s",
+ gettext("DNS client is enabled"));
+ }
+ return (NS_LDAP_SUCCESS);
+ } else {
+ if (config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY) {
+ (void) snprintf(buf, MSGSIZE,
+ gettext("%s: DNS client is not enabled. "
+ "Run \"svcadm enable %s\". %s."),
+ "Error", DNS_FMRI, "Abort");
+ loglevel = LOG_ERR;
+ retcode = NS_LDAP_CONFIG;
+ } else if (config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED) {
+ (void) snprintf(buf, MSGSIZE,
+ gettext("%s: DNS client is not enabled. "
+ "Run \"svcadm enable %s\". %s."
+ "Fall back to other cred level/bind. "),
+ "Warning", DNS_FMRI, "Continue");
+ loglevel = LOG_INFO;
+ retcode = NS_LDAP_SUCCESS;
+ }
+
+ if (foreground) {
+ (void) fprintf(stderr, "start: %s\n", buf);
+ } else {
+ MKERROR(loglevel, *errpp, retcode, strdup(buf),
+ NS_LDAP_MEMORY);
+ }
+ return (retcode);
+ }
+}
+
+/*
+ * Check if sasl/GSSAPI works
+ */
+int
+__ns_ldap_check_gssapi_preq(int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp) {
+
+ int rc;
+ char *attr[2] = {"dn", NULL}, buf[MSGSIZE];
+ ns_cred_t cred;
+ ns_ldap_result_t *result = NULL;
+ int loglevel;
+
+ if (errpp)
+ *errpp = NULL;
+ else
+ return (NS_LDAP_INVALID_PARAM);
+
+ if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
+ /* Don't need to check */
+ return (NS_LDAP_SUCCESS);
+
+ (void) memset(&cred, 0, sizeof (ns_cred_t));
+
+ cred.auth.type = NS_LDAP_AUTH_SASL;
+ cred.auth.tlstype = NS_LDAP_TLS_NONE;
+ cred.auth.saslmech = NS_LDAP_SASL_GSSAPI;
+
+ rc = __ns_ldap_list(NULL, (const char *)"objectclass=*",
+ NULL, (const char **)attr, &cred,
+ NS_LDAP_SCOPE_BASE, &result, errpp, NULL, NULL);
+ if (result)
+ (void) __ns_ldap_freeResult(&result);
+
+ if (rc == NS_LDAP_SUCCESS) {
+ if (foreground) {
+ CLIENT_FPRINTF(stdout, "start: %s\n",
+ gettext("sasl/GSSAPI bind works"));
+ } else {
+ syslog(LOG_INFO, "%s",
+ gettext("sasl/GSSAPI bind works"));
+ }
+ return (NS_LDAP_SUCCESS);
+ } else {
+ if (config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY) {
+ (void) snprintf(buf, MSGSIZE,
+ gettext("%s: sasl/GSSAPI bind is not "
+ "working. %s."),
+ "Error", "Abort");
+ loglevel = LOG_ERR;
+ } else if (config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED) {
+ (void) snprintf(buf, MSGSIZE,
+ gettext("%s: sasl/GSSAPI bind is not "
+ "working. Fall back to other cred "
+ "level/bind. %s."),
+ "Warning", "Continue");
+ loglevel = LOG_INFO;
+ /* reset return code */
+ rc = NS_LDAP_SUCCESS;
+ }
+
+ if (foreground) {
+ (void) fprintf(stderr, "start: %s\n", buf);
+ } else {
+ MKERROR(loglevel, *errpp, rc, strdup(buf),
+ NS_LDAP_MEMORY);
+ }
+ return (rc);
+ }
+}
+/*
+ * This is called by ldap_cachemgr to check dns and gssapi prequisites.
+ */
+int
+__ns_ldap_check_all_preq(int foreground,
+ int mode_verbose,
+ int mode_quiet,
+ ns_ldap_self_gssapi_config_t config,
+ ns_ldap_error_t **errpp) {
+
+ int rc;
+
+ if (errpp)
+ *errpp = NULL;
+ else
+ return (NS_LDAP_INVALID_PARAM);
+
+ if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
+ /* Don't need to check */
+ return (NS_LDAP_SUCCESS);
+
+ if ((rc = __ns_ldap_check_dns_preq(foreground,
+ mode_verbose, mode_quiet, NSSWITCH_CONF,
+ config, errpp)) != NS_LDAP_SUCCESS)
+ return (rc);
+ if ((rc = __ns_ldap_check_gssapi_preq(foreground,
+ mode_verbose, mode_quiet, config, errpp)) !=
+ NS_LDAP_SUCCESS)
+ return (rc);
+
+ return (NS_LDAP_SUCCESS);
+}
diff --git a/usr/src/lib/libsldap/common/ns_sldap.h b/usr/src/lib/libsldap/common/ns_sldap.h
index 0138c1e3d5..59d7ae516a 100644
--- a/usr/src/lib/libsldap/common/ns_sldap.h
+++ b/usr/src/lib/libsldap/common/ns_sldap.h
@@ -91,7 +91,7 @@ typedef enum ScopeType {
typedef enum CredLevel {
NS_LDAP_CRED_ANON = 0,
NS_LDAP_CRED_PROXY = 1,
- NS_LDAP_CRED_SELF = 2 /* currently not supported */
+ NS_LDAP_CRED_SELF = 2
} CredLevel_t;
typedef enum AuthType {
@@ -113,14 +113,14 @@ typedef enum SaslMech {
NS_LDAP_SASL_CRAM_MD5 = 1,
NS_LDAP_SASL_DIGEST_MD5 = 2,
NS_LDAP_SASL_EXTERNAL = 3, /* currently not supported */
- NS_LDAP_SASL_GSSAPI = 4, /* currently not supported */
+ NS_LDAP_SASL_GSSAPI = 4,
NS_LDAP_SASL_SPNEGO = 5 /* currently not supported */
} SaslMech_t;
typedef enum SaslOpt {
NS_LDAP_SASLOPT_NONE = 0,
- NS_LDAP_SASLOPT_INT = 1, /* currently not supported */
- NS_LDAP_SASLOPT_PRIV = 2 /* currently not supported */
+ NS_LDAP_SASLOPT_INT = 1,
+ NS_LDAP_SASLOPT_PRIV = 2
} SaslOpt_t;
typedef enum PrefOnly {
@@ -211,6 +211,17 @@ typedef enum {
} ParamIndexType;
/*
+ * NONE - No self / SASL/GSSAPI configured
+ * ONLY - Only self / SASL/GSSAPI configured
+ * MIXED - self / SASL/GSSAPI is mixed with other types of configuration
+ */
+typedef enum {
+ NS_LDAP_SELF_GSSAPI_CONFIG_NONE = 0,
+ NS_LDAP_SELF_GSSAPI_CONFIG_ONLY = 1,
+ NS_LDAP_SELF_GSSAPI_CONFIG_MIXED = 2
+} ns_ldap_self_gssapi_config_t;
+
+/*
* __ns_ldap_*() return codes
*/
typedef enum {
@@ -614,6 +625,10 @@ char **__ns_ldap_getAttr(
const ns_ldap_entry_t *entry,
const char *attrname);
+ns_ldap_attr_t *__ns_ldap_getAttrStruct(
+ const ns_ldap_entry_t *entry,
+ const char *attrname);
+
int __ns_ldap_getServiceAuthMethods(
const char *service,
ns_auth_t ***auth,
@@ -666,6 +681,12 @@ int __ns_ldap_getParamType(
int __ns_ldap_getAcctMgmt(
const char *user,
AcctUsableResponse_t *acctResp);
+void
+__ns_ldap_self_gssapi_only_set(
+ int flag);
+int
+__ns_ldap_self_gssapi_config(
+ ns_ldap_self_gssapi_config_t *config);
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libsldap/common/ns_writes.c b/usr/src/lib/libsldap/common/ns_writes.c
index dadec06207..474db98161 100644
--- a/usr/src/lib/libsldap/common/ns_writes.c
+++ b/usr/src/lib/libsldap/common/ns_writes.c
@@ -691,7 +691,7 @@ write_state_machine(
switch (state) {
case W_EXIT:
if (connectionId > -1)
- DropConnection(connectionId, 0);
+ DropConnection(connectionId, NS_LDAP_NEW_CONN);
if (ref_list)
__s_api_deleteRefInfo(ref_list);
if (target_dn && target_dn_allocated)
@@ -723,7 +723,7 @@ write_state_machine(
break;
case GET_CONNECTION:
rc = __s_api_getConnection(NULL,
- flags,
+ flags | NS_LDAP_NEW_CONN,
cred,
&connectionId,
&conp,
@@ -912,7 +912,7 @@ write_state_machine(
if (*errorp)
(void) __ns_ldap_freeError(errorp);
if (connectionId > -1)
- DropConnection(connectionId, 0);
+ DropConnection(connectionId, NS_LDAP_NEW_CONN);
rc = __s_api_getConnection(current_ref->refHost,
0,
cred,
diff --git a/usr/src/lib/libsldap/req.flg b/usr/src/lib/libsldap/req.flg
index 6ced3afe87..25da177a24 100644
--- a/usr/src/lib/libsldap/req.flg
+++ b/usr/src/lib/libsldap/req.flg
@@ -28,3 +28,4 @@
echo_file usr/src/lib/libldap5/include/ldap/solaris-priv.h
echo_file usr/src/lib/libldap5/include/ldap/ldappr.h
+echo_file usr/src/lib/libldap5/include/ldap/solaris-int.h