1e1dd0a2fSth160488 /*
2e1dd0a2fSth160488 * CDDL HEADER START
3e1dd0a2fSth160488 *
4e1dd0a2fSth160488 * The contents of this file are subject to the terms of the
5e1dd0a2fSth160488 * Common Development and Distribution License (the "License").
6e1dd0a2fSth160488 * You may not use this file except in compliance with the License.
7e1dd0a2fSth160488 *
8e1dd0a2fSth160488 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e1dd0a2fSth160488 * or http://www.opensolaris.org/os/licensing.
10e1dd0a2fSth160488 * See the License for the specific language governing permissions
11e1dd0a2fSth160488 * and limitations under the License.
12e1dd0a2fSth160488 *
13e1dd0a2fSth160488 * When distributing Covered Code, include this CDDL HEADER in each
14e1dd0a2fSth160488 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e1dd0a2fSth160488 * If applicable, add the following below this CDDL HEADER, with the
16e1dd0a2fSth160488 * fields enclosed by brackets "[]" replaced with your own identifying
17e1dd0a2fSth160488 * information: Portions Copyright [yyyy] [name of copyright owner]
18e1dd0a2fSth160488 *
19e1dd0a2fSth160488 * CDDL HEADER END
20e1dd0a2fSth160488 */
21e1dd0a2fSth160488 /*
22e1dd0a2fSth160488 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23e1dd0a2fSth160488 * Use is subject to license terms.
24e1dd0a2fSth160488 */
25e1dd0a2fSth160488
26e1dd0a2fSth160488 #pragma ident "%Z%%M% %I% %E% SMI"
27e1dd0a2fSth160488
28e1dd0a2fSth160488 #include <string.h>
29e1dd0a2fSth160488 #include <errno.h>
30e1dd0a2fSth160488 #include <syslog.h>
31e1dd0a2fSth160488 #include <procfs.h>
32e1dd0a2fSth160488 #include <unistd.h>
33e1dd0a2fSth160488 #include <fcntl.h>
34e1dd0a2fSth160488 #include <libintl.h>
35e1dd0a2fSth160488 #include <atomic.h>
36e1dd0a2fSth160488 #include <pthread.h>
37e1dd0a2fSth160488 #include <sys/mman.h>
38e1dd0a2fSth160488 #include <time.h>
39e1dd0a2fSth160488 #include "solaris-int.h"
40e1dd0a2fSth160488 #include "ns_connmgmt.h"
41e1dd0a2fSth160488 #include "ns_cache_door.h"
42e1dd0a2fSth160488 #include "ns_internal.h"
43e1dd0a2fSth160488
44e1dd0a2fSth160488 /*
45e1dd0a2fSth160488 * Access (reference, shutdown, or reload) the current connection
46e1dd0a2fSth160488 * management control structure conn_mgmt_t.
47e1dd0a2fSth160488 */
48e1dd0a2fSth160488 #define NS_CONN_MGMT_OP_REF 1
49e1dd0a2fSth160488 #define NS_CONN_MGMT_OP_SHUTDOWN 2
50e1dd0a2fSth160488 #define NS_CONN_MGMT_OP_RELOAD_CONFIG 3
51e1dd0a2fSth160488 #define NS_CONN_MGMT_OP_NEW_CONFIG 4
52e1dd0a2fSth160488 #define NS_CONN_MGMT_OP_LIB_INIT 5
53e1dd0a2fSth160488
54e1dd0a2fSth160488 static ns_conn_mgmt_t *access_conn_mgmt(int);
55e1dd0a2fSth160488 static ns_conn_mgmt_t *release_conn_mgmt(ns_conn_mgmt_t *, boolean_t);
56e1dd0a2fSth160488 static int close_conn_mt(ns_conn_mt_t *, int, ns_ldap_error_t **,
57e1dd0a2fSth160488 ns_conn_user_t *);
58e1dd0a2fSth160488 static int close_conn_mt_when_nouser(ns_conn_mt_t *cm);
59e1dd0a2fSth160488 void shutdown_all_conn_mt(ns_conn_mgmt_t *cmg);
60e1dd0a2fSth160488 static int conn_signal(ns_conn_mt_t *);
61e1dd0a2fSth160488 static int conn_wait(ns_conn_mt_t *, ns_conn_user_t *);
62e1dd0a2fSth160488 static void close_conn_mt_by_procchg(ns_conn_mt_t *cm, int rc, char *errmsg);
63e1dd0a2fSth160488 static ns_conn_mgmt_t *proc_server_change(ns_server_status_change_t *chg,
64e1dd0a2fSth160488 ns_conn_mgmt_t *cmg);
65e1dd0a2fSth160488 static void get_preferred_servers(boolean_t, boolean_t, ns_conn_mgmt_t *);
66e1dd0a2fSth160488 static void start_thread();
67e1dd0a2fSth160488
68e1dd0a2fSth160488 static ns_conn_mgmt_t *ns_connmgmt = NULL;
69e1dd0a2fSth160488 static ns_conn_mgmt_t *ns_connmgmt_parent = NULL;
70e1dd0a2fSth160488 static mutex_t ns_connmgmt_lock = DEFAULTMUTEX;
71e1dd0a2fSth160488 static boolean_t ns_connmgmt_shutting_down = B_FALSE;
72e1dd0a2fSth160488
73e1dd0a2fSth160488 #define NS_CONN_MSG_NO_CONN_MGMT gettext( \
74e1dd0a2fSth160488 "libsldap: unable to allocate the connection management control")
75e1dd0a2fSth160488 #define NS_CONN_MSG_NO_MTC_KEY gettext( \
76e1dd0a2fSth160488 "libsldap: unable to allocate the TSD key for per-thread ldap error")
77e1dd0a2fSth160488 #define NS_CONN_MSG_NO_CMG_KEY gettext( \
78e1dd0a2fSth160488 "libsldap: unable to allocate the TSD key for connection management")
79e1dd0a2fSth160488 #define NS_CONN_MSG_SHUTDOWN gettext("libsldap: library is being unloaded")
80e1dd0a2fSth160488 #define NS_CONN_MSG_RELOADED gettext( \
81e1dd0a2fSth160488 "libsldap: configuration has been reloaded")
82e1dd0a2fSth160488 #define NS_CONN_MSG_SHUTDOWN_RELOADED gettext( \
83e1dd0a2fSth160488 "libsldap: library unloaded or configuration has been reloaded")
84e1dd0a2fSth160488 #define NS_CONN_MSG_BAD_CACHEMGR_DATA gettext( \
85e1dd0a2fSth160488 "libsldap: received incorrect data from ldap_cachemgr")
86e1dd0a2fSth160488 #define NS_CONN_MSG_MEMORY_ERROR gettext( \
87e1dd0a2fSth160488 "libsldap: unable to allocate memory")
88e1dd0a2fSth160488 #define NS_CONN_MSG_NO_PROCCHG_THREAD gettext( \
89e1dd0a2fSth160488 "libsldap: unable to start the server monitor thread (%s)")
90e1dd0a2fSth160488 #define NS_CONN_MSG_DOWN_FROM_CACHEMGR gettext( \
91e1dd0a2fSth160488 "libsldap: server down reported by ldap_cachemgr")
92e1dd0a2fSth160488
93e1dd0a2fSth160488 static int ns_conn_free = 1;
94e1dd0a2fSth160488 #define NS_CONN_UNLOCK_AND_FREE(free, cm, cmg) \
95e1dd0a2fSth160488 { \
96e1dd0a2fSth160488 (void) mutex_unlock(&(cm)->lock); \
97e1dd0a2fSth160488 if (free == 1) \
98e1dd0a2fSth160488 cmg = free_conn_mt((cm), 1); \
99e1dd0a2fSth160488 if (cmg != NULL) \
100e1dd0a2fSth160488 (void) mutex_unlock(&(cmg)->lock); \
101e1dd0a2fSth160488 }
102e1dd0a2fSth160488
103e1dd0a2fSth160488 #define NS_CONN_CHECK_ABORT_AND_LOCK(cmg, cu, errp) \
104e1dd0a2fSth160488 { \
105e1dd0a2fSth160488 char *msg = NULL; \
106e1dd0a2fSth160488 (void) mutex_lock(&(cmg)->lock); \
107e1dd0a2fSth160488 if ((cmg)->shutting_down == B_TRUE) \
108e1dd0a2fSth160488 msg = NS_CONN_MSG_SHUTDOWN; \
109e1dd0a2fSth160488 else if ((cmg)->cfg_reloaded == B_TRUE) \
110e1dd0a2fSth160488 msg = NS_CONN_MSG_RELOADED; \
111e1dd0a2fSth160488 if (msg != NULL) { \
112e1dd0a2fSth160488 (*errp) = __s_api_make_error(NS_LDAP_OP_FAILED, msg); \
113e1dd0a2fSth160488 (void) mutex_unlock(&(cmg)->lock); \
114e1dd0a2fSth160488 return (NS_LDAP_OP_FAILED); \
115e1dd0a2fSth160488 } \
116e1dd0a2fSth160488 }
117e1dd0a2fSth160488
118e1dd0a2fSth160488 /*
119e1dd0a2fSth160488 * TSD keys ns_mtckey and ns_cmgkey are for sharing ldap connections
120e1dd0a2fSth160488 * and their associated connection management structure among
121e1dd0a2fSth160488 * multiple threads. The pointers to the per-thread ldap error
122e1dd0a2fSth160488 * information and the connection management structure are
123e1dd0a2fSth160488 * saved in ns_mtckey and ns_cmgkey.
124e1dd0a2fSth160488 */
125e1dd0a2fSth160488 thread_key_t ns_mtckey = THR_ONCE_KEY;
126e1dd0a2fSth160488 thread_key_t ns_cmgkey = THR_ONCE_KEY;
127e1dd0a2fSth160488
128e1dd0a2fSth160488 /* Per thread LDAP error resides in thread-specific data (ns_mtckey) */
129e1dd0a2fSth160488 struct ldap_error {
130e1dd0a2fSth160488 int le_errno;
131e1dd0a2fSth160488 char *le_matched;
132e1dd0a2fSth160488 char *le_errmsg;
133e1dd0a2fSth160488 };
134e1dd0a2fSth160488
135e1dd0a2fSth160488 /* NULL struct ldap_error */
136e1dd0a2fSth160488 static struct ldap_error ldap_error_NULL = { LDAP_SUCCESS, NULL, NULL};
137e1dd0a2fSth160488
138e1dd0a2fSth160488 /* destructor: free the ldap error data in the thread specific area */
139e1dd0a2fSth160488 static void
ns_mtckey_cleanup(void * key)140e1dd0a2fSth160488 ns_mtckey_cleanup(void *key) {
141e1dd0a2fSth160488 struct ldap_error *le = (struct ldap_error *)key;
142e1dd0a2fSth160488
143e1dd0a2fSth160488 if (le == NULL)
144e1dd0a2fSth160488 return;
145e1dd0a2fSth160488 if (le->le_matched != NULL) {
146e1dd0a2fSth160488 ldap_memfree(le->le_matched);
147e1dd0a2fSth160488 }
148e1dd0a2fSth160488 if (le->le_errmsg != NULL) {
149e1dd0a2fSth160488 ldap_memfree(le->le_errmsg);
150e1dd0a2fSth160488 }
151e1dd0a2fSth160488 free(le);
152e1dd0a2fSth160488 }
153e1dd0a2fSth160488
154e1dd0a2fSth160488 /* Free/detach the thread specific data structures */
155e1dd0a2fSth160488 static void
conn_tsd_free()156e1dd0a2fSth160488 conn_tsd_free() {
157e1dd0a2fSth160488 void *tsd = NULL;
158e1dd0a2fSth160488 int rc;
159e1dd0a2fSth160488
160e1dd0a2fSth160488 /* free the per-thread ldap error info */
161e1dd0a2fSth160488 rc = thr_getspecific(ns_mtckey, &tsd);
162e1dd0a2fSth160488 if (rc == 0 && tsd != NULL)
163e1dd0a2fSth160488 ns_mtckey_cleanup(tsd);
164e1dd0a2fSth160488 (void) thr_setspecific(ns_mtckey, NULL);
165e1dd0a2fSth160488
166e1dd0a2fSth160488 /* detach the connection management control */
167e1dd0a2fSth160488 (void) thr_setspecific(ns_cmgkey, NULL);
168e1dd0a2fSth160488 }
169e1dd0a2fSth160488
170e1dd0a2fSth160488 /* per-thread callback function for allocating a mutex */
171e1dd0a2fSth160488 static void *
ns_mutex_alloc(void)172e1dd0a2fSth160488 ns_mutex_alloc(void)
173e1dd0a2fSth160488 {
174e1dd0a2fSth160488 mutex_t *mutexp = NULL;
175e1dd0a2fSth160488
176e1dd0a2fSth160488 if ((mutexp = malloc(sizeof (mutex_t))) != NULL) {
177e1dd0a2fSth160488 if (mutex_init(mutexp, USYNC_THREAD, NULL) != 0) {
178e1dd0a2fSth160488 free(mutexp);
179e1dd0a2fSth160488 mutexp = NULL;
180e1dd0a2fSth160488 }
181e1dd0a2fSth160488 }
182e1dd0a2fSth160488 return (mutexp);
183e1dd0a2fSth160488 }
184e1dd0a2fSth160488
185e1dd0a2fSth160488 /* per-thread callback function for freeing a mutex */
186e1dd0a2fSth160488 static void
ns_mutex_free(void * mutexp)187e1dd0a2fSth160488 ns_mutex_free(void *mutexp)
188e1dd0a2fSth160488 {
189e1dd0a2fSth160488 (void) mutex_destroy((mutex_t *)mutexp);
190e1dd0a2fSth160488 free(mutexp);
191e1dd0a2fSth160488 }
192e1dd0a2fSth160488
193e1dd0a2fSth160488 /*
194e1dd0a2fSth160488 * Function for setting up thread-specific data
195e1dd0a2fSth160488 * where per thread LDAP error and the pointer
196e1dd0a2fSth160488 * to the active connection management control
197e1dd0a2fSth160488 * are stored.
198e1dd0a2fSth160488 */
199e1dd0a2fSth160488 static int
conn_tsd_setup(ns_conn_mgmt_t * cmg)200e1dd0a2fSth160488 conn_tsd_setup(ns_conn_mgmt_t *cmg)
201e1dd0a2fSth160488 {
202e1dd0a2fSth160488 void *tsd;
203e1dd0a2fSth160488 int rc;
204e1dd0a2fSth160488
205e1dd0a2fSth160488 rc = thr_setspecific(ns_cmgkey, cmg);
206e1dd0a2fSth160488 if (rc != 0) /* must be ENOMEM */
207e1dd0a2fSth160488 return (-1);
208e1dd0a2fSth160488
209e1dd0a2fSth160488 /* return success if the ns_mtckey TSD is already set */
210e1dd0a2fSth160488 rc = thr_getspecific(ns_mtckey, &tsd);
211e1dd0a2fSth160488 if (rc == 0 && tsd != NULL)
212e1dd0a2fSth160488 return (0);
213e1dd0a2fSth160488
214e1dd0a2fSth160488 /* allocate and set the ns_mtckey TSD */
215e1dd0a2fSth160488 tsd = (void *) calloc(1, sizeof (struct ldap_error));
216e1dd0a2fSth160488 if (tsd == NULL)
217e1dd0a2fSth160488 return (-1);
218e1dd0a2fSth160488 rc = thr_setspecific(ns_mtckey, tsd);
219e1dd0a2fSth160488 if (rc != 0) { /* must be ENOMEM */
220e1dd0a2fSth160488 free(tsd);
221e1dd0a2fSth160488 return (-1);
222e1dd0a2fSth160488 }
223e1dd0a2fSth160488 return (0);
224e1dd0a2fSth160488 }
225e1dd0a2fSth160488
226e1dd0a2fSth160488 /* Callback function for setting the per thread LDAP error */
227e1dd0a2fSth160488 /*ARGSUSED*/
228e1dd0a2fSth160488 static void
set_ld_error(int err,char * matched,char * errmsg,void * dummy)229e1dd0a2fSth160488 set_ld_error(int err, char *matched, char *errmsg, void *dummy)
230e1dd0a2fSth160488 {
231e1dd0a2fSth160488 struct ldap_error *le;
232e1dd0a2fSth160488 int eno;
233e1dd0a2fSth160488
234e1dd0a2fSth160488 if ((eno = thr_getspecific(ns_mtckey, (void **)&le)) != 0) {
235e1dd0a2fSth160488 syslog(LOG_ERR, gettext(
236e1dd0a2fSth160488 "libsldap: set_ld_error: thr_getspecific failed (%s)."),
237e1dd0a2fSth160488 strerror(eno));
238e1dd0a2fSth160488 return;
239e1dd0a2fSth160488 }
240e1dd0a2fSth160488
241e1dd0a2fSth160488 /* play safe, do nothing if TSD pointer is NULL */
242e1dd0a2fSth160488 if (le == NULL) {
243e1dd0a2fSth160488 syslog(LOG_INFO, gettext(
244e1dd0a2fSth160488 "libsldap: set_ld_error: TSD pointer is NULL."));
245e1dd0a2fSth160488 return;
246e1dd0a2fSth160488 }
247e1dd0a2fSth160488
248e1dd0a2fSth160488 le->le_errno = err;
249e1dd0a2fSth160488
250e1dd0a2fSth160488 if (le->le_matched != NULL) {
251e1dd0a2fSth160488 ldap_memfree(le->le_matched);
252e1dd0a2fSth160488 le->le_matched = NULL;
253e1dd0a2fSth160488 }
254e1dd0a2fSth160488 le->le_matched = matched;
255e1dd0a2fSth160488
256e1dd0a2fSth160488 if (le->le_errmsg != NULL) {
257e1dd0a2fSth160488 ldap_memfree(le->le_errmsg);
258e1dd0a2fSth160488 le->le_errmsg = NULL;
259e1dd0a2fSth160488 }
260e1dd0a2fSth160488 le->le_errmsg = errmsg;
261e1dd0a2fSth160488 }
262e1dd0a2fSth160488
263e1dd0a2fSth160488 /* check and allocate the thread-specific data for using a MT connection */
264e1dd0a2fSth160488 static int
conn_tsd_check(ns_conn_mgmt_t * cmg)265e1dd0a2fSth160488 conn_tsd_check(ns_conn_mgmt_t *cmg)
266e1dd0a2fSth160488 {
267e1dd0a2fSth160488 if (conn_tsd_setup(cmg) != 0)
268e1dd0a2fSth160488 return (NS_LDAP_MEMORY);
269e1dd0a2fSth160488
270e1dd0a2fSth160488 return (NS_LDAP_SUCCESS);
271e1dd0a2fSth160488 }
272e1dd0a2fSth160488
273e1dd0a2fSth160488 /* Callback function for getting the per thread LDAP error */
274e1dd0a2fSth160488 /*ARGSUSED*/
275e1dd0a2fSth160488 static int
get_ld_error(char ** matched,char ** errmsg,void * dummy)276e1dd0a2fSth160488 get_ld_error(char **matched, char **errmsg, void *dummy)
277e1dd0a2fSth160488 {
278e1dd0a2fSth160488 struct ldap_error *le;
279e1dd0a2fSth160488 int eno;
280e1dd0a2fSth160488
281e1dd0a2fSth160488 if ((eno = thr_getspecific(ns_mtckey, (void **)&le)) != 0) {
282e1dd0a2fSth160488 syslog(LOG_ERR, gettext(
283e1dd0a2fSth160488 "libsldap: get_ld_error: thr_getspecific failed (%s)"),
284e1dd0a2fSth160488 strerror(eno));
285e1dd0a2fSth160488 return (eno);
286e1dd0a2fSth160488 }
287e1dd0a2fSth160488
288e1dd0a2fSth160488 /* play safe, return NULL error data, if TSD pointer is NULL */
289e1dd0a2fSth160488 if (le == NULL)
290e1dd0a2fSth160488 le = &ldap_error_NULL;
291e1dd0a2fSth160488
292e1dd0a2fSth160488 if (matched != NULL) {
293e1dd0a2fSth160488 *matched = le->le_matched;
294e1dd0a2fSth160488 }
295e1dd0a2fSth160488 if (errmsg != NULL) {
296e1dd0a2fSth160488 *errmsg = le->le_errmsg;
297e1dd0a2fSth160488 }
298e1dd0a2fSth160488 return (le->le_errno);
299e1dd0a2fSth160488 }
300e1dd0a2fSth160488
301e1dd0a2fSth160488 /* Callback function for setting per thread errno */
302e1dd0a2fSth160488 static void
set_errno(int err)303e1dd0a2fSth160488 set_errno(int err)
304e1dd0a2fSth160488 {
305e1dd0a2fSth160488 errno = err;
306e1dd0a2fSth160488 }
307e1dd0a2fSth160488
308e1dd0a2fSth160488 /* Callback function for getting per thread errno */
309e1dd0a2fSth160488 static int
get_errno(void)310e1dd0a2fSth160488 get_errno(void)
311e1dd0a2fSth160488 {
312e1dd0a2fSth160488 return (errno);
313e1dd0a2fSth160488 }
314e1dd0a2fSth160488
315e1dd0a2fSth160488 /* set up an ldap session 'ld' for sharing among multiple threads */
316e1dd0a2fSth160488 static int
setup_mt_conn(LDAP * ld)317e1dd0a2fSth160488 setup_mt_conn(LDAP *ld)
318e1dd0a2fSth160488 {
319e1dd0a2fSth160488
320e1dd0a2fSth160488 struct ldap_thread_fns tfns;
321e1dd0a2fSth160488 struct ldap_extra_thread_fns extrafns;
322e1dd0a2fSth160488 int rc;
323e1dd0a2fSth160488
324e1dd0a2fSth160488 /*
325e1dd0a2fSth160488 * Set the function pointers for dealing with mutexes
326e1dd0a2fSth160488 * and error information
327e1dd0a2fSth160488 */
328e1dd0a2fSth160488 (void) memset(&tfns, '\0', sizeof (struct ldap_thread_fns));
329e1dd0a2fSth160488 tfns.ltf_mutex_alloc = (void *(*)(void)) ns_mutex_alloc;
330e1dd0a2fSth160488 tfns.ltf_mutex_free = (void (*)(void *)) ns_mutex_free;
331e1dd0a2fSth160488 tfns.ltf_mutex_lock = (int (*)(void *)) mutex_lock;
332e1dd0a2fSth160488 tfns.ltf_mutex_unlock = (int (*)(void *)) mutex_unlock;
333e1dd0a2fSth160488 tfns.ltf_get_errno = get_errno;
334e1dd0a2fSth160488 tfns.ltf_set_errno = set_errno;
335e1dd0a2fSth160488 tfns.ltf_get_lderrno = get_ld_error;
336e1dd0a2fSth160488 tfns.ltf_set_lderrno = set_ld_error;
337e1dd0a2fSth160488 tfns.ltf_lderrno_arg = NULL;
338e1dd0a2fSth160488
339e1dd0a2fSth160488 /*
340e1dd0a2fSth160488 * Set up the ld to use those function pointers
341e1dd0a2fSth160488 */
342e1dd0a2fSth160488 rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS,
343e1dd0a2fSth160488 (void *) &tfns);
344e1dd0a2fSth160488 if (rc < 0) {
345e1dd0a2fSth160488 syslog(LOG_INFO, gettext("libsldap: ldap_set_option "
346e1dd0a2fSth160488 "(LDAP_OPT_THREAD_FN_PTRS)"));
347e1dd0a2fSth160488 return (0);
348e1dd0a2fSth160488 }
349e1dd0a2fSth160488
350e1dd0a2fSth160488 /*
351e1dd0a2fSth160488 * Set the function pointers for working with semaphores
352e1dd0a2fSth160488 */
353e1dd0a2fSth160488 (void) memset(&extrafns, '\0',
354e1dd0a2fSth160488 sizeof (struct ldap_extra_thread_fns));
355e1dd0a2fSth160488 extrafns.ltf_threadid_fn = (void * (*)(void))thr_self;
356e1dd0a2fSth160488 extrafns.ltf_mutex_trylock = NULL;
357e1dd0a2fSth160488 extrafns.ltf_sema_alloc = NULL;
358e1dd0a2fSth160488 extrafns.ltf_sema_free = NULL;
359e1dd0a2fSth160488 extrafns.ltf_sema_wait = NULL;
360e1dd0a2fSth160488 extrafns.ltf_sema_post = NULL;
361e1dd0a2fSth160488
362e1dd0a2fSth160488 /* Set up the ld to use those function pointers */
363e1dd0a2fSth160488 rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
364e1dd0a2fSth160488 (void *) &extrafns);
365e1dd0a2fSth160488 if (rc < 0) {
366e1dd0a2fSth160488 syslog(LOG_INFO, gettext("libsldap: ldap_set_option "
367e1dd0a2fSth160488 "(LDAP_OPT_EXTRA_THREAD_FN_PTRS)"));
368e1dd0a2fSth160488 return (0);
369e1dd0a2fSth160488 }
370e1dd0a2fSth160488
371e1dd0a2fSth160488 return (1);
372e1dd0a2fSth160488 }
373e1dd0a2fSth160488
374e1dd0a2fSth160488 /* set up an MT connection for sharing among multiple threads */
375e1dd0a2fSth160488 static int
setup_mt_ld(LDAP * ld,ns_conn_mgmt_t * cmg)376e1dd0a2fSth160488 setup_mt_ld(LDAP *ld, ns_conn_mgmt_t *cmg)
377e1dd0a2fSth160488 {
378e1dd0a2fSth160488 thread_t t = thr_self();
379e1dd0a2fSth160488
380e1dd0a2fSth160488 /* set up the per-thread data for using the MT connection */
381e1dd0a2fSth160488 if (conn_tsd_setup(cmg) == -1) {
382e1dd0a2fSth160488 syslog(LOG_WARNING,
383e1dd0a2fSth160488 gettext("libsldap: tid= %d: unable to set up TSD\n"), t);
384e1dd0a2fSth160488 return (-1);
385e1dd0a2fSth160488 }
386e1dd0a2fSth160488
387e1dd0a2fSth160488 if (setup_mt_conn(ld) == 0) {
388e1dd0a2fSth160488 /* multiple threads per connection not supported */
389e1dd0a2fSth160488 syslog(LOG_WARNING, gettext("libsldap: tid= %d: multiple "
390e1dd0a2fSth160488 "threads per connection not supported\n"), t);
391e1dd0a2fSth160488 conn_tsd_free();
392e1dd0a2fSth160488 return (-1);
393e1dd0a2fSth160488 }
394e1dd0a2fSth160488 return (0);
395e1dd0a2fSth160488 }
396e1dd0a2fSth160488
397e1dd0a2fSth160488 /*
398e1dd0a2fSth160488 * Check name and UID of process, if it is nscd.
399e1dd0a2fSth160488 *
400e1dd0a2fSth160488 * Input:
401e1dd0a2fSth160488 * pid : PID of checked process
402e1dd0a2fSth160488 * check_uid : check if UID == 0
403e1dd0a2fSth160488 * Output:
404e1dd0a2fSth160488 * B_TRUE : nscd detected
405e1dd0a2fSth160488 * B_FALSE : nscd not confirmed
406e1dd0a2fSth160488 */
407e1dd0a2fSth160488 static boolean_t
check_nscd_proc(pid_t pid,boolean_t check_uid)408e1dd0a2fSth160488 check_nscd_proc(pid_t pid, boolean_t check_uid)
409e1dd0a2fSth160488 {
410e1dd0a2fSth160488 psinfo_t pinfo;
411e1dd0a2fSth160488 char fname[MAXPATHLEN];
412e1dd0a2fSth160488 ssize_t ret;
413e1dd0a2fSth160488 int fd;
414e1dd0a2fSth160488
415e1dd0a2fSth160488 if (snprintf(fname, MAXPATHLEN, "/proc/%d/psinfo", pid) > 0) {
416e1dd0a2fSth160488 if ((fd = open(fname, O_RDONLY)) >= 0) {
417e1dd0a2fSth160488 ret = read(fd, &pinfo, sizeof (psinfo_t));
418e1dd0a2fSth160488 (void) close(fd);
419e1dd0a2fSth160488 if ((ret == sizeof (psinfo_t)) &&
420e1dd0a2fSth160488 (strcmp(pinfo.pr_fname, "nscd") == 0)) {
421e1dd0a2fSth160488 if (check_uid && (pinfo.pr_uid != 0))
422e1dd0a2fSth160488 return (B_FALSE);
423e1dd0a2fSth160488 return (B_TRUE);
424e1dd0a2fSth160488 }
425e1dd0a2fSth160488 }
426e1dd0a2fSth160488 }
427e1dd0a2fSth160488 return (B_FALSE);
428e1dd0a2fSth160488 }
429e1dd0a2fSth160488
430e1dd0a2fSth160488 /*
431e1dd0a2fSth160488 * Check if this process is peruser nscd.
432e1dd0a2fSth160488 */
433e1dd0a2fSth160488 boolean_t
__s_api_peruser_proc(void)434e1dd0a2fSth160488 __s_api_peruser_proc(void)
435e1dd0a2fSth160488 {
436e1dd0a2fSth160488 pid_t my_ppid;
437e1dd0a2fSth160488 static mutex_t nscdLock = DEFAULTMUTEX;
438e1dd0a2fSth160488 static pid_t checkedPpid = (pid_t)-1;
439e1dd0a2fSth160488 static boolean_t isPeruserNscd = B_FALSE;
440e1dd0a2fSth160488
441e1dd0a2fSth160488 my_ppid = getppid();
442e1dd0a2fSth160488
443e1dd0a2fSth160488 /*
444e1dd0a2fSth160488 * Already checked before for this process? If yes, return cached
445e1dd0a2fSth160488 * response.
446e1dd0a2fSth160488 */
447e1dd0a2fSth160488 if (my_ppid == checkedPpid) {
448e1dd0a2fSth160488 return (isPeruserNscd);
449e1dd0a2fSth160488 }
450e1dd0a2fSth160488
451e1dd0a2fSth160488 (void) mutex_lock(&nscdLock);
452e1dd0a2fSth160488
453e1dd0a2fSth160488 /* Check once more incase another thread has just complete this. */
454e1dd0a2fSth160488 if (my_ppid == checkedPpid) {
455e1dd0a2fSth160488 (void) mutex_unlock(&nscdLock);
456e1dd0a2fSth160488 return (isPeruserNscd);
457e1dd0a2fSth160488 }
458e1dd0a2fSth160488
459e1dd0a2fSth160488 /* Reinitialize to be sure there is no residue after fork. */
460e1dd0a2fSth160488 isPeruserNscd = B_FALSE;
461e1dd0a2fSth160488
462e1dd0a2fSth160488 /* Am I the nscd process? */
463e1dd0a2fSth160488 if (check_nscd_proc(getpid(), B_FALSE)) {
464e1dd0a2fSth160488 /* Is my parent the nscd process with UID == 0. */
465e1dd0a2fSth160488 isPeruserNscd = check_nscd_proc(my_ppid, B_TRUE);
466e1dd0a2fSth160488 }
467e1dd0a2fSth160488
468ca190d8dSmichen /* Remember for whom isPeruserNscd is. */
469e1dd0a2fSth160488 checkedPpid = my_ppid;
470e1dd0a2fSth160488
471e1dd0a2fSth160488 (void) mutex_unlock(&nscdLock);
472e1dd0a2fSth160488 return (isPeruserNscd);
473e1dd0a2fSth160488 }
474e1dd0a2fSth160488
475e1dd0a2fSth160488 /*
476e1dd0a2fSth160488 * Check if this process is main nscd.
477e1dd0a2fSth160488 */
478e1dd0a2fSth160488 boolean_t
__s_api_nscd_proc(void)479e1dd0a2fSth160488 __s_api_nscd_proc(void)
480e1dd0a2fSth160488 {
481e1dd0a2fSth160488 pid_t my_pid;
482e1dd0a2fSth160488 static mutex_t nscdLock = DEFAULTMUTEX;
483e1dd0a2fSth160488 static pid_t checkedPid = (pid_t)-1;
484e1dd0a2fSth160488 static boolean_t isMainNscd = B_FALSE;
485e1dd0a2fSth160488
486e1dd0a2fSth160488 /*
487e1dd0a2fSth160488 * Don't bother checking if this process isn't root, this cannot
488e1dd0a2fSth160488 * be main nscd.
489e1dd0a2fSth160488 */
490e1dd0a2fSth160488 if (getuid() != 0)
491e1dd0a2fSth160488 return (B_FALSE);
492e1dd0a2fSth160488
493e1dd0a2fSth160488 my_pid = getpid();
494e1dd0a2fSth160488
495e1dd0a2fSth160488 /*
496e1dd0a2fSth160488 * Already checked before for this process? If yes, return cached
497e1dd0a2fSth160488 * response.
498e1dd0a2fSth160488 */
499e1dd0a2fSth160488 if (my_pid == checkedPid) {
500e1dd0a2fSth160488 return (isMainNscd);
501e1dd0a2fSth160488 }
502e1dd0a2fSth160488
503e1dd0a2fSth160488 (void) mutex_lock(&nscdLock);
504e1dd0a2fSth160488
505e1dd0a2fSth160488 /* Check once more incase another thread has just done this. */
506e1dd0a2fSth160488 if (my_pid == checkedPid) {
507e1dd0a2fSth160488 (void) mutex_unlock(&nscdLock);
508e1dd0a2fSth160488 return (isMainNscd);
509e1dd0a2fSth160488 }
510e1dd0a2fSth160488
511e1dd0a2fSth160488 /*
512e1dd0a2fSth160488 * Am I the nscd process? UID is already checked, not needed from
513e1dd0a2fSth160488 * psinfo.
514e1dd0a2fSth160488 */
515e1dd0a2fSth160488 isMainNscd = check_nscd_proc(my_pid, B_FALSE);
516e1dd0a2fSth160488
517ca190d8dSmichen /* Remember for whom isMainNscd is. */
518e1dd0a2fSth160488 checkedPid = my_pid;
519e1dd0a2fSth160488
520e1dd0a2fSth160488 (void) mutex_unlock(&nscdLock);
521e1dd0a2fSth160488 return (isMainNscd);
522e1dd0a2fSth160488 }
523e1dd0a2fSth160488
524e1dd0a2fSth160488 /*
525e1dd0a2fSth160488 * initialize a connection management control structure conn_mgmt_t
526e1dd0a2fSth160488 */
527e1dd0a2fSth160488 ns_conn_mgmt_t *
init_conn_mgmt()528e1dd0a2fSth160488 init_conn_mgmt()
529e1dd0a2fSth160488 {
530e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
531e1dd0a2fSth160488
532e1dd0a2fSth160488 cmg = (ns_conn_mgmt_t *)calloc(1, sizeof (*cmg));
533e1dd0a2fSth160488 if (cmg == NULL) {
534e1dd0a2fSth160488 syslog(LOG_ERR, NS_CONN_MSG_NO_CONN_MGMT);
535e1dd0a2fSth160488 return (NULL);
536e1dd0a2fSth160488 }
537e1dd0a2fSth160488
538e1dd0a2fSth160488 /* is this process nscd or peruser nscd ? */
539e1dd0a2fSth160488 cmg->is_nscd = __s_api_nscd_proc();
540e1dd0a2fSth160488 cmg->is_peruser_nscd = __s_api_peruser_proc();
541e1dd0a2fSth160488
542e1dd0a2fSth160488 /*
543e1dd0a2fSth160488 * assume the underlying libldap allows multiple threads sharing
544e1dd0a2fSth160488 * the same ldap connection (MT connection)
545e1dd0a2fSth160488 */
546e1dd0a2fSth160488 cmg->ldap_mt = B_TRUE;
547e1dd0a2fSth160488 /* state is inactive until MT connection is required/requested */
548e1dd0a2fSth160488 cmg->state = NS_CONN_MGMT_INACTIVE;
549e1dd0a2fSth160488
550e1dd0a2fSth160488 (void) mutex_init(&cmg->lock, USYNC_THREAD, NULL);
551e1dd0a2fSth160488 (void) mutex_init(&cmg->cfg_lock, USYNC_THREAD, NULL);
552e1dd0a2fSth160488 cmg->pid = getpid();
553e1dd0a2fSth160488
554e1dd0a2fSth160488 /* for nscd or peruser nscd, MT connection is required */
555e1dd0a2fSth160488 if (cmg->is_nscd == B_TRUE || cmg->is_peruser_nscd == B_TRUE)
556e1dd0a2fSth160488 cmg->state = NS_CONN_MGMT_ACTIVE;
557e1dd0a2fSth160488
558e1dd0a2fSth160488 /*
559e1dd0a2fSth160488 * reference (or initialize) the current Native LDAP configuration and
560e1dd0a2fSth160488 * if in nscd process, make it never refreshed
561e1dd0a2fSth160488 */
562e1dd0a2fSth160488 cmg->config = __s_api_get_default_config_global();
563e1dd0a2fSth160488 if (cmg->config == NULL)
564e1dd0a2fSth160488 cmg->config = __s_api_loadrefresh_config_global();
565e1dd0a2fSth160488 if (cmg->config != NULL) {
566e1dd0a2fSth160488 /*
567e1dd0a2fSth160488 * main nscd get config change notice from ldap_cachemgr
568e1dd0a2fSth160488 * so won't times out and refresh the config
569e1dd0a2fSth160488 */
570e1dd0a2fSth160488 if (cmg->is_nscd == B_TRUE)
571e1dd0a2fSth160488 (cmg->config)->paramList[NS_LDAP_EXP_P].ns_tm = 0;
572e1dd0a2fSth160488 cmg->cfg_cookie = cmg->config->config_cookie;
573e1dd0a2fSth160488 }
574e1dd0a2fSth160488
575e1dd0a2fSth160488 return (cmg);
576e1dd0a2fSth160488 }
577e1dd0a2fSth160488
578e1dd0a2fSth160488 static void
mark_shutdown_or_reloaded(int op)579ca190d8dSmichen mark_shutdown_or_reloaded(int op)
580e1dd0a2fSth160488 {
581e1dd0a2fSth160488 ns_conn_mgmt_t *cmg = ns_connmgmt;
582e1dd0a2fSth160488
583e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
584e1dd0a2fSth160488 if (op == NS_CONN_MGMT_OP_SHUTDOWN)
585e1dd0a2fSth160488 cmg->shutting_down = B_TRUE;
586e1dd0a2fSth160488 else
587e1dd0a2fSth160488 cmg->cfg_reloaded = B_TRUE;
588e1dd0a2fSth160488 atomic_inc_uint(&cmg->ref_cnt);
589e1dd0a2fSth160488 cmg->state = NS_CONN_MGMT_DETACHED;
590e1dd0a2fSth160488
591e1dd0a2fSth160488 if (op == NS_CONN_MGMT_OP_RELOAD_CONFIG)
592e1dd0a2fSth160488 __s_api_init_config_global(NULL);
593e1dd0a2fSth160488
594e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
595e1dd0a2fSth160488 }
596e1dd0a2fSth160488
597e1dd0a2fSth160488 /*
598e1dd0a2fSth160488 * Return a pointer to the current connection management. If
599e1dd0a2fSth160488 * it has not been created, or is requested to recreate, then
600e1dd0a2fSth160488 * create and return the pointer. It is possible, the current
601e1dd0a2fSth160488 * one is created by the parent before fork, create a new
602e1dd0a2fSth160488 * one too in such a case.
603e1dd0a2fSth160488 */
604e1dd0a2fSth160488 static ns_conn_mgmt_t *
get_current_conn_mgmt(int op)605e1dd0a2fSth160488 get_current_conn_mgmt(int op)
606e1dd0a2fSth160488 {
607e1dd0a2fSth160488 ns_conn_mgmt_t *cmg = ns_connmgmt;
608e1dd0a2fSth160488 static pid_t checked_pid = (pid_t)-1;
609e1dd0a2fSth160488 pid_t mypid;
610e1dd0a2fSth160488
611e1dd0a2fSth160488 mypid = getpid();
612e1dd0a2fSth160488 if (cmg == NULL || checked_pid != mypid) {
613e1dd0a2fSth160488 checked_pid = mypid;
614e1dd0a2fSth160488
615e1dd0a2fSth160488 /*
616e1dd0a2fSth160488 * if current conn_mgmt not created yet or is from parent
617e1dd0a2fSth160488 * or is requested to recreate, create it
618e1dd0a2fSth160488 */
619e1dd0a2fSth160488 if (cmg == NULL || cmg->pid != mypid) {
620e1dd0a2fSth160488 if (cmg != NULL) {
621e1dd0a2fSth160488 /*
622e1dd0a2fSth160488 * We don't want to free the conn_mgmt
623e1dd0a2fSth160488 * allocated by the parent, since
624e1dd0a2fSth160488 * there may be ldap connections
625e1dd0a2fSth160488 * still being used. So leave it
626e1dd0a2fSth160488 * alone but keep it referenced,
627e1dd0a2fSth160488 * so that it will not be flagged
628e1dd0a2fSth160488 * as a piece of leaked memory.
629e1dd0a2fSth160488 */
630e1dd0a2fSth160488 ns_connmgmt_parent = cmg;
631e1dd0a2fSth160488 /*
632e1dd0a2fSth160488 * avoid lint warning; does not
633e1dd0a2fSth160488 * change the conn_mgmt in parent
634e1dd0a2fSth160488 */
635e1dd0a2fSth160488 ns_connmgmt_parent->state =
636e1dd0a2fSth160488 NS_CONN_MGMT_DETACHED;
637e1dd0a2fSth160488 }
638e1dd0a2fSth160488 ns_connmgmt = init_conn_mgmt();
639e1dd0a2fSth160488 cmg = ns_connmgmt;
640e1dd0a2fSth160488 /*
641e1dd0a2fSth160488 * ensure it will not be destroyed until explicitly
642e1dd0a2fSth160488 * shut down or reloaded
643e1dd0a2fSth160488 */
644e1dd0a2fSth160488 if (op == NS_CONN_MGMT_OP_REF)
645e1dd0a2fSth160488 atomic_inc_uint(&cmg->ref_cnt);
646e1dd0a2fSth160488 }
647e1dd0a2fSth160488 }
648e1dd0a2fSth160488
649e1dd0a2fSth160488 return (cmg);
650e1dd0a2fSth160488 }
651e1dd0a2fSth160488
652e1dd0a2fSth160488 static ns_conn_mgmt_t *
access_conn_mgmt(int op)653e1dd0a2fSth160488 access_conn_mgmt(int op)
654e1dd0a2fSth160488 {
655e1dd0a2fSth160488 ns_conn_mgmt_t *cmg = NULL;
656e1dd0a2fSth160488 ns_conn_mgmt_t *cmg_prev;
657e1dd0a2fSth160488
658e1dd0a2fSth160488 (void) mutex_lock(&ns_connmgmt_lock);
659e1dd0a2fSth160488
660e1dd0a2fSth160488 /*
661e1dd0a2fSth160488 * connection management is not available when the libsldap is being
662e1dd0a2fSth160488 * unloaded or shut down
663e1dd0a2fSth160488 */
664e1dd0a2fSth160488 if (ns_connmgmt_shutting_down == B_TRUE) {
665e1dd0a2fSth160488 (void) mutex_unlock(&ns_connmgmt_lock);
666e1dd0a2fSth160488 return (NULL);
667e1dd0a2fSth160488 }
668e1dd0a2fSth160488
669e1dd0a2fSth160488 if (op == NS_CONN_MGMT_OP_SHUTDOWN) {
670e1dd0a2fSth160488 ns_connmgmt_shutting_down = B_TRUE;
671e1dd0a2fSth160488 if (ns_connmgmt != NULL) {
672e1dd0a2fSth160488 cmg = ns_connmgmt;
673ca190d8dSmichen mark_shutdown_or_reloaded(op);
674e1dd0a2fSth160488 ns_connmgmt = NULL;
675e1dd0a2fSth160488 }
676e1dd0a2fSth160488 (void) mutex_unlock(&ns_connmgmt_lock);
677e1dd0a2fSth160488 return (cmg);
678e1dd0a2fSth160488 }
679e1dd0a2fSth160488
680e1dd0a2fSth160488 if (op == NS_CONN_MGMT_OP_RELOAD_CONFIG ||
681e1dd0a2fSth160488 op == NS_CONN_MGMT_OP_NEW_CONFIG) {
682e1dd0a2fSth160488 cmg_prev = ns_connmgmt;
683ca190d8dSmichen mark_shutdown_or_reloaded(op);
684e1dd0a2fSth160488 /*
685e1dd0a2fSth160488 * the previous cmg (cmg_prev) will be freed later
686e1dd0a2fSth160488 * when its ref count reaches zero
687e1dd0a2fSth160488 */
688e1dd0a2fSth160488 ns_connmgmt = NULL;
689e1dd0a2fSth160488 }
690e1dd0a2fSth160488
691e1dd0a2fSth160488 cmg = get_current_conn_mgmt(op);
692e1dd0a2fSth160488 if (cmg == NULL) {
693e1dd0a2fSth160488 (void) mutex_unlock(&ns_connmgmt_lock);
694e1dd0a2fSth160488 return (NULL);
695e1dd0a2fSth160488 }
696e1dd0a2fSth160488
697e1dd0a2fSth160488 atomic_inc_uint(&cmg->ref_cnt);
698e1dd0a2fSth160488 if (op == NS_CONN_MGMT_OP_RELOAD_CONFIG ||
699e1dd0a2fSth160488 op == NS_CONN_MGMT_OP_NEW_CONFIG)
700e1dd0a2fSth160488 cmg = cmg_prev;
701e1dd0a2fSth160488 else { /* op is NS_CONN_MGMT_OP_REF or NS_CONN_MGMT_OP_LIB_INIT */
702e1dd0a2fSth160488 if (cmg->config == NULL)
703e1dd0a2fSth160488 cmg->config = __s_api_get_default_config();
704e1dd0a2fSth160488 }
705e1dd0a2fSth160488
706e1dd0a2fSth160488 (void) mutex_unlock(&ns_connmgmt_lock);
707e1dd0a2fSth160488 return (cmg);
708e1dd0a2fSth160488 }
709e1dd0a2fSth160488
710e1dd0a2fSth160488 /*
711e1dd0a2fSth160488 * free a connection management control
712e1dd0a2fSth160488 */
713e1dd0a2fSth160488 static void
free_conn_mgmt(ns_conn_mgmt_t * cmg)714e1dd0a2fSth160488 free_conn_mgmt(ns_conn_mgmt_t *cmg)
715e1dd0a2fSth160488 {
716e1dd0a2fSth160488 union {
717e1dd0a2fSth160488 ldap_data_t s_d;
718e1dd0a2fSth160488 char s_b[1024];
719e1dd0a2fSth160488 } space;
720e1dd0a2fSth160488 ldap_data_t *sptr;
721e1dd0a2fSth160488 int ndata;
722e1dd0a2fSth160488 int adata;
723e1dd0a2fSth160488 int rc;
724e1dd0a2fSth160488 ldap_get_chg_cookie_t cookie;
725e1dd0a2fSth160488
726e1dd0a2fSth160488 if (cmg == NULL)
727e1dd0a2fSth160488 return;
728e1dd0a2fSth160488 cookie = cmg->cfg_cookie;
729e1dd0a2fSth160488
730e1dd0a2fSth160488 __s_api_free2dArray(cmg->pservers);
731e1dd0a2fSth160488 /* destroy the previous config or release the current one */
732e1dd0a2fSth160488 if (cmg->config != NULL) {
733e1dd0a2fSth160488 if (cmg->state == NS_CONN_MGMT_DETACHED)
734e1dd0a2fSth160488 __s_api_destroy_config(cmg->config);
735e1dd0a2fSth160488 else
736e1dd0a2fSth160488 __s_api_release_config(cmg->config);
737e1dd0a2fSth160488 }
738e1dd0a2fSth160488
739e1dd0a2fSth160488 /* stop the server status/config-change monitor thread */
740e1dd0a2fSth160488 if (cmg->procchg_started == B_TRUE) {
741e1dd0a2fSth160488 if (cmg->procchg_tid != thr_self()) {
742e1dd0a2fSth160488 if (cmg->procchg_door_call == B_TRUE) {
743e1dd0a2fSth160488 adata = sizeof (ldap_call_t) + 1;
744e1dd0a2fSth160488 ndata = sizeof (space);
745e1dd0a2fSth160488 space.s_d.ldap_call.ldap_callnumber =
746e1dd0a2fSth160488 GETSTATUSCHANGE;
747e1dd0a2fSth160488 space.s_d.ldap_call.ldap_u.get_change.op =
748e1dd0a2fSth160488 NS_STATUS_CHANGE_OP_STOP;
749e1dd0a2fSth160488 space.s_d.ldap_call.ldap_u.get_change.cookie =
750e1dd0a2fSth160488 cookie;
751e1dd0a2fSth160488 sptr = &space.s_d;
752e1dd0a2fSth160488 rc = __ns_ldap_trydoorcall(&sptr, &ndata,
753e1dd0a2fSth160488 &adata);
754e1dd0a2fSth160488 if (rc != NS_CACHE_SUCCESS)
755e1dd0a2fSth160488 syslog(LOG_INFO,
756e1dd0a2fSth160488 gettext("libsldap: "
757e1dd0a2fSth160488 "free_conn_mgmt():"
758e1dd0a2fSth160488 " stopping door call "
759e1dd0a2fSth160488 " GETSTATUSCHANGE failed "
760e1dd0a2fSth160488 " (rc = %d)"), rc);
761e1dd0a2fSth160488 }
762e1dd0a2fSth160488 (void) pthread_cancel(cmg->procchg_tid);
763e1dd0a2fSth160488 cmg->procchg_started = B_FALSE;
764e1dd0a2fSth160488 }
765e1dd0a2fSth160488 }
766e1dd0a2fSth160488
767e1dd0a2fSth160488 free(cmg);
768e1dd0a2fSth160488 }
769e1dd0a2fSth160488
770e1dd0a2fSth160488 static ns_conn_mgmt_t *
release_conn_mgmt(ns_conn_mgmt_t * cmg,boolean_t unlock_cmg)771e1dd0a2fSth160488 release_conn_mgmt(ns_conn_mgmt_t *cmg, boolean_t unlock_cmg)
772e1dd0a2fSth160488 {
773e1dd0a2fSth160488 if (cmg == NULL)
774e1dd0a2fSth160488 return (NULL);
775e1dd0a2fSth160488 if (atomic_dec_uint_nv(&cmg->ref_cnt) == 0) {
776e1dd0a2fSth160488 if (cmg->state == NS_CONN_MGMT_DETACHED) {
777e1dd0a2fSth160488 if (unlock_cmg == B_TRUE)
778e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
779e1dd0a2fSth160488 free_conn_mgmt(cmg);
780*29836b19Smichen __s_api_free_sessionPool();
781e1dd0a2fSth160488 return (NULL);
782e1dd0a2fSth160488 } else {
783e1dd0a2fSth160488 syslog(LOG_WARNING,
784e1dd0a2fSth160488 gettext("libsldap: connection management "
785e1dd0a2fSth160488 " has a refcount of zero but the state "
786e1dd0a2fSth160488 " is not DETACHED (%d)"), cmg->state);
787e1dd0a2fSth160488 cmg = NULL;
788e1dd0a2fSth160488 }
789e1dd0a2fSth160488 }
790e1dd0a2fSth160488 return (cmg);
791e1dd0a2fSth160488 }
792e1dd0a2fSth160488
793e1dd0a2fSth160488 /*
794e1dd0a2fSth160488 * exposed function for initializing a connection management control structure
795e1dd0a2fSth160488 */
796e1dd0a2fSth160488 ns_conn_mgmt_t *
__s_api_conn_mgmt_init()797e1dd0a2fSth160488 __s_api_conn_mgmt_init()
798e1dd0a2fSth160488 {
799e1dd0a2fSth160488 if (thr_keycreate_once(&ns_mtckey, ns_mtckey_cleanup) != 0) {
800e1dd0a2fSth160488 syslog(LOG_WARNING, NS_CONN_MSG_NO_MTC_KEY);
801e1dd0a2fSth160488 return (NULL);
802e1dd0a2fSth160488 }
803e1dd0a2fSth160488
804e1dd0a2fSth160488 if (thr_keycreate_once(&ns_cmgkey, NULL) != 0) {
805e1dd0a2fSth160488 syslog(LOG_WARNING, NS_CONN_MSG_NO_CMG_KEY);
806e1dd0a2fSth160488 return (NULL);
807e1dd0a2fSth160488 }
808e1dd0a2fSth160488
809e1dd0a2fSth160488 return (access_conn_mgmt(NS_CONN_MGMT_OP_LIB_INIT));
810e1dd0a2fSth160488 }
811e1dd0a2fSth160488
812e1dd0a2fSth160488 /* initialize a connection user */
813e1dd0a2fSth160488 ns_conn_user_t *
__s_api_conn_user_init(int type,void * userinfo,boolean_t referral)814e1dd0a2fSth160488 __s_api_conn_user_init(int type, void *userinfo, boolean_t referral)
815e1dd0a2fSth160488 {
816e1dd0a2fSth160488 ns_conn_user_t *cu;
817e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
818e1dd0a2fSth160488
819e1dd0a2fSth160488 /* delete the reference to the previously used conn_mgmt */
820e1dd0a2fSth160488 (void) thr_setspecific(ns_cmgkey, NULL);
821e1dd0a2fSth160488
822e1dd0a2fSth160488 cmg = access_conn_mgmt(NS_CONN_MGMT_OP_REF);
823e1dd0a2fSth160488 if (cmg == NULL)
824e1dd0a2fSth160488 return (NULL);
825e1dd0a2fSth160488
826e1dd0a2fSth160488 if (cmg->state != NS_CONN_MGMT_ACTIVE &&
827e1dd0a2fSth160488 cmg->state != NS_CONN_MGMT_INACTIVE) {
828e1dd0a2fSth160488 atomic_dec_uint(&cmg->ref_cnt);
829e1dd0a2fSth160488 return (NULL);
830e1dd0a2fSth160488 }
831e1dd0a2fSth160488
832e1dd0a2fSth160488 cu = (ns_conn_user_t *)calloc(1, sizeof (*cu));
833e1dd0a2fSth160488 if (cu == NULL) {
834e1dd0a2fSth160488 atomic_dec_uint(&cmg->ref_cnt);
835e1dd0a2fSth160488 return (NULL);
836e1dd0a2fSth160488 }
837e1dd0a2fSth160488
838e1dd0a2fSth160488 cu->type = type;
839e1dd0a2fSth160488 cu->state = NS_CONN_USER_ALLOCATED;
840e1dd0a2fSth160488 cu->tid = thr_self();
841e1dd0a2fSth160488 cu->userinfo = userinfo;
842e1dd0a2fSth160488 cu->referral = referral;
843e1dd0a2fSth160488 cu->ns_rc = NS_LDAP_SUCCESS;
844e1dd0a2fSth160488 cu->conn_mgmt = cmg;
845e1dd0a2fSth160488
846e1dd0a2fSth160488 (void) conn_tsd_setup(cmg);
847e1dd0a2fSth160488
848e1dd0a2fSth160488 return (cu);
849e1dd0a2fSth160488 }
850e1dd0a2fSth160488
851e1dd0a2fSth160488 /*
852e1dd0a2fSth160488 * Free the resources used by a connection user.
853e1dd0a2fSth160488 * The caller should ensure this conn_user is
854e1dd0a2fSth160488 * not associated with any conn_mt, i.e.,
855e1dd0a2fSth160488 * not in any conn_mt's linked list of conn_users.
856e1dd0a2fSth160488 * The caller needs to free the userinfo member
857e1dd0a2fSth160488 * as well.
858e1dd0a2fSth160488 */
859e1dd0a2fSth160488 void
__s_api_conn_user_free(ns_conn_user_t * cu)860e1dd0a2fSth160488 __s_api_conn_user_free(ns_conn_user_t *cu)
861e1dd0a2fSth160488 {
862e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
863e1dd0a2fSth160488
864e1dd0a2fSth160488 if (cu == NULL)
865e1dd0a2fSth160488 return;
866e1dd0a2fSth160488
867e1dd0a2fSth160488 cu->state = NS_CONN_USER_FREED;
868e1dd0a2fSth160488 if (cu->ns_error != NULL)
869e1dd0a2fSth160488 (void) __ns_ldap_freeError(&cu->ns_error);
870e1dd0a2fSth160488
871e1dd0a2fSth160488 cmg = cu->conn_mgmt;
872e1dd0a2fSth160488 conn_tsd_free();
873e1dd0a2fSth160488 (void) release_conn_mgmt(cmg, B_FALSE);
874e1dd0a2fSth160488 (void) free(cu);
875e1dd0a2fSth160488 }
876e1dd0a2fSth160488
877e1dd0a2fSth160488 /*
878e1dd0a2fSth160488 * Initialize an MT connection control structure
879e1dd0a2fSth160488 * that will be used to represent an ldap connection
880e1dd0a2fSth160488 * to be shared among multiple threads and to hold
881e1dd0a2fSth160488 * and manage all the conn_users using the ldap
882e1dd0a2fSth160488 * connection.
883e1dd0a2fSth160488 */
884e1dd0a2fSth160488 static ns_conn_mt_t *
init_conn_mt(ns_conn_mgmt_t * cmg,ns_ldap_error_t ** ep)885e1dd0a2fSth160488 init_conn_mt(ns_conn_mgmt_t *cmg, ns_ldap_error_t **ep)
886e1dd0a2fSth160488 {
887e1dd0a2fSth160488 ns_conn_mt_t *cm;
888e1dd0a2fSth160488 ns_conn_mgmt_t *cmg_a;
889e1dd0a2fSth160488
890e1dd0a2fSth160488 cm = (ns_conn_mt_t *)calloc(1, sizeof (*cm));
891e1dd0a2fSth160488 if (cm == NULL) {
892e1dd0a2fSth160488 if (ep != NULL)
893e1dd0a2fSth160488 *ep = __s_api_make_error(NS_LDAP_MEMORY, NULL);
894e1dd0a2fSth160488 return (NULL);
895e1dd0a2fSth160488 }
896e1dd0a2fSth160488
897e1dd0a2fSth160488 cmg_a = access_conn_mgmt(NS_CONN_MGMT_OP_REF);
898e1dd0a2fSth160488 if (cmg_a != cmg) {
899e1dd0a2fSth160488 if (cmg_a != NULL) {
900e1dd0a2fSth160488 (void) release_conn_mgmt(cmg_a, B_FALSE);
901e1dd0a2fSth160488 if (ep != NULL)
902e1dd0a2fSth160488 *ep = __s_api_make_error(NS_LDAP_OP_FAILED,
903e1dd0a2fSth160488 NS_CONN_MSG_SHUTDOWN_RELOADED);
904e1dd0a2fSth160488 }
905e1dd0a2fSth160488 return (NULL);
906e1dd0a2fSth160488 }
907e1dd0a2fSth160488
908e1dd0a2fSth160488 (void) mutex_init(&cm->lock, USYNC_THREAD, NULL);
909e1dd0a2fSth160488 cm->state = NS_CONN_MT_CONNECTING;
910e1dd0a2fSth160488 cm->tid = thr_self();
911e1dd0a2fSth160488 cm->pid = getpid();
912e1dd0a2fSth160488 cm->next = NULL;
913e1dd0a2fSth160488 cm->cu_head = NULL;
914e1dd0a2fSth160488 cm->cu_tail = NULL;
915e1dd0a2fSth160488 cm->conn = NULL;
916e1dd0a2fSth160488 cm->conn_mgmt = cmg;
917e1dd0a2fSth160488
918e1dd0a2fSth160488 return (cm);
919e1dd0a2fSth160488 }
920e1dd0a2fSth160488
921e1dd0a2fSth160488 /*
922e1dd0a2fSth160488 * Free an MT connection control structure, assume conn_mgmt is locked.
923e1dd0a2fSth160488 * 'unlock_cmg' is passed to release_conn_mgmt() to indicate the
924e1dd0a2fSth160488 * cmg needs to be unlocked or not.
925e1dd0a2fSth160488 */
926e1dd0a2fSth160488 static ns_conn_mgmt_t *
free_conn_mt(ns_conn_mt_t * cm,int unlock_cmg)927e1dd0a2fSth160488 free_conn_mt(ns_conn_mt_t *cm, int unlock_cmg)
928e1dd0a2fSth160488 {
929e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
930e1dd0a2fSth160488
931e1dd0a2fSth160488 if (cm == NULL)
932e1dd0a2fSth160488 return (NULL);
933e1dd0a2fSth160488 if (cm->ns_error != NULL)
934e1dd0a2fSth160488 (void) __ns_ldap_freeError(&cm->ns_error);
935e1dd0a2fSth160488 if (cm->conn != NULL) {
936e1dd0a2fSth160488 if (cm->conn->ld != NULL)
937e1dd0a2fSth160488 (void) ldap_unbind(cm->conn->ld);
938e1dd0a2fSth160488 __s_api_freeConnection(cm->conn);
939e1dd0a2fSth160488 }
940e1dd0a2fSth160488 cmg = cm->conn_mgmt;
941e1dd0a2fSth160488 free(cm);
942e1dd0a2fSth160488 return (release_conn_mgmt(cmg, unlock_cmg));
943e1dd0a2fSth160488 }
944e1dd0a2fSth160488
945e1dd0a2fSth160488 /* add a connection user to an MT connection */
946e1dd0a2fSth160488 static void
add_cu2cm(ns_conn_user_t * cu,ns_conn_mt_t * cm)947e1dd0a2fSth160488 add_cu2cm(ns_conn_user_t *cu, ns_conn_mt_t *cm)
948e1dd0a2fSth160488 {
949e1dd0a2fSth160488
950e1dd0a2fSth160488 if (cm->cu_head == NULL) {
951e1dd0a2fSth160488 cm->cu_head = cu;
952e1dd0a2fSth160488 cm->cu_tail = cu;
953e1dd0a2fSth160488 } else {
954e1dd0a2fSth160488 cm->cu_tail->next = cu;
955e1dd0a2fSth160488 cm->cu_tail = cu;
956e1dd0a2fSth160488 }
957e1dd0a2fSth160488 cm->cu_cnt++;
958e1dd0a2fSth160488 }
959e1dd0a2fSth160488
960e1dd0a2fSth160488 /* add an MT connection to the connection management */
961e1dd0a2fSth160488 static void
add_cm2cmg(ns_conn_mt_t * cm,ns_conn_mgmt_t * cmg)962e1dd0a2fSth160488 add_cm2cmg(ns_conn_mt_t *cm, ns_conn_mgmt_t *cmg)
963e1dd0a2fSth160488 {
964e1dd0a2fSth160488 /*
965e1dd0a2fSth160488 * add connection opened for WRITE to top of list
966e1dd0a2fSth160488 * for garbage collection purpose. This is to
967e1dd0a2fSth160488 * ensure the connection will be closed after a
968e1dd0a2fSth160488 * certain amount of time (60 seconds).
969e1dd0a2fSth160488 */
970e1dd0a2fSth160488 if (cmg->cm_head == NULL) {
971e1dd0a2fSth160488 cmg->cm_head = cm;
972e1dd0a2fSth160488 cmg->cm_tail = cm;
973e1dd0a2fSth160488 } else {
974e1dd0a2fSth160488 if (cm->opened_for == NS_CONN_USER_WRITE) {
975e1dd0a2fSth160488 cm->next = cmg->cm_head;
976e1dd0a2fSth160488 cmg->cm_head = cm;
977e1dd0a2fSth160488 } else {
978e1dd0a2fSth160488 cmg->cm_tail->next = cm;
979e1dd0a2fSth160488 cmg->cm_tail = cm;
980e1dd0a2fSth160488 }
981e1dd0a2fSth160488 }
982e1dd0a2fSth160488 cmg->cm_cnt++;
983e1dd0a2fSth160488 }
984e1dd0a2fSth160488
985e1dd0a2fSth160488 /* delete a connection user from an MT connection */
986e1dd0a2fSth160488 static void
del_cu4cm(ns_conn_user_t * cu,ns_conn_mt_t * cm)987e1dd0a2fSth160488 del_cu4cm(ns_conn_user_t *cu, ns_conn_mt_t *cm)
988e1dd0a2fSth160488 {
989e1dd0a2fSth160488 ns_conn_user_t *pu, *u;
990e1dd0a2fSth160488
991e1dd0a2fSth160488 if (cu == NULL || cm->cu_head == NULL || cm->cu_cnt == 0)
992e1dd0a2fSth160488 return;
993e1dd0a2fSth160488
994e1dd0a2fSth160488 /* only one conn_user on list */
995e1dd0a2fSth160488 if (cm->cu_head == cm->cu_tail) {
996e1dd0a2fSth160488 if (cu == cm->cu_head) {
997e1dd0a2fSth160488 cm->cu_head = cm->cu_tail = NULL;
998e1dd0a2fSth160488 cm->cu_cnt = 0;
999e1dd0a2fSth160488 cu->next = NULL;
1000e1dd0a2fSth160488 }
1001e1dd0a2fSth160488 return;
1002e1dd0a2fSth160488 }
1003e1dd0a2fSth160488
1004e1dd0a2fSth160488 /* more than one and cu is the first one */
1005e1dd0a2fSth160488 if (cu == cm->cu_head) {
1006e1dd0a2fSth160488 cm->cu_head = cu->next;
1007e1dd0a2fSth160488 cm->cu_cnt--;
1008e1dd0a2fSth160488 cu->next = NULL;
1009e1dd0a2fSth160488 return;
1010e1dd0a2fSth160488 }
1011e1dd0a2fSth160488
1012e1dd0a2fSth160488 pu = cm->cu_head;
1013e1dd0a2fSth160488 for (u = cm->cu_head->next; u; u = u->next) {
1014e1dd0a2fSth160488 if (cu == u)
1015e1dd0a2fSth160488 break;
1016e1dd0a2fSth160488 pu = u;
1017e1dd0a2fSth160488 }
1018e1dd0a2fSth160488 if (pu != cm->cu_tail) {
1019e1dd0a2fSth160488 pu->next = cu->next;
1020e1dd0a2fSth160488 if (pu->next == NULL)
1021e1dd0a2fSth160488 cm->cu_tail = pu;
1022e1dd0a2fSth160488 cm->cu_cnt--;
1023e1dd0a2fSth160488 cu->next = NULL;
1024e1dd0a2fSth160488 } else {
1025e1dd0a2fSth160488 syslog(LOG_INFO, gettext(
1026e1dd0a2fSth160488 "libsldap: del_cu4cm(): connection user not found"));
1027e1dd0a2fSth160488 }
1028e1dd0a2fSth160488 }
1029e1dd0a2fSth160488
1030e1dd0a2fSth160488 /* delete an MT connection from the connection management control structure */
1031e1dd0a2fSth160488 static void
del_cm4cmg(ns_conn_mt_t * cm,ns_conn_mgmt_t * cmg)1032e1dd0a2fSth160488 del_cm4cmg(ns_conn_mt_t *cm, ns_conn_mgmt_t *cmg)
1033e1dd0a2fSth160488 {
1034e1dd0a2fSth160488 ns_conn_mt_t *pm, *m;
1035e1dd0a2fSth160488
1036e1dd0a2fSth160488 if (cm == NULL || cmg->cm_head == NULL || cmg->cm_cnt == 0)
1037e1dd0a2fSth160488 return;
1038e1dd0a2fSth160488
1039e1dd0a2fSth160488 /* only one conn_mt on list */
1040e1dd0a2fSth160488 if (cmg->cm_head == cmg->cm_tail) {
1041e1dd0a2fSth160488 if (cm == cmg->cm_head) {
1042e1dd0a2fSth160488 cmg->cm_head = cmg->cm_tail = NULL;
1043e1dd0a2fSth160488 cmg->cm_cnt = 0;
1044e1dd0a2fSth160488 cm->next = NULL;
1045e1dd0a2fSth160488 }
1046e1dd0a2fSth160488 return;
1047e1dd0a2fSth160488 }
1048e1dd0a2fSth160488
1049e1dd0a2fSth160488 /* more than one and cm is the first one */
1050e1dd0a2fSth160488 if (cm == cmg->cm_head) {
1051e1dd0a2fSth160488 cmg->cm_head = cm->next;
1052e1dd0a2fSth160488 cmg->cm_cnt--;
1053e1dd0a2fSth160488 cm->next = NULL;
1054e1dd0a2fSth160488 return;
1055e1dd0a2fSth160488 }
1056e1dd0a2fSth160488
1057e1dd0a2fSth160488 pm = cmg->cm_head;
1058e1dd0a2fSth160488 for (m = cmg->cm_head->next; m; m = m->next) {
1059e1dd0a2fSth160488 if (cm == m)
1060e1dd0a2fSth160488 break;
1061e1dd0a2fSth160488 pm = m;
1062e1dd0a2fSth160488 }
1063e1dd0a2fSth160488 if (pm != cmg->cm_tail) {
1064e1dd0a2fSth160488 pm->next = cm->next;
1065e1dd0a2fSth160488 if (pm->next == NULL)
1066e1dd0a2fSth160488 cmg->cm_tail = pm;
1067e1dd0a2fSth160488 cmg->cm_cnt--;
1068e1dd0a2fSth160488 cm->next = NULL;
1069e1dd0a2fSth160488 } else {
1070e1dd0a2fSth160488 syslog(LOG_INFO, gettext(
1071e1dd0a2fSth160488 "libsldap: del_cm4cmg(): MT connection not found"));
1072e1dd0a2fSth160488 }
1073e1dd0a2fSth160488 }
1074e1dd0a2fSth160488
1075e1dd0a2fSth160488 /*
1076e1dd0a2fSth160488 * compare to see if the server and credential for authentication match
1077e1dd0a2fSth160488 * those used by an MT connection
1078e1dd0a2fSth160488 */
1079e1dd0a2fSth160488 static boolean_t
is_server_cred_matched(const char * server,const ns_cred_t * cred,ns_conn_mt_t * cm)1080e1dd0a2fSth160488 is_server_cred_matched(const char *server, const ns_cred_t *cred,
1081e1dd0a2fSth160488 ns_conn_mt_t *cm)
1082e1dd0a2fSth160488 {
1083e1dd0a2fSth160488 Connection *cp = cm->conn;
1084e1dd0a2fSth160488
1085e1dd0a2fSth160488 /* check server first */
1086e1dd0a2fSth160488 if (server != NULL && *server != 0) {
1087e1dd0a2fSth160488 if (strcasecmp(server, cp->serverAddr) != 0)
1088e1dd0a2fSth160488 return (B_FALSE);
1089e1dd0a2fSth160488 }
1090e1dd0a2fSth160488
1091e1dd0a2fSth160488 if (cred == NULL)
1092e1dd0a2fSth160488 return (B_TRUE);
1093e1dd0a2fSth160488
1094e1dd0a2fSth160488 /* then check cred */
1095e1dd0a2fSth160488 return (__s_api_is_auth_matched(cp->auth, cred));
1096e1dd0a2fSth160488 }
1097e1dd0a2fSth160488
1098e1dd0a2fSth160488 /*
1099e1dd0a2fSth160488 * Wait until a pending MT connection becomes available.
1100e1dd0a2fSth160488 * Return 1 if so, 0 if error.
1101e1dd0a2fSth160488 *
1102e1dd0a2fSth160488 * Assume the current conn_mgmt and the input conn_mt
1103e1dd0a2fSth160488 * are locked.
1104e1dd0a2fSth160488 */
1105e1dd0a2fSth160488 static int
wait_for_conn_mt(ns_conn_user_t * cu,ns_conn_mt_t * cm)1106e1dd0a2fSth160488 wait_for_conn_mt(ns_conn_user_t *cu, ns_conn_mt_t *cm)
1107e1dd0a2fSth160488 {
1108e1dd0a2fSth160488
1109e1dd0a2fSth160488 cu->state = NS_CONN_USER_WAITING;
1110e1dd0a2fSth160488 add_cu2cm(cu, cm);
1111e1dd0a2fSth160488 cu->conn_mt = cm;
1112e1dd0a2fSth160488
1113e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1114e1dd0a2fSth160488 /*
1115e1dd0a2fSth160488 * It could take some time so we don't want to hold
1116e1dd0a2fSth160488 * cm->conn_mgmt across the wait
1117e1dd0a2fSth160488 */
1118e1dd0a2fSth160488 (void) mutex_unlock(&(cm->conn_mgmt)->lock);
1119e1dd0a2fSth160488
1120e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
1121e1dd0a2fSth160488 /* check one more time see if need to wait */
1122e1dd0a2fSth160488 if (cm->state == NS_CONN_MT_CONNECTING) {
1123e1dd0a2fSth160488 (void) conn_wait(cm, cu);
1124e1dd0a2fSth160488
1125e1dd0a2fSth160488 /* cm->lock is locked again at this point */
1126e1dd0a2fSth160488
1127e1dd0a2fSth160488 cu->state = NS_CONN_USER_WOKEUP;
1128e1dd0a2fSth160488 }
1129e1dd0a2fSth160488
1130e1dd0a2fSth160488 if (cm->state == NS_CONN_MT_CONNECTED)
1131e1dd0a2fSth160488 return (1);
1132e1dd0a2fSth160488 else {
1133e1dd0a2fSth160488 del_cu4cm(cu, cm);
1134e1dd0a2fSth160488 cu->conn_mt = NULL;
1135e1dd0a2fSth160488 cu->bad_mt_conn = B_FALSE;
1136e1dd0a2fSth160488 return (0);
1137e1dd0a2fSth160488 }
1138e1dd0a2fSth160488 }
1139e1dd0a2fSth160488
1140e1dd0a2fSth160488 /*
1141e1dd0a2fSth160488 * Check and see if the input MT connection '*cm' should be closed.
1142e1dd0a2fSth160488 * In two cases, it should be closed. If a preferred server is
1143e1dd0a2fSth160488 * found to be up when ldap_cachemgr is queried and reported back.
1144e1dd0a2fSth160488 * Or when the server being used for the connection is found to
1145e1dd0a2fSth160488 * be down. Return B_FALSE if the connection is not closed (or not marked
1146e1dd0a2fSth160488 * to be closed), otherwise unlock mutex (*cm)->lock and return B_TRUE.
1147e1dd0a2fSth160488 * This function assumes conn_mgmt cmg and conn_mt *cm are locked.
1148e1dd0a2fSth160488 */
1149e1dd0a2fSth160488 static boolean_t
check_and_close_conn(ns_conn_mgmt_t * cmg,ns_conn_mt_t ** cm,ns_conn_user_t * cu)1150e1dd0a2fSth160488 check_and_close_conn(ns_conn_mgmt_t *cmg, ns_conn_mt_t **cm,
1151e1dd0a2fSth160488 ns_conn_user_t *cu) {
1152e1dd0a2fSth160488
1153e1dd0a2fSth160488 int rc;
1154e1dd0a2fSth160488 int j;
1155e1dd0a2fSth160488 int svridx = -1;
1156e1dd0a2fSth160488 int upidx = -1;
1157e1dd0a2fSth160488 int free_cm;
1158e1dd0a2fSth160488 ns_server_info_t sinfo;
1159e1dd0a2fSth160488 ns_ldap_error_t *errorp = NULL;
1160e1dd0a2fSth160488
1161e1dd0a2fSth160488 /*
1162e1dd0a2fSth160488 * check only if preferred servers are defined
1163e1dd0a2fSth160488 */
1164e1dd0a2fSth160488 if (cmg->pservers_loaded == B_FALSE)
1165e1dd0a2fSth160488 get_preferred_servers(B_FALSE, B_FALSE, cmg);
1166e1dd0a2fSth160488 if (cmg->pservers == NULL)
1167e1dd0a2fSth160488 return (B_FALSE);
1168e1dd0a2fSth160488
1169e1dd0a2fSth160488 /*
1170e1dd0a2fSth160488 * ask ldap_cachemgr for the first available server
1171e1dd0a2fSth160488 */
1172e1dd0a2fSth160488 rc = __s_api_requestServer(NS_CACHE_NEW, NULL,
1173e1dd0a2fSth160488 &sinfo, &errorp, NS_CACHE_ADDR_IP);
1174e1dd0a2fSth160488 if (rc != NS_LDAP_SUCCESS || sinfo.server == NULL) {
1175e1dd0a2fSth160488 (void) __ns_ldap_freeError(&errorp);
1176e1dd0a2fSth160488 return (B_FALSE);
1177e1dd0a2fSth160488 }
1178e1dd0a2fSth160488
1179e1dd0a2fSth160488 /*
1180e1dd0a2fSth160488 * Did ldap_cachemgr return a preferred server ?
1181e1dd0a2fSth160488 */
1182e1dd0a2fSth160488 for (j = 0; cmg->pservers[j] != NULL; j++) {
1183e1dd0a2fSth160488 if (strcasecmp(sinfo.server, cmg->pservers[j]) != 0)
1184e1dd0a2fSth160488 continue;
1185e1dd0a2fSth160488 upidx = j;
1186e1dd0a2fSth160488 break;
1187e1dd0a2fSth160488 }
1188e1dd0a2fSth160488
1189e1dd0a2fSth160488 /*
1190e1dd0a2fSth160488 * Is the server being used a preferred one ?
1191e1dd0a2fSth160488 */
1192e1dd0a2fSth160488 for (j = 0; cmg->pservers[j] != NULL; j++) {
1193e1dd0a2fSth160488 if (strcasecmp(cmg->pservers[j], (*cm)->conn->serverAddr) != 0)
1194e1dd0a2fSth160488 continue;
1195e1dd0a2fSth160488 svridx = j;
1196e1dd0a2fSth160488 break;
1197e1dd0a2fSth160488 }
1198e1dd0a2fSth160488
1199e1dd0a2fSth160488 /*
1200e1dd0a2fSth160488 * Need to fall back to a down-but-now-up preferred server ?
1201e1dd0a2fSth160488 * A preferred server falls back to a more preferred one.
1202e1dd0a2fSth160488 * A regular one falls back to any preferred ones. So if
1203e1dd0a2fSth160488 * both are preferred ones and same index, or both
1204e1dd0a2fSth160488 * are not preferred ones, then no need to close the
1205e1dd0a2fSth160488 * connection.
1206e1dd0a2fSth160488 */
1207e1dd0a2fSth160488 if ((upidx == -1 && svridx == -1) ||
1208e1dd0a2fSth160488 (upidx != -1 && svridx != -1 && upidx == svridx)) {
1209e1dd0a2fSth160488 __s_api_free_server_info(&sinfo);
1210e1dd0a2fSth160488 return (B_FALSE);
1211e1dd0a2fSth160488 }
1212e1dd0a2fSth160488
1213e1dd0a2fSth160488 /*
1214e1dd0a2fSth160488 * otherwise, 4 cases, all may need to close the connection:
1215e1dd0a2fSth160488 * For case 1 and 2, both servers are preferred ones:
1216e1dd0a2fSth160488 * 1. ldap_cachemgr returned a better one to use (upidx < svridx)
1217e1dd0a2fSth160488 * 2. the server being used is down (upidx > svridx)
1218e1dd0a2fSth160488 * 3. ldap_cachemgr returned a preferred one, but the server
1219e1dd0a2fSth160488 * being used is not, so need to fall back to the preferred server
1220e1dd0a2fSth160488 * 4. ldap_cachemgr returned a non-preferred one, but the server
1221e1dd0a2fSth160488 * being used is a preferred one, so it must be down (since
1222e1dd0a2fSth160488 * ldap_cachemgr always returns a preferred one when possible).
1223e1dd0a2fSth160488 * For case 1 & 3, close the READ connection when no user uses it.
1224e1dd0a2fSth160488 * For 2 and 4, close the connection with error rc, LDAP_SERVER_DOWN.
1225e1dd0a2fSth160488 */
1226e1dd0a2fSth160488 if (upidx != -1 && (svridx == -1 || upidx < svridx)) { /* case 1 & 3 */
1227e1dd0a2fSth160488 /* fallback does not make sense for WRITE/referred connection */
1228e1dd0a2fSth160488 if ((*cm)->opened_for == NS_CONN_USER_WRITE ||
1229e1dd0a2fSth160488 (*cm)->referral == B_TRUE) {
1230e1dd0a2fSth160488 __s_api_free_server_info(&sinfo);
1231e1dd0a2fSth160488 return (B_FALSE);
1232e1dd0a2fSth160488 }
1233e1dd0a2fSth160488 free_cm = close_conn_mt_when_nouser(*cm);
1234e1dd0a2fSth160488 if (cmg->shutting_down == B_FALSE)
1235e1dd0a2fSth160488 cu->retry = B_TRUE;
1236e1dd0a2fSth160488 } else {
1237e1dd0a2fSth160488 ns_ldap_error_t *ep;
1238e1dd0a2fSth160488 ep = __s_api_make_error(LDAP_SERVER_DOWN,
1239e1dd0a2fSth160488 NS_CONN_MSG_DOWN_FROM_CACHEMGR);
1240e1dd0a2fSth160488 /* cu has not been attached to cm yet, use NULL as cu pointer */
1241e1dd0a2fSth160488 free_cm = close_conn_mt(*cm, LDAP_SERVER_DOWN, &ep, NULL);
1242e1dd0a2fSth160488 if (cmg->shutting_down == B_FALSE)
1243e1dd0a2fSth160488 cu->retry = B_TRUE;
1244e1dd0a2fSth160488 (void) __ns_ldap_freeError(&ep);
1245e1dd0a2fSth160488 }
1246e1dd0a2fSth160488
1247e1dd0a2fSth160488 (void) mutex_unlock(&(*cm)->lock);
1248e1dd0a2fSth160488 if (free_cm == 1) {
1249e1dd0a2fSth160488 (void) free_conn_mt(*cm, 0);
1250e1dd0a2fSth160488 *cm = NULL;
1251e1dd0a2fSth160488 }
1252e1dd0a2fSth160488
1253e1dd0a2fSth160488 __s_api_free_server_info(&sinfo);
1254e1dd0a2fSth160488
1255e1dd0a2fSth160488 return (B_TRUE);
1256e1dd0a2fSth160488 }
1257e1dd0a2fSth160488
1258e1dd0a2fSth160488 /*
1259e1dd0a2fSth160488 * Check to see if a conn_mt matches the connection criteria from
1260e1dd0a2fSth160488 * a conn_user. Return B_TRUE if yes, B_FALSE, otherwise. The input
1261e1dd0a2fSth160488 * conn_mt pointer (*cmt) may be freed and *cmt will be set to NULL
1262e1dd0a2fSth160488 * to indicate so.
1263e1dd0a2fSth160488 * conn_mt *cmt and conn_mgmt cm->conn_mgmt are assumed locked.
1264e1dd0a2fSth160488 * cm->lock is unlocked at exit if rc is B_FALSE.
1265e1dd0a2fSth160488 */
1266e1dd0a2fSth160488 static boolean_t
match_conn_mt(ns_conn_user_t * cu,ns_conn_mt_t ** cmt,ns_conn_mt_state_t st,const char * server,const ns_cred_t * cred)1267e1dd0a2fSth160488 match_conn_mt(ns_conn_user_t *cu, ns_conn_mt_t **cmt,
1268e1dd0a2fSth160488 ns_conn_mt_state_t st, const char *server,
1269e1dd0a2fSth160488 const ns_cred_t *cred)
1270e1dd0a2fSth160488 {
1271e1dd0a2fSth160488 boolean_t matched = B_FALSE;
1272e1dd0a2fSth160488 boolean_t drop_conn;
1273e1dd0a2fSth160488 int free_cm = 0;
1274e1dd0a2fSth160488 ns_conn_mt_t *cm = *cmt;
1275e1dd0a2fSth160488 ns_conn_mgmt_t *cmg = cm->conn_mgmt;
1276e1dd0a2fSth160488
1277e1dd0a2fSth160488 if (cm->state != st || cm->close_when_nouser == B_TRUE ||
1278e1dd0a2fSth160488 cm->detached == B_TRUE || cm->pid != getpid() ||
1279e1dd0a2fSth160488 cm->referral != cu->referral) {
1280e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1281e1dd0a2fSth160488 return (B_FALSE);
1282e1dd0a2fSth160488 }
1283e1dd0a2fSth160488
1284e1dd0a2fSth160488 /*
1285e1dd0a2fSth160488 * if a conn_mt opened for WRITE is idle
1286e1dd0a2fSth160488 * long enough, then close it. To improve
1287e1dd0a2fSth160488 * the performance of applications, such
1288e1dd0a2fSth160488 * as ldapaddent, a WRITE connection is
1289e1dd0a2fSth160488 * given a short time to live in the
1290e1dd0a2fSth160488 * connection pool, expecting the write
1291e1dd0a2fSth160488 * requests to come in a quick succession.
1292e1dd0a2fSth160488 * To save resource, the connection will
1293e1dd0a2fSth160488 * be closed if idle more than 60 seconds.
1294e1dd0a2fSth160488 */
1295e1dd0a2fSth160488 if (cm->opened_for == NS_CONN_USER_WRITE &&
1296e1dd0a2fSth160488 cu->type != NS_CONN_USER_WRITE && cm->cu_cnt == 0 &&
1297e1dd0a2fSth160488 ((time(NULL) - cm->access_time) > 60)) {
1298e1dd0a2fSth160488 /*
1299e1dd0a2fSth160488 * NS_LDAP_INTERNAL is irrelevant here. There no
1300e1dd0a2fSth160488 * conn_user to consume the rc
1301e1dd0a2fSth160488 */
1302e1dd0a2fSth160488 free_cm = close_conn_mt(cm, NS_LDAP_INTERNAL, NULL, NULL);
1303e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1304e1dd0a2fSth160488 if (free_cm == 1) {
1305e1dd0a2fSth160488 (void) free_conn_mt(cm, 0);
1306e1dd0a2fSth160488 *cmt = NULL;
1307e1dd0a2fSth160488 }
1308e1dd0a2fSth160488 return (B_FALSE);
1309e1dd0a2fSth160488 }
1310e1dd0a2fSth160488
1311e1dd0a2fSth160488 switch (cu->type) {
1312e1dd0a2fSth160488 case NS_CONN_USER_SEARCH:
1313e1dd0a2fSth160488 case NS_CONN_USER_GETENT:
1314e1dd0a2fSth160488 if (cm->opened_for == NS_CONN_USER_SEARCH ||
1315e1dd0a2fSth160488 cm->opened_for == NS_CONN_USER_GETENT)
1316e1dd0a2fSth160488 matched = B_TRUE;
1317e1dd0a2fSth160488 break;
1318e1dd0a2fSth160488
1319e1dd0a2fSth160488 case NS_CONN_USER_WRITE:
1320e1dd0a2fSth160488 if (cm->opened_for == NS_CONN_USER_WRITE)
1321e1dd0a2fSth160488 matched = B_TRUE;
1322e1dd0a2fSth160488 break;
1323e1dd0a2fSth160488
1324e1dd0a2fSth160488 default:
1325e1dd0a2fSth160488 matched = B_FALSE;
1326e1dd0a2fSth160488 break;
1327e1dd0a2fSth160488 }
1328e1dd0a2fSth160488
1329e1dd0a2fSth160488 if (matched == B_TRUE && ((server != NULL || cred != NULL) &&
1330e1dd0a2fSth160488 is_server_cred_matched(server, cred, cm) == B_FALSE))
1331e1dd0a2fSth160488 matched = B_FALSE;
1332e1dd0a2fSth160488
1333e1dd0a2fSth160488 if (matched != B_FALSE) {
1334e1dd0a2fSth160488 /*
1335e1dd0a2fSth160488 * Check and drop the 'connected' connection if
1336e1dd0a2fSth160488 * necessary. Main nscd gets status changes from
1337e1dd0a2fSth160488 * the ldap_cachemgr daemon directly via the
1338e1dd0a2fSth160488 * GETSTATUSCHANGE door call, the standalone
1339e1dd0a2fSth160488 * function works in a no ldap_cachemgr environment,
1340e1dd0a2fSth160488 * so no need to check and drop connections.
1341e1dd0a2fSth160488 */
1342e1dd0a2fSth160488 if (cm->state == NS_CONN_MT_CONNECTED &&
1343e1dd0a2fSth160488 cmg->is_nscd == B_FALSE && !__s_api_isStandalone()) {
1344e1dd0a2fSth160488 drop_conn = check_and_close_conn(cmg, &cm, cu);
1345e1dd0a2fSth160488 if (drop_conn == B_TRUE) {
1346e1dd0a2fSth160488 if (cm == NULL)
1347e1dd0a2fSth160488 *cmt = NULL;
1348e1dd0a2fSth160488 return (B_FALSE);
1349e1dd0a2fSth160488 }
1350e1dd0a2fSth160488 }
1351e1dd0a2fSth160488
1352e1dd0a2fSth160488 /* check if max. users using or waiting for the connection */
1353e1dd0a2fSth160488 if ((cm->state == NS_CONN_MT_CONNECTED &&
1354e1dd0a2fSth160488 cm->cu_max != NS_CONN_MT_USER_NO_MAX &&
1355e1dd0a2fSth160488 cm->cu_cnt >= cm->cu_max) ||
1356e1dd0a2fSth160488 (cm->state == NS_CONN_MT_CONNECTING &&
1357e1dd0a2fSth160488 cm->cu_max != NS_CONN_MT_USER_NO_MAX &&
1358e1dd0a2fSth160488 cm->waiter_cnt >= cm->cu_max - 1))
1359e1dd0a2fSth160488 matched = B_FALSE;
1360e1dd0a2fSth160488 }
1361e1dd0a2fSth160488
1362e1dd0a2fSth160488 if (matched == B_FALSE)
1363e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1364e1dd0a2fSth160488
1365e1dd0a2fSth160488 return (matched);
1366e1dd0a2fSth160488 }
1367e1dd0a2fSth160488
1368e1dd0a2fSth160488 /*
1369e1dd0a2fSth160488 * obtain an MT connection from the connection management for a conn_user
1370e1dd0a2fSth160488 *
1371e1dd0a2fSth160488 * Input:
1372e1dd0a2fSth160488 * server : server name or IP address
1373e1dd0a2fSth160488 * flags : libsldap API flags
1374e1dd0a2fSth160488 * cred : pointer to the user credential
1375e1dd0a2fSth160488 * cu : pointer to the conn_user structure
1376e1dd0a2fSth160488 * Output:
1377e1dd0a2fSth160488 * session : hold pointer to the Connection structure
1378e1dd0a2fSth160488 * errorp : hold pointer to error info (ns_ldap_error_t)
1379e1dd0a2fSth160488 */
1380e1dd0a2fSth160488 int
__s_api_conn_mt_get(const char * server,const int flags,const ns_cred_t * cred,Connection ** session,ns_ldap_error_t ** errorp,ns_conn_user_t * cu)1381e1dd0a2fSth160488 __s_api_conn_mt_get(const char *server, const int flags, const ns_cred_t *cred,
1382e1dd0a2fSth160488 Connection **session, ns_ldap_error_t **errorp, ns_conn_user_t *cu)
1383e1dd0a2fSth160488 {
1384e1dd0a2fSth160488 int rc;
1385e1dd0a2fSth160488 int i;
1386e1dd0a2fSth160488 ns_conn_mt_t *cn;
1387e1dd0a2fSth160488 ns_conn_mt_state_t st;
1388e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
1389e1dd0a2fSth160488
1390e1dd0a2fSth160488 if (errorp == NULL || cu == NULL || session == NULL)
1391e1dd0a2fSth160488 return (NS_LDAP_INVALID_PARAM);
1392e1dd0a2fSth160488
1393e1dd0a2fSth160488 *session = NULL;
1394e1dd0a2fSth160488 cmg = cu->conn_mgmt;
1395e1dd0a2fSth160488
1396e1dd0a2fSth160488 /*
1397e1dd0a2fSth160488 * for pam_ldap, always try opening a new connection
1398e1dd0a2fSth160488 */
1399e1dd0a2fSth160488 if (cu->type == NS_CONN_USER_AUTH)
1400e1dd0a2fSth160488 return (NS_LDAP_NOTFOUND);
1401e1dd0a2fSth160488
1402e1dd0a2fSth160488 /* if need a new conn, then don't reuse */
1403e1dd0a2fSth160488 if (flags & NS_LDAP_NEW_CONN)
1404e1dd0a2fSth160488 return (NS_LDAP_NOTFOUND);
1405e1dd0a2fSth160488
1406e1dd0a2fSth160488 if (flags & NS_LDAP_KEEP_CONN)
1407e1dd0a2fSth160488 cu->keep_conn = B_TRUE;
1408e1dd0a2fSth160488
1409e1dd0a2fSth160488 /*
1410e1dd0a2fSth160488 * We want to use MT connection only if keep-connection flag is
1411e1dd0a2fSth160488 * set or if MT was requested (or active)
1412e1dd0a2fSth160488 */
1413e1dd0a2fSth160488 if (!((cmg->state == NS_CONN_MGMT_INACTIVE &&
1414e1dd0a2fSth160488 cu->keep_conn == B_TRUE) || cmg->state == NS_CONN_MGMT_ACTIVE))
1415e1dd0a2fSth160488 return (NS_LDAP_NOTFOUND);
1416e1dd0a2fSth160488
1417e1dd0a2fSth160488 /* MT connection will be used now (if possible/available) */
1418e1dd0a2fSth160488 cu->use_mt_conn = B_TRUE;
1419e1dd0a2fSth160488
1420e1dd0a2fSth160488 NS_CONN_CHECK_ABORT_AND_LOCK(cmg, cu, errorp);
1421e1dd0a2fSth160488
1422e1dd0a2fSth160488 /* first look for a connection already open */
1423e1dd0a2fSth160488 st = NS_CONN_MT_CONNECTED;
1424e1dd0a2fSth160488 cu->state = NS_CONN_USER_FINDING;
1425e1dd0a2fSth160488 for (i = 0; i < 2; i++) {
1426e1dd0a2fSth160488 for (cn = cmg->cm_head; cn; cn = cn->next) {
1427e1dd0a2fSth160488 (void) mutex_lock(&cn->lock);
1428e1dd0a2fSth160488 rc = match_conn_mt(cu, &cn, st, server, cred);
1429e1dd0a2fSth160488 if (rc == B_FALSE && cn != NULL) /* not found */
1430e1dd0a2fSth160488 continue;
1431e1dd0a2fSth160488 if (cn == NULL) { /* not found and cn freed */
1432e1dd0a2fSth160488 /*
1433e1dd0a2fSth160488 * as the conn_mt list could
1434e1dd0a2fSth160488 * be different due to cn's
1435e1dd0a2fSth160488 * deletion, scan the entire
1436e1dd0a2fSth160488 * conn_mt list again
1437e1dd0a2fSth160488 */
1438e1dd0a2fSth160488 st = NS_CONN_MT_CONNECTED;
1439e1dd0a2fSth160488 i = -1;
1440e1dd0a2fSth160488 break;
1441e1dd0a2fSth160488 }
1442e1dd0a2fSth160488
1443e1dd0a2fSth160488 /* return a connected one if found */
1444e1dd0a2fSth160488 if (cn->state == NS_CONN_MT_CONNECTED) {
1445e1dd0a2fSth160488 *session = cn->conn;
1446e1dd0a2fSth160488 add_cu2cm(cu, cn);
1447e1dd0a2fSth160488 cu->conn_mt = cn;
1448e1dd0a2fSth160488 cu->state = NS_CONN_USER_CONNECTED;
1449e1dd0a2fSth160488 (void) mutex_unlock(&cn->lock);
1450e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
1451e1dd0a2fSth160488 return (NS_LDAP_SUCCESS);
1452e1dd0a2fSth160488 }
1453e1dd0a2fSth160488
1454e1dd0a2fSth160488 /*
1455e1dd0a2fSth160488 * if cn is not connecting, or allow only
1456e1dd0a2fSth160488 * one user, skip it
1457e1dd0a2fSth160488 */
1458e1dd0a2fSth160488 if (cn->state != NS_CONN_MT_CONNECTING ||
1459e1dd0a2fSth160488 cn->cu_max == 1) {
1460e1dd0a2fSth160488 (void) mutex_unlock(&cn->lock);
1461e1dd0a2fSth160488 continue;
1462e1dd0a2fSth160488 }
1463e1dd0a2fSth160488
1464e1dd0a2fSth160488 /* wait for the connecting conn_mt */
1465e1dd0a2fSth160488 if (wait_for_conn_mt(cu, cn) != 1) {
1466e1dd0a2fSth160488 /*
1467e1dd0a2fSth160488 * NS_LDAP_NOTFOUND signals that the function
1468e1dd0a2fSth160488 * __s_api_check_libldap_MT_conn_support()
1469e1dd0a2fSth160488 * detected that the lower libldap library
1470e1dd0a2fSth160488 * does not support MT connection, so return
1471e1dd0a2fSth160488 * NS_LDAP_NOTFOUND to let the caller to
1472e1dd0a2fSth160488 * open a non-MT conneciton. Otherwise,
1473e1dd0a2fSth160488 * connect error occurred, return
1474e1dd0a2fSth160488 * NS_CONN_USER_CONNECT_ERROR
1475e1dd0a2fSth160488 */
1476e1dd0a2fSth160488 if (cn->ns_rc != NS_LDAP_NOTFOUND)
1477e1dd0a2fSth160488 cu->state = NS_CONN_USER_CONNECT_ERROR;
1478e1dd0a2fSth160488 else {
1479e1dd0a2fSth160488 cu->state = NS_CONN_USER_FINDING;
1480e1dd0a2fSth160488 cu->use_mt_conn = B_FALSE;
1481e1dd0a2fSth160488 }
1482e1dd0a2fSth160488 (void) mutex_unlock(&cn->lock);
1483e1dd0a2fSth160488
1484e1dd0a2fSth160488 /* cmg->lock unlocked by wait_for_conn_mt() */
1485e1dd0a2fSth160488
1486e1dd0a2fSth160488 return (cn->ns_rc);
1487e1dd0a2fSth160488 }
1488e1dd0a2fSth160488
1489e1dd0a2fSth160488 /* return the newly available conn_mt */
1490e1dd0a2fSth160488 *session = cn->conn;
1491e1dd0a2fSth160488 cu->state = NS_CONN_USER_CONNECTED;
1492e1dd0a2fSth160488 (void) mutex_unlock(&cn->lock);
1493e1dd0a2fSth160488
1494e1dd0a2fSth160488 /* cmg->lock unlocked by wait_for_conn_mt() */
1495e1dd0a2fSth160488
1496e1dd0a2fSth160488 return (NS_LDAP_SUCCESS);
1497e1dd0a2fSth160488 }
1498e1dd0a2fSth160488
1499e1dd0a2fSth160488 /* next, look for a connecting conn_mt */
1500e1dd0a2fSth160488 if (i == 0)
1501e1dd0a2fSth160488 st = NS_CONN_MT_CONNECTING;
1502e1dd0a2fSth160488 }
1503e1dd0a2fSth160488
1504e1dd0a2fSth160488 /* no connection found, start opening one */
1505e1dd0a2fSth160488 cn = init_conn_mt(cmg, errorp);
1506e1dd0a2fSth160488 if (cn == NULL) {
1507e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
1508e1dd0a2fSth160488 return ((*errorp)->status);
1509e1dd0a2fSth160488 }
1510e1dd0a2fSth160488 cu->conn_mt = cn;
1511e1dd0a2fSth160488 cn->opened_for = cu->type;
1512e1dd0a2fSth160488 cn->referral = cu->referral;
1513e1dd0a2fSth160488 if (cmg->ldap_mt == B_TRUE)
1514e1dd0a2fSth160488 cn->cu_max = NS_CONN_MT_USER_MAX;
1515e1dd0a2fSth160488 else
1516e1dd0a2fSth160488 cn->cu_max = 1;
1517e1dd0a2fSth160488 add_cm2cmg(cn, cmg);
1518e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
1519e1dd0a2fSth160488
1520e1dd0a2fSth160488 return (NS_LDAP_NOTFOUND);
1521e1dd0a2fSth160488 }
1522e1dd0a2fSth160488
1523e1dd0a2fSth160488
1524e1dd0a2fSth160488 /*
1525e1dd0a2fSth160488 * add an MT connection to the connection management
1526e1dd0a2fSth160488 *
1527e1dd0a2fSth160488 * Input:
1528e1dd0a2fSth160488 * con : pointer to the Connection info
1529e1dd0a2fSth160488 * cu : pointer to the conn_user structure
1530e1dd0a2fSth160488 * Output:
1531e1dd0a2fSth160488 * ep : hold pointer to error info (ns_ldap_error_t)
1532e1dd0a2fSth160488 */
1533e1dd0a2fSth160488 int
__s_api_conn_mt_add(Connection * con,ns_conn_user_t * cu,ns_ldap_error_t ** ep)1534e1dd0a2fSth160488 __s_api_conn_mt_add(Connection *con, ns_conn_user_t *cu, ns_ldap_error_t **ep)
1535e1dd0a2fSth160488 {
1536e1dd0a2fSth160488 ns_conn_mgmt_t *cmg = cu->conn_mgmt;
1537e1dd0a2fSth160488 ns_conn_mt_t *cm = cu->conn_mt;
1538e1dd0a2fSth160488
1539e1dd0a2fSth160488 /* if the conn_mgmt is being shut down, return error */
1540e1dd0a2fSth160488 NS_CONN_CHECK_ABORT_AND_LOCK(cmg, cu, ep);
1541e1dd0a2fSth160488
1542e1dd0a2fSth160488 /*
1543e1dd0a2fSth160488 * start the change monitor thread only if it
1544e1dd0a2fSth160488 * hasn't been started and the process is the
1545e1dd0a2fSth160488 * main nscd (not peruser nscd)
1546e1dd0a2fSth160488 */
1547e1dd0a2fSth160488 if (cmg->procchg_started == B_FALSE && cmg->is_nscd == B_TRUE) {
1548e1dd0a2fSth160488 start_thread(cmg);
1549e1dd0a2fSth160488 cmg->procchg_started = B_TRUE;
1550e1dd0a2fSth160488 }
1551e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
1552e1dd0a2fSth160488 cm->conn = con;
1553e1dd0a2fSth160488 cm->state = NS_CONN_MT_CONNECTED;
1554e1dd0a2fSth160488 cm->pid = getpid();
1555e1dd0a2fSth160488 cm->create_time = time(NULL);
1556e1dd0a2fSth160488 cm->access_time = cm->create_time;
1557e1dd0a2fSth160488 cm->opened_for = cu->type;
1558e1dd0a2fSth160488 add_cu2cm(cu, cm);
1559e1dd0a2fSth160488 cu->conn_mt = cm;
1560e1dd0a2fSth160488 cu->state = NS_CONN_USER_CONNECTED;
1561e1dd0a2fSth160488 if (cmg->ldap_mt == B_TRUE)
1562e1dd0a2fSth160488 cm->cu_max = NS_CONN_MT_USER_MAX;
1563e1dd0a2fSth160488 else
1564e1dd0a2fSth160488 cm->cu_max = 1;
1565e1dd0a2fSth160488
1566e1dd0a2fSth160488 /* wake up the waiters if any */
1567e1dd0a2fSth160488 (void) conn_signal(cm);
1568e1dd0a2fSth160488
1569e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1570e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
1571e1dd0a2fSth160488
1572e1dd0a2fSth160488 return (NS_LDAP_SUCCESS);
1573e1dd0a2fSth160488 }
1574e1dd0a2fSth160488
1575e1dd0a2fSth160488 /*
1576ca190d8dSmichen * return an MT connection to the pool when a conn user is done using it
1577e1dd0a2fSth160488 *
1578e1dd0a2fSth160488 * Input:
1579e1dd0a2fSth160488 * cu : pointer to the conn_user structure
1580e1dd0a2fSth160488 * Output: NONE
1581e1dd0a2fSth160488 */
1582e1dd0a2fSth160488 void
__s_api_conn_mt_return(ns_conn_user_t * cu)1583e1dd0a2fSth160488 __s_api_conn_mt_return(ns_conn_user_t *cu)
1584e1dd0a2fSth160488 {
1585e1dd0a2fSth160488 ns_conn_mt_t *cm;
1586e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
1587e1dd0a2fSth160488
1588e1dd0a2fSth160488 if (cu == NULL || cu->use_mt_conn == B_FALSE)
1589e1dd0a2fSth160488 return;
1590e1dd0a2fSth160488 cm = cu->conn_mt;
1591e1dd0a2fSth160488 if (cm == NULL)
1592e1dd0a2fSth160488 return;
1593e1dd0a2fSth160488 cmg = cu->conn_mgmt;
1594e1dd0a2fSth160488
1595e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
1596e1dd0a2fSth160488 del_cu4cm(cu, cm);
1597e1dd0a2fSth160488 cu->state = NS_CONN_USER_DISCONNECTED;
1598e1dd0a2fSth160488 cu->conn_mt = NULL;
1599e1dd0a2fSth160488 cu->bad_mt_conn = B_FALSE;
1600e1dd0a2fSth160488
1601e1dd0a2fSth160488 /*
1602e1dd0a2fSth160488 * if this MT connection is no longer needed, or not usable, and
1603e1dd0a2fSth160488 * no more conn_user uses it, then close it.
1604e1dd0a2fSth160488 */
1605e1dd0a2fSth160488
1606e1dd0a2fSth160488 if ((cm->close_when_nouser == B_TRUE ||
1607e1dd0a2fSth160488 cm->state != NS_CONN_MT_CONNECTED) && cm->cu_cnt == 0) {
1608e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1609e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
1610e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
1611e1dd0a2fSth160488 del_cm4cmg(cm, cmg);
1612e1dd0a2fSth160488 /* use ns_conn_free (instead of 1) to avoid lint warning */
1613e1dd0a2fSth160488 NS_CONN_UNLOCK_AND_FREE(ns_conn_free, cm, cmg);
1614e1dd0a2fSth160488 } else {
1615e1dd0a2fSth160488 if (cm->state == NS_CONN_MT_CONNECTED && cm->cu_cnt == 0 &&
1616e1dd0a2fSth160488 cm->conn != NULL && cm->conn->ld != NULL) {
1617e1dd0a2fSth160488 struct timeval zerotime;
1618e1dd0a2fSth160488 LDAPMessage *res;
1619e1dd0a2fSth160488
1620e1dd0a2fSth160488 zerotime.tv_sec = zerotime.tv_usec = 0L;
1621e1dd0a2fSth160488 /* clean up remaining results just in case */
1622e1dd0a2fSth160488 while (ldap_result(cm->conn->ld, LDAP_RES_ANY,
1623e1dd0a2fSth160488 LDAP_MSG_ALL, &zerotime, &res) > 0) {
1624e1dd0a2fSth160488 if (res != NULL)
1625e1dd0a2fSth160488 (void) ldap_msgfree(res);
1626e1dd0a2fSth160488 }
1627e1dd0a2fSth160488 }
1628e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1629e1dd0a2fSth160488 }
1630e1dd0a2fSth160488 }
1631e1dd0a2fSth160488
1632e1dd0a2fSth160488 /* save error info (rc and ns_ldap_error_t) in the conn_mt */
1633e1dd0a2fSth160488 static void
err2cm(ns_conn_mt_t * cm,int rc,ns_ldap_error_t ** errorp)1634e1dd0a2fSth160488 err2cm(ns_conn_mt_t *cm, int rc, ns_ldap_error_t **errorp) {
1635e1dd0a2fSth160488 ns_ldap_error_t *ep;
1636e1dd0a2fSth160488
1637e1dd0a2fSth160488 cm->ns_rc = rc;
1638e1dd0a2fSth160488 cm->ns_error = NULL;
1639e1dd0a2fSth160488 if (errorp != NULL && *errorp != NULL) {
1640e1dd0a2fSth160488 ep = __s_api_copy_error(*errorp);
1641e1dd0a2fSth160488 if (ep == NULL)
1642e1dd0a2fSth160488 cm->ns_rc = NS_LDAP_MEMORY;
1643e1dd0a2fSth160488 else
1644e1dd0a2fSth160488 cm->ns_error = ep;
1645e1dd0a2fSth160488 }
1646e1dd0a2fSth160488 }
1647e1dd0a2fSth160488
1648e1dd0a2fSth160488 /* copy error info (rc and ns_ldap_error_t) from conn_mt to conn_user */
1649e1dd0a2fSth160488 static void
err_from_cm(ns_conn_user_t * cu,ns_conn_mt_t * cm)1650e1dd0a2fSth160488 err_from_cm(ns_conn_user_t *cu, ns_conn_mt_t *cm) {
1651e1dd0a2fSth160488 ns_ldap_error_t *ep;
1652e1dd0a2fSth160488
1653e1dd0a2fSth160488 cu->ns_rc = cm->ns_rc;
1654e1dd0a2fSth160488 if (cu->ns_error != NULL)
1655e1dd0a2fSth160488 (void) __ns_ldap_freeError(&cu->ns_error);
1656e1dd0a2fSth160488 cu->ns_error = NULL;
1657e1dd0a2fSth160488 if (cm->ns_rc != NS_LDAP_SUCCESS && cm->ns_error != NULL) {
1658e1dd0a2fSth160488 ep = __s_api_copy_error(cm->ns_error);
1659e1dd0a2fSth160488 if (ep == NULL)
1660e1dd0a2fSth160488 cu->ns_rc = NS_LDAP_MEMORY;
1661e1dd0a2fSth160488 else
1662e1dd0a2fSth160488 cu->ns_error = ep;
1663e1dd0a2fSth160488 }
1664e1dd0a2fSth160488 }
1665e1dd0a2fSth160488
1666e1dd0a2fSth160488 /* copy error info (rc and ns_ldap_error_t) from caller to conn_user */
1667e1dd0a2fSth160488 static void
err_from_caller(ns_conn_user_t * cu,int rc,ns_ldap_error_t ** errorp)1668e1dd0a2fSth160488 err_from_caller(ns_conn_user_t *cu, int rc, ns_ldap_error_t **errorp) {
1669e1dd0a2fSth160488
1670e1dd0a2fSth160488 cu->ns_rc = rc;
1671e1dd0a2fSth160488 if (errorp != NULL) {
1672e1dd0a2fSth160488 if (cu->ns_error != NULL)
1673e1dd0a2fSth160488 (void) __ns_ldap_freeError(&cu->ns_error);
1674e1dd0a2fSth160488 cu->ns_error = *errorp;
1675e1dd0a2fSth160488 *errorp = NULL;
1676e1dd0a2fSth160488 } else
1677e1dd0a2fSth160488 cu->ns_error = NULL;
1678e1dd0a2fSth160488 }
1679e1dd0a2fSth160488
1680e1dd0a2fSth160488 /*
1681e1dd0a2fSth160488 * remove an MT connection from the connection management when failed to open
1682e1dd0a2fSth160488 *
1683e1dd0a2fSth160488 * Input:
1684e1dd0a2fSth160488 * cu : pointer to the conn_user structure
1685e1dd0a2fSth160488 * rc : error code
1686e1dd0a2fSth160488 * errorp : pointer to pointer to error info (ns_ldap_error_t)
1687e1dd0a2fSth160488 * Output:
1688e1dd0a2fSth160488 * errorp : set to NULL, if none NULL cm, callers do not need to free it
1689e1dd0a2fSth160488 */
1690e1dd0a2fSth160488 void
__s_api_conn_mt_remove(ns_conn_user_t * cu,int rc,ns_ldap_error_t ** errorp)1691e1dd0a2fSth160488 __s_api_conn_mt_remove(ns_conn_user_t *cu, int rc, ns_ldap_error_t **errorp)
1692e1dd0a2fSth160488 {
1693e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
1694e1dd0a2fSth160488 ns_conn_mt_t *cm;
1695e1dd0a2fSth160488 int free_cm = 0;
1696e1dd0a2fSth160488
1697e1dd0a2fSth160488 if (cu == NULL || cu->use_mt_conn == B_FALSE)
1698e1dd0a2fSth160488 return;
1699e1dd0a2fSth160488 if ((cm = cu->conn_mt) == NULL)
1700e1dd0a2fSth160488 return;
1701e1dd0a2fSth160488 cmg = cu->conn_mgmt;
1702e1dd0a2fSth160488
1703e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
1704e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
1705e1dd0a2fSth160488 if (cm->state != NS_CONN_MT_CONNECT_ERROR) {
1706e1dd0a2fSth160488 cm->state = NS_CONN_MT_CONNECT_ERROR;
1707e1dd0a2fSth160488 cm->ns_rc = rc;
1708e1dd0a2fSth160488 if (errorp != NULL) {
1709e1dd0a2fSth160488 cm->ns_error = *errorp;
1710e1dd0a2fSth160488 *errorp = NULL;
1711e1dd0a2fSth160488 }
1712e1dd0a2fSth160488 }
1713e1dd0a2fSth160488
1714e1dd0a2fSth160488 /* all the conn_users share the same error rc and ns_ldap_error_t */
1715e1dd0a2fSth160488 err_from_cm(cu, cm);
1716e1dd0a2fSth160488 /* wake up the waiters if any */
1717e1dd0a2fSth160488 (void) conn_signal(cm);
1718e1dd0a2fSth160488
1719e1dd0a2fSth160488 del_cu4cm(cu, cm);
1720e1dd0a2fSth160488 cu->conn_mt = NULL;
1721e1dd0a2fSth160488 cu->bad_mt_conn = B_FALSE;
1722e1dd0a2fSth160488 if (cm->cu_cnt == 0) {
1723e1dd0a2fSth160488 del_cm4cmg(cm, cmg);
1724e1dd0a2fSth160488 free_cm = 1;
1725e1dd0a2fSth160488 }
1726e1dd0a2fSth160488
1727e1dd0a2fSth160488 NS_CONN_UNLOCK_AND_FREE(free_cm, cm, cmg);
1728e1dd0a2fSth160488 }
1729e1dd0a2fSth160488
1730e1dd0a2fSth160488 /*
1731e1dd0a2fSth160488 * check to see if the underlying libldap supports multi-threaded client
1732e1dd0a2fSth160488 * (MT connections)
1733e1dd0a2fSth160488 */
1734e1dd0a2fSth160488 int
__s_api_check_libldap_MT_conn_support(ns_conn_user_t * cu,LDAP * ld,ns_ldap_error_t ** ep)1735e1dd0a2fSth160488 __s_api_check_libldap_MT_conn_support(ns_conn_user_t *cu, LDAP *ld,
1736e1dd0a2fSth160488 ns_ldap_error_t **ep)
1737e1dd0a2fSth160488 {
1738e1dd0a2fSth160488 int rc;
1739e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
1740e1dd0a2fSth160488
1741e1dd0a2fSth160488 /* if no need to check, just return success */
1742e1dd0a2fSth160488 if (cu->conn_mt == NULL || cu->use_mt_conn == B_FALSE)
1743e1dd0a2fSth160488 return (NS_LDAP_SUCCESS);
1744e1dd0a2fSth160488
1745e1dd0a2fSth160488 cmg = cu->conn_mgmt;
1746e1dd0a2fSth160488 rc = setup_mt_ld(ld, cmg);
1747e1dd0a2fSth160488
1748e1dd0a2fSth160488 if (cmg->do_mt_conn == B_FALSE) {
1749e1dd0a2fSth160488 /*
1750e1dd0a2fSth160488 * If the conn_mgmt is being shut down, return error.
1751e1dd0a2fSth160488 * if cmg is usable, cmg->lock will be locked. Otherwise,
1752e1dd0a2fSth160488 * this function will return with rc NS_LDAP_OP_FAILED.
1753e1dd0a2fSth160488 */
1754e1dd0a2fSth160488 NS_CONN_CHECK_ABORT_AND_LOCK(cmg, cu, ep);
1755e1dd0a2fSth160488 if (cmg->do_mt_conn == B_FALSE) {
1756e1dd0a2fSth160488 if (rc < 0)
1757e1dd0a2fSth160488 cmg->ldap_mt = B_FALSE;
1758e1dd0a2fSth160488 else {
1759e1dd0a2fSth160488 cmg->ldap_mt = B_TRUE;
1760e1dd0a2fSth160488 if (cmg->is_nscd == B_TRUE ||
1761e1dd0a2fSth160488 cmg->is_peruser_nscd == B_TRUE) {
1762e1dd0a2fSth160488 cmg->do_mt_conn = B_TRUE;
1763e1dd0a2fSth160488 cmg->state = NS_CONN_MGMT_ACTIVE;
1764e1dd0a2fSth160488 }
1765e1dd0a2fSth160488 }
1766e1dd0a2fSth160488 }
1767e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
1768e1dd0a2fSth160488 }
1769e1dd0a2fSth160488
1770e1dd0a2fSth160488 if (rc < 0)
1771e1dd0a2fSth160488 __s_api_conn_mt_remove(cu, NS_LDAP_NOTFOUND, NULL);
1772e1dd0a2fSth160488 return (NS_LDAP_SUCCESS);
1773e1dd0a2fSth160488 }
1774e1dd0a2fSth160488
1775e1dd0a2fSth160488 /*
1776e1dd0a2fSth160488 * Close an MT connection.
1777e1dd0a2fSth160488 * Assume cm not null and locked, assume conn_mgmt is also locked.
1778e1dd0a2fSth160488 * Return -1 if error, 1 if the cm should be freed, otherwise 0.
1779e1dd0a2fSth160488 */
1780e1dd0a2fSth160488 static int
close_conn_mt(ns_conn_mt_t * cm,int rc,ns_ldap_error_t ** errorp,ns_conn_user_t * cu)1781e1dd0a2fSth160488 close_conn_mt(ns_conn_mt_t *cm, int rc, ns_ldap_error_t **errorp,
1782e1dd0a2fSth160488 ns_conn_user_t *cu)
1783e1dd0a2fSth160488 {
1784e1dd0a2fSth160488 ns_conn_mgmt_t *cmg = cm->conn_mgmt;
1785e1dd0a2fSth160488 ns_conn_mt_t *m;
1786e1dd0a2fSth160488 ns_conn_user_t *u;
1787e1dd0a2fSth160488
1788e1dd0a2fSth160488 if ((cm->state != NS_CONN_MT_CONNECTED && cm->state !=
1789e1dd0a2fSth160488 NS_CONN_MT_CLOSING) || cmg->cm_head == NULL || cmg->cm_cnt == 0)
1790e1dd0a2fSth160488 return (-1);
1791e1dd0a2fSth160488
1792e1dd0a2fSth160488 /* if the conn_mt is not in the MT connection pool, nothing to do */
1793e1dd0a2fSth160488 for (m = cmg->cm_head; m; m = m->next) {
1794e1dd0a2fSth160488 if (cm == m)
1795e1dd0a2fSth160488 break;
1796e1dd0a2fSth160488 }
1797e1dd0a2fSth160488 if (m == NULL)
1798e1dd0a2fSth160488 return (-1);
1799e1dd0a2fSth160488
1800e1dd0a2fSth160488 if (cm->state == NS_CONN_MT_CONNECTED) { /* first time in here */
1801e1dd0a2fSth160488 cm->state = NS_CONN_MT_CLOSING;
1802e1dd0a2fSth160488 /*
1803e1dd0a2fSth160488 * If more cu exist to consume the error info, copy
1804e1dd0a2fSth160488 * it to the cm. If the caller calls on behalf of
1805e1dd0a2fSth160488 * a cu, cu won't be NULL. Check to see if there's
1806e1dd0a2fSth160488 * more cu that needs the error info. If caller does
1807e1dd0a2fSth160488 * not have a specific cu attached to it (e.g.,
1808e1dd0a2fSth160488 * shutdown_all_conn_mt()), cu is NULL, check if at
1809e1dd0a2fSth160488 * least one cu exists.
1810e1dd0a2fSth160488 */
1811e1dd0a2fSth160488 if ((cu != NULL && cm->cu_cnt > 1) ||
1812e1dd0a2fSth160488 (cu == NULL && cm->cu_cnt > 0)) {
1813e1dd0a2fSth160488 err2cm(cm, rc, errorp);
1814e1dd0a2fSth160488 /* wake up waiter (conn_user) if any */
1815e1dd0a2fSth160488 (void) conn_signal(cm);
1816e1dd0a2fSth160488 }
1817e1dd0a2fSth160488
1818e1dd0a2fSth160488 /* for each conn_user using the conn_mt, set bad_mt_conn flag */
1819e1dd0a2fSth160488 if (cm->cu_head != NULL) {
1820e1dd0a2fSth160488 for (u = cm->cu_head; u; u = u->next) {
1821e1dd0a2fSth160488 u->bad_mt_conn = B_TRUE;
1822e1dd0a2fSth160488 if (cmg->shutting_down == B_FALSE)
1823e1dd0a2fSth160488 u->retry = B_TRUE;
1824e1dd0a2fSth160488 }
1825e1dd0a2fSth160488 }
1826e1dd0a2fSth160488 }
1827e1dd0a2fSth160488
1828e1dd0a2fSth160488 /* detach the conn_mt if no more conn_user left */
1829e1dd0a2fSth160488 if ((cu != NULL && cm->cu_cnt == 1) ||
1830e1dd0a2fSth160488 (cu == NULL && cm->cu_cnt == 0)) {
1831e1dd0a2fSth160488 del_cm4cmg(cm, cmg);
1832e1dd0a2fSth160488 cm->detached = B_TRUE;
1833e1dd0a2fSth160488 return (1);
1834e1dd0a2fSth160488 }
1835e1dd0a2fSth160488
1836e1dd0a2fSth160488 return (0);
1837e1dd0a2fSth160488 }
1838e1dd0a2fSth160488
1839e1dd0a2fSth160488 /*
1840e1dd0a2fSth160488 * An MT connection becomes bad, close it and free resources.
1841e1dd0a2fSth160488 * This function is called with a ns_conn_user_t representing
1842e1dd0a2fSth160488 * a user of the MT connection.
1843e1dd0a2fSth160488 *
1844e1dd0a2fSth160488 * Input:
1845e1dd0a2fSth160488 * cu : pointer to the conn_user structure
1846e1dd0a2fSth160488 * rc : error code
1847e1dd0a2fSth160488 * errorp : pointer to pointer to error info (ns_ldap_error_t)
1848e1dd0a2fSth160488 * Output:
1849e1dd0a2fSth160488 * errorp : set to NULL (if no error), callers do not need to free it
1850e1dd0a2fSth160488 */
1851e1dd0a2fSth160488 void
__s_api_conn_mt_close(ns_conn_user_t * cu,int rc,ns_ldap_error_t ** errorp)1852e1dd0a2fSth160488 __s_api_conn_mt_close(ns_conn_user_t *cu, int rc, ns_ldap_error_t **errorp)
1853e1dd0a2fSth160488 {
1854e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
1855e1dd0a2fSth160488 ns_conn_mt_t *cm;
1856e1dd0a2fSth160488 int free_cm = 0;
1857e1dd0a2fSth160488
1858e1dd0a2fSth160488 if (cu == NULL || cu->use_mt_conn == B_FALSE)
1859e1dd0a2fSth160488 return;
1860e1dd0a2fSth160488
1861e1dd0a2fSth160488 if (cu->state != NS_CONN_USER_CONNECTED || (cm = cu->conn_mt) == NULL)
1862e1dd0a2fSth160488 return;
1863e1dd0a2fSth160488 cmg = cu->conn_mgmt;
1864e1dd0a2fSth160488
1865e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
1866e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
1867e1dd0a2fSth160488
1868e1dd0a2fSth160488 /* close the MT connection if possible */
1869e1dd0a2fSth160488 free_cm = close_conn_mt(cm, rc, errorp, cu);
1870e1dd0a2fSth160488 if (free_cm == -1) { /* error case */
1871e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1872e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
1873e1dd0a2fSth160488 return;
1874e1dd0a2fSth160488 }
1875e1dd0a2fSth160488
1876e1dd0a2fSth160488 if (rc != NS_LDAP_SUCCESS) { /* error info passed in, use it */
1877e1dd0a2fSth160488 err_from_caller(cu, rc, errorp);
1878e1dd0a2fSth160488 } else { /* error not passed in, use those saved in the conn_mt */
1879e1dd0a2fSth160488 err_from_cm(cu, cm);
1880e1dd0a2fSth160488 }
1881e1dd0a2fSth160488
1882e1dd0a2fSth160488 /* detach the conn_user from the conn_mt */
1883e1dd0a2fSth160488 del_cu4cm(cu, cm);
1884e1dd0a2fSth160488 cu->conn_mt = NULL;
1885e1dd0a2fSth160488 cu->bad_mt_conn = B_FALSE;
1886e1dd0a2fSth160488 if (cmg->shutting_down == B_FALSE)
1887e1dd0a2fSth160488 cu->retry = B_TRUE;
1888e1dd0a2fSth160488 NS_CONN_UNLOCK_AND_FREE(free_cm, cm, cmg);
1889e1dd0a2fSth160488 }
1890e1dd0a2fSth160488
1891e1dd0a2fSth160488 /*
1892e1dd0a2fSth160488 * Close an MT connection when the associated server is known to be
1893e1dd0a2fSth160488 * down. This function is called with a ns_conn_mt_t representing
1894e1dd0a2fSth160488 * the MT connection. That is, the caller is not a conn_user
1895e1dd0a2fSth160488 * thread but rather the procchg thread.
1896e1dd0a2fSth160488 */
1897e1dd0a2fSth160488 static void
close_conn_mt_by_procchg(ns_conn_mt_t * cm,int rc,char * errmsg)1898e1dd0a2fSth160488 close_conn_mt_by_procchg(ns_conn_mt_t *cm, int rc, char *errmsg)
1899e1dd0a2fSth160488 {
1900e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
1901e1dd0a2fSth160488 int free_cm = 0;
1902e1dd0a2fSth160488 ns_ldap_error_t *ep;
1903e1dd0a2fSth160488
1904e1dd0a2fSth160488 if (cm == NULL)
1905e1dd0a2fSth160488 return;
1906e1dd0a2fSth160488 cmg = cm->conn_mgmt;
1907e1dd0a2fSth160488
1908e1dd0a2fSth160488 ep = (ns_ldap_error_t *)calloc(1, sizeof (*ep));
1909e1dd0a2fSth160488 if (ep != NULL) {
1910e1dd0a2fSth160488 ep->status = rc;
1911e1dd0a2fSth160488 if (errmsg != NULL)
1912e1dd0a2fSth160488 ep->message = strdup(errmsg); /* OK if returns NULL */
1913e1dd0a2fSth160488 }
1914e1dd0a2fSth160488
1915e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
1916e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
1917e1dd0a2fSth160488
1918e1dd0a2fSth160488 /* close the MT connection if possible */
1919e1dd0a2fSth160488 free_cm = close_conn_mt(cm, LDAP_SERVER_DOWN, &ep, NULL);
1920e1dd0a2fSth160488 if (free_cm == -1) { /* error case */
1921e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
1922e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
1923e1dd0a2fSth160488 return;
1924e1dd0a2fSth160488 }
1925e1dd0a2fSth160488 (void) __ns_ldap_freeError(&ep);
1926e1dd0a2fSth160488
1927e1dd0a2fSth160488 NS_CONN_UNLOCK_AND_FREE(free_cm, cm, cmg);
1928e1dd0a2fSth160488 }
1929e1dd0a2fSth160488
1930e1dd0a2fSth160488 /*
1931e1dd0a2fSth160488 * Close an MT connection when there is a better server to connect to.
1932e1dd0a2fSth160488 * Mark the connection as to-be-closed-when-no-one-using so that
1933e1dd0a2fSth160488 * any outstanding ldap operations can run to completion.
1934e1dd0a2fSth160488 * Assume that both the conn_mt and conn_mgmt are locked.
1935e1dd0a2fSth160488 * Return 1 if the conn_mt should be freed.
1936e1dd0a2fSth160488 */
1937e1dd0a2fSth160488 static int
close_conn_mt_when_nouser(ns_conn_mt_t * cm)1938e1dd0a2fSth160488 close_conn_mt_when_nouser(ns_conn_mt_t *cm)
1939e1dd0a2fSth160488 {
1940e1dd0a2fSth160488 int free_cm = 0;
1941e1dd0a2fSth160488
1942e1dd0a2fSth160488 if (cm->cu_cnt == 0) {
1943e1dd0a2fSth160488 del_cm4cmg(cm, cm->conn_mgmt);
1944e1dd0a2fSth160488 free_cm = 1;
1945e1dd0a2fSth160488 } else {
1946e1dd0a2fSth160488 cm->close_when_nouser = B_TRUE;
1947e1dd0a2fSth160488 }
1948e1dd0a2fSth160488
1949e1dd0a2fSth160488 return (free_cm);
1950e1dd0a2fSth160488 }
1951e1dd0a2fSth160488
1952e1dd0a2fSth160488 /*
1953e1dd0a2fSth160488 * Retrieve the configured preferred server list.
1954e1dd0a2fSth160488 * This function locked the conn_mgmt and does not
1955e1dd0a2fSth160488 * unlock at exit.
1956e1dd0a2fSth160488 */
1957e1dd0a2fSth160488 static void
get_preferred_servers(boolean_t lock,boolean_t reload,ns_conn_mgmt_t * cmg)1958e1dd0a2fSth160488 get_preferred_servers(boolean_t lock, boolean_t reload, ns_conn_mgmt_t *cmg)
1959e1dd0a2fSth160488 {
1960e1dd0a2fSth160488 ns_ldap_error_t *errorp = NULL;
1961e1dd0a2fSth160488 void **pservers = NULL;
1962e1dd0a2fSth160488
1963e1dd0a2fSth160488 if (lock == B_TRUE)
1964e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
1965e1dd0a2fSth160488
1966e1dd0a2fSth160488 /* if already done, and no reload, then return */
1967e1dd0a2fSth160488 if (cmg->pservers_loaded == B_TRUE && reload == B_FALSE)
1968e1dd0a2fSth160488 return;
1969e1dd0a2fSth160488
1970e1dd0a2fSth160488 if (cmg->pservers != NULL) {
1971e1dd0a2fSth160488 (void) __ns_ldap_freeParam((void ***)&cmg->pservers);
1972e1dd0a2fSth160488 cmg->pservers = NULL;
1973e1dd0a2fSth160488 }
1974e1dd0a2fSth160488
1975e1dd0a2fSth160488 if (__ns_ldap_getParam(NS_LDAP_SERVER_PREF_P,
1976e1dd0a2fSth160488 &pservers, &errorp) == NS_LDAP_SUCCESS) {
1977e1dd0a2fSth160488 cmg->pservers = (char **)pservers;
1978e1dd0a2fSth160488 cmg->pservers_loaded = B_TRUE;
1979e1dd0a2fSth160488 } else {
1980e1dd0a2fSth160488 (void) __ns_ldap_freeError(&errorp);
1981e1dd0a2fSth160488 (void) __ns_ldap_freeParam(&pservers);
1982e1dd0a2fSth160488 }
1983e1dd0a2fSth160488 }
1984e1dd0a2fSth160488
1985e1dd0a2fSth160488 /*
1986e1dd0a2fSth160488 * This function handles the config or server status change notification
1987e1dd0a2fSth160488 * from the ldap_cachemgr.
1988e1dd0a2fSth160488 */
1989e1dd0a2fSth160488 static ns_conn_mgmt_t *
proc_server_change(ns_server_status_change_t * chg,ns_conn_mgmt_t * cmg)1990e1dd0a2fSth160488 proc_server_change(ns_server_status_change_t *chg, ns_conn_mgmt_t *cmg)
1991e1dd0a2fSth160488 {
1992e1dd0a2fSth160488 int cnt, i, j, k, n;
1993e1dd0a2fSth160488 boolean_t loop = B_TRUE;
1994e1dd0a2fSth160488 boolean_t cmg_locked = B_FALSE;
1995e1dd0a2fSth160488 char *s;
1996e1dd0a2fSth160488 ns_conn_mt_t *cm;
1997e1dd0a2fSth160488 ns_conn_mgmt_t *ocmg;
1998e1dd0a2fSth160488
1999e1dd0a2fSth160488 /* if config changed, reload the configuration */
2000e1dd0a2fSth160488 if (chg->config_changed == B_TRUE) {
2001e1dd0a2fSth160488 /* reload the conn_mgmt and Native LDAP config */
2002e1dd0a2fSth160488 ocmg = access_conn_mgmt(NS_CONN_MGMT_OP_RELOAD_CONFIG);
2003e1dd0a2fSth160488 shutdown_all_conn_mt(ocmg);
2004e1dd0a2fSth160488 /* release the one obtained from access_conn_mgmt(RELOAD) */
2005e1dd0a2fSth160488 (void) release_conn_mgmt(ocmg, B_FALSE);
2006e1dd0a2fSth160488 /* release the one obtained when ocmg was created */
2007e1dd0a2fSth160488 (void) release_conn_mgmt(ocmg, B_FALSE);
2008e1dd0a2fSth160488 return (ocmg);
2009e1dd0a2fSth160488 }
2010e1dd0a2fSth160488
2011e1dd0a2fSth160488 if ((cnt = chg->num_server) == 0)
2012e1dd0a2fSth160488 return (cmg);
2013e1dd0a2fSth160488
2014e1dd0a2fSth160488 /* handle down servers first */
2015e1dd0a2fSth160488 for (i = 0; i < cnt; i++) {
2016e1dd0a2fSth160488
2017e1dd0a2fSth160488 if (chg->changes[i] != NS_SERVER_DOWN)
2018e1dd0a2fSth160488 continue;
2019e1dd0a2fSth160488 s = chg->servers[i];
2020e1dd0a2fSth160488
2021e1dd0a2fSth160488 /*
2022e1dd0a2fSth160488 * look for a CONNECTED MT connection using
2023e1dd0a2fSth160488 * the same server s, and close it
2024e1dd0a2fSth160488 */
2025e1dd0a2fSth160488 while (loop) {
2026e1dd0a2fSth160488 if (cmg_locked == B_FALSE) {
2027e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
2028e1dd0a2fSth160488 cmg_locked = B_TRUE;
2029e1dd0a2fSth160488 }
2030e1dd0a2fSth160488 for (cm = cmg->cm_head; cm; cm = cm->next) {
2031e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
2032e1dd0a2fSth160488
2033e1dd0a2fSth160488 if (cm->state == NS_CONN_MT_CONNECTED &&
2034e1dd0a2fSth160488 cm->conn != NULL &&
2035e1dd0a2fSth160488 strcasecmp(cm->conn->serverAddr, s) == 0) {
2036e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
2037e1dd0a2fSth160488 break;
2038e1dd0a2fSth160488 }
2039e1dd0a2fSth160488
2040e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
2041e1dd0a2fSth160488 }
2042e1dd0a2fSth160488 if (cm != NULL) {
2043e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
2044e1dd0a2fSth160488 cmg_locked = B_FALSE;
2045e1dd0a2fSth160488 close_conn_mt_by_procchg(cm, LDAP_SERVER_DOWN,
2046e1dd0a2fSth160488 NS_CONN_MSG_DOWN_FROM_CACHEMGR);
2047e1dd0a2fSth160488 /*
2048e1dd0a2fSth160488 * Process the next cm using server s.
2049e1dd0a2fSth160488 * Start from the head of the cm linked
2050e1dd0a2fSth160488 * list again, as the cm list may change
2051e1dd0a2fSth160488 * after close_conn_mt_by_procchg() is done.
2052e1dd0a2fSth160488 */
2053e1dd0a2fSth160488 continue;
2054e1dd0a2fSth160488 }
2055e1dd0a2fSth160488
2056e1dd0a2fSth160488 /*
2057e1dd0a2fSth160488 * No (more) MT connection using the down server s.
2058e1dd0a2fSth160488 * Process the next server on the list.
2059e1dd0a2fSth160488 */
2060e1dd0a2fSth160488 break;
2061e1dd0a2fSth160488 } /* while loop */
2062e1dd0a2fSth160488 }
2063e1dd0a2fSth160488
2064e1dd0a2fSth160488 /*
2065e1dd0a2fSth160488 * Next handle servers whose status changed to up.
2066e1dd0a2fSth160488 * Get the preferred server list first if not done yet.
2067e1dd0a2fSth160488 * get_preferred_servers() leaves conn_mgmt locked.
2068e1dd0a2fSth160488 */
2069e1dd0a2fSth160488 get_preferred_servers(cmg_locked == B_FALSE ? B_TRUE : B_FALSE,
2070e1dd0a2fSth160488 B_FALSE, cmg);
2071e1dd0a2fSth160488 cmg_locked = B_TRUE;
2072e1dd0a2fSth160488 /*
2073e1dd0a2fSth160488 * if no preferred server configured, we don't switch MT connection
2074e1dd0a2fSth160488 * to a more preferred server (i.e., fallback), so just return
2075e1dd0a2fSth160488 */
2076e1dd0a2fSth160488 if (cmg->pservers == NULL) {
2077e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
2078e1dd0a2fSth160488 return (cmg);
2079e1dd0a2fSth160488 }
2080e1dd0a2fSth160488
2081e1dd0a2fSth160488 /* for each server that is up now */
2082e1dd0a2fSth160488 for (i = 0; i < cnt; i++) {
2083e1dd0a2fSth160488 if (chg->changes[i] != NS_SERVER_UP)
2084e1dd0a2fSth160488 continue;
2085e1dd0a2fSth160488 s = chg->servers[i];
2086e1dd0a2fSth160488
2087e1dd0a2fSth160488 /*
2088e1dd0a2fSth160488 * look for a CONNECTED MT connection which uses
2089e1dd0a2fSth160488 * a server less preferred than s, and treat it
2090e1dd0a2fSth160488 * as 'fallback needed' by calling
2091e1dd0a2fSth160488 * close_conn_mt_when_nouser()
2092e1dd0a2fSth160488 */
2093e1dd0a2fSth160488 k = -1;
2094e1dd0a2fSth160488 loop = B_TRUE;
2095e1dd0a2fSth160488 while (loop) {
2096e1dd0a2fSth160488 if (cmg_locked == B_FALSE) {
2097e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
2098e1dd0a2fSth160488 cmg_locked = B_TRUE;
2099e1dd0a2fSth160488 }
2100e1dd0a2fSth160488
2101e1dd0a2fSth160488 /* Is s a preferred server ? */
2102e1dd0a2fSth160488 if (k == -1) {
2103e1dd0a2fSth160488 for (j = 0; cmg->pservers[j] != NULL; j++) {
2104e1dd0a2fSth160488 if (strcasecmp(cmg->pservers[j],
2105e1dd0a2fSth160488 s) == 0) {
2106e1dd0a2fSth160488 k = j;
2107e1dd0a2fSth160488 break;
2108e1dd0a2fSth160488 }
2109e1dd0a2fSth160488 }
2110e1dd0a2fSth160488 }
2111e1dd0a2fSth160488 /* skip s if not a preferred server */
2112e1dd0a2fSth160488 if (k == -1) {
2113e1dd0a2fSth160488 break;
2114e1dd0a2fSth160488 }
2115e1dd0a2fSth160488
2116e1dd0a2fSth160488 /* check each MT connection */
2117e1dd0a2fSth160488 for (cm = cmg->cm_head; cm; cm = cm->next) {
2118e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
2119e1dd0a2fSth160488 /*
2120e1dd0a2fSth160488 * Find an MT connection that is connected and
2121e1dd0a2fSth160488 * not marked, but leave WRITE or REFERRAL
2122e1dd0a2fSth160488 * connections alone, since fallback does not
2123e1dd0a2fSth160488 * make sense for them.
2124e1dd0a2fSth160488 */
2125e1dd0a2fSth160488 if (cm->state == NS_CONN_MT_CONNECTED &&
2126e1dd0a2fSth160488 cm->close_when_nouser == B_FALSE &&
2127e1dd0a2fSth160488 cm->conn != NULL && cm->opened_for !=
2128e1dd0a2fSth160488 NS_CONN_USER_WRITE &&
2129e1dd0a2fSth160488 cm->referral == B_FALSE) {
2130e1dd0a2fSth160488 n = -1;
2131e1dd0a2fSth160488 /*
2132e1dd0a2fSth160488 * j < k ??? should we close
2133e1dd0a2fSth160488 * an active MT that is using s ?
2134e1dd0a2fSth160488 * ie could s went down and up
2135e1dd0a2fSth160488 * again, but cm is bound prior to
2136e1dd0a2fSth160488 * the down ? Play safe here,
2137e1dd0a2fSth160488 * and check j <= k.
2138e1dd0a2fSth160488 */
2139e1dd0a2fSth160488 for (j = 0; j <= k; j++) {
2140e1dd0a2fSth160488 if (strcasecmp(
2141e1dd0a2fSth160488 cm->conn->serverAddr,
2142e1dd0a2fSth160488 cmg->pservers[j]) == 0) {
2143e1dd0a2fSth160488 n = j;
2144e1dd0a2fSth160488 break;
2145e1dd0a2fSth160488 }
2146e1dd0a2fSth160488 }
2147e1dd0a2fSth160488 /*
2148e1dd0a2fSth160488 * s is preferred, if its location
2149e1dd0a2fSth160488 * in the preferred server list is
2150e1dd0a2fSth160488 * ahead of that of the server
2151e1dd0a2fSth160488 * used by the cm (i.e., no match
2152e1dd0a2fSth160488 * found before s)
2153e1dd0a2fSth160488 */
2154e1dd0a2fSth160488 if (n == -1) { /* s is preferred */
2155e1dd0a2fSth160488 int fr = 0;
2156e1dd0a2fSth160488 fr = close_conn_mt_when_nouser(
2157e1dd0a2fSth160488 cm);
2158e1dd0a2fSth160488 NS_CONN_UNLOCK_AND_FREE(fr,
2159e1dd0a2fSth160488 cm, cmg);
2160e1dd0a2fSth160488 cmg_locked = B_FALSE;
2161e1dd0a2fSth160488 /*
2162e1dd0a2fSth160488 * break, not continue,
2163e1dd0a2fSth160488 * because we need to
2164e1dd0a2fSth160488 * check the entire cm
2165e1dd0a2fSth160488 * list again. The call
2166e1dd0a2fSth160488 * above may change the
2167e1dd0a2fSth160488 * cm list.
2168e1dd0a2fSth160488 */
2169e1dd0a2fSth160488 break;
2170e1dd0a2fSth160488 }
2171e1dd0a2fSth160488 }
2172e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
2173e1dd0a2fSth160488 }
2174e1dd0a2fSth160488 /* if no (more) cm using s, check next server */
2175e1dd0a2fSth160488 if (cm == NULL)
2176e1dd0a2fSth160488 loop = B_FALSE;
2177e1dd0a2fSth160488 } /* while loop */
2178e1dd0a2fSth160488 }
2179e1dd0a2fSth160488 if (cmg_locked == B_TRUE)
2180e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
2181e1dd0a2fSth160488 return (cmg);
2182e1dd0a2fSth160488 }
2183e1dd0a2fSth160488
2184e1dd0a2fSth160488 /* Shut down all MT connection managed by the connection management */
2185e1dd0a2fSth160488 void
shutdown_all_conn_mt(ns_conn_mgmt_t * cmg)2186e1dd0a2fSth160488 shutdown_all_conn_mt(ns_conn_mgmt_t *cmg)
2187e1dd0a2fSth160488 {
2188e1dd0a2fSth160488 ns_ldap_error_t *ep;
2189e1dd0a2fSth160488 ns_conn_mt_t *cm;
2190e1dd0a2fSth160488 int free_cm = 0;
2191e1dd0a2fSth160488 boolean_t done = B_FALSE;
2192e1dd0a2fSth160488
2193e1dd0a2fSth160488 ep = (ns_ldap_error_t *)calloc(1, sizeof (*ep));
2194e1dd0a2fSth160488 if (ep != NULL) { /* if NULL, not a problem */
2195e1dd0a2fSth160488 /* OK if returns NULL */
2196e1dd0a2fSth160488 ep->message = strdup(NS_CONN_MSG_SHUTDOWN_RELOADED);
2197e1dd0a2fSth160488 }
2198e1dd0a2fSth160488
2199e1dd0a2fSth160488 (void) mutex_lock(&cmg->lock);
2200e1dd0a2fSth160488 while (cmg->cm_head != NULL && done == B_FALSE) {
2201e1dd0a2fSth160488 for (cm = cmg->cm_head; cm; cm = cm->next) {
2202e1dd0a2fSth160488 (void) mutex_lock(&cm->lock);
2203e1dd0a2fSth160488 if (cm->next == NULL)
2204e1dd0a2fSth160488 done = B_TRUE;
2205e1dd0a2fSth160488 /* shut down each conn_mt, ignore errors */
2206e1dd0a2fSth160488 free_cm = close_conn_mt(cm, LDAP_OTHER, &ep, NULL);
2207e1dd0a2fSth160488 (void) mutex_unlock(&cm->lock);
2208e1dd0a2fSth160488 if (free_cm == 1) {
2209e1dd0a2fSth160488 (void) free_conn_mt(cm, 0);
2210e1dd0a2fSth160488 /*
2211e1dd0a2fSth160488 * conn_mt may change, so start from
2212e1dd0a2fSth160488 * top of list again
2213e1dd0a2fSth160488 */
2214e1dd0a2fSth160488 break;
2215e1dd0a2fSth160488 }
2216e1dd0a2fSth160488 }
2217e1dd0a2fSth160488 }
2218e1dd0a2fSth160488 (void) mutex_unlock(&cmg->lock);
2219e1dd0a2fSth160488 (void) __ns_ldap_freeError(&ep);
2220e1dd0a2fSth160488 }
2221e1dd0a2fSth160488
2222e1dd0a2fSth160488 /* free all the resources used by the connection management */
2223e1dd0a2fSth160488 void
__s_api_shutdown_conn_mgmt()2224e1dd0a2fSth160488 __s_api_shutdown_conn_mgmt()
2225e1dd0a2fSth160488 {
2226e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
2227e1dd0a2fSth160488
2228e1dd0a2fSth160488 cmg = access_conn_mgmt(NS_CONN_MGMT_OP_SHUTDOWN);
2229e1dd0a2fSth160488 if (cmg == NULL) /* already being SHUT done */
2230e1dd0a2fSth160488 return;
2231e1dd0a2fSth160488
2232e1dd0a2fSth160488 (void) shutdown_all_conn_mt(cmg);
2233e1dd0a2fSth160488 (void) release_conn_mgmt(cmg, B_FALSE);
2234e1dd0a2fSth160488
2235e1dd0a2fSth160488 /* then destroy the conn_mgmt */
2236e1dd0a2fSth160488 (void) release_conn_mgmt(cmg, B_FALSE);
2237e1dd0a2fSth160488 }
2238e1dd0a2fSth160488
2239e1dd0a2fSth160488
2240e1dd0a2fSth160488 /*
2241ca190d8dSmichen * Reinitialize the libsldap connection management after
2242ca190d8dSmichen * a new native LDAP configuration is received.
2243e1dd0a2fSth160488 */
2244e1dd0a2fSth160488 void
__s_api_reinit_conn_mgmt_new_config(ns_config_t * new_cfg)2245e1dd0a2fSth160488 __s_api_reinit_conn_mgmt_new_config(ns_config_t *new_cfg)
2246e1dd0a2fSth160488 {
2247e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
2248e1dd0a2fSth160488 ns_conn_mgmt_t *ocmg;
2249e1dd0a2fSth160488
2250e1dd0a2fSth160488 cmg = access_conn_mgmt(NS_CONN_MGMT_OP_REF);
2251e1dd0a2fSth160488 if (cmg == NULL)
2252e1dd0a2fSth160488 return;
2253e1dd0a2fSth160488 if (cmg->config == new_cfg || cmg->state == NS_CONN_MGMT_DETACHED) {
2254e1dd0a2fSth160488 (void) release_conn_mgmt(cmg, B_FALSE);
2255e1dd0a2fSth160488 return;
2256e1dd0a2fSth160488 }
2257e1dd0a2fSth160488
2258e1dd0a2fSth160488 /* reload the conn_mgmt and native LDAP config */
2259e1dd0a2fSth160488 ocmg = access_conn_mgmt(NS_CONN_MGMT_OP_NEW_CONFIG);
2260e1dd0a2fSth160488 if (ocmg == cmg)
2261e1dd0a2fSth160488 shutdown_all_conn_mt(ocmg);
2262e1dd0a2fSth160488 /* release the one obtained from access_conn_mgmt(RELOAD) */
2263e1dd0a2fSth160488 (void) release_conn_mgmt(ocmg, B_FALSE);
2264e1dd0a2fSth160488 /* release the one obtained when ocmg was created */
2265e1dd0a2fSth160488 (void) release_conn_mgmt(ocmg, B_FALSE);
2266e1dd0a2fSth160488 /* release the one obtained when this function is entered */
2267e1dd0a2fSth160488 (void) release_conn_mgmt(cmg, B_FALSE);
2268e1dd0a2fSth160488 }
2269e1dd0a2fSth160488
2270e1dd0a2fSth160488 /*
2271e1dd0a2fSth160488 * Prepare to retry ldap search operation if needed.
2272e1dd0a2fSth160488 * Return 1 if retry is needed, otherwise 0.
2273e1dd0a2fSth160488 * If first time in, return 1. If not, return 1 if:
2274e1dd0a2fSth160488 * - not a NS_CONN_USER_GETENT conn_user AND
2275e1dd0a2fSth160488 * - have not retried 3 times yet AND
2276e1dd0a2fSth160488 * - previous search failed AND
2277e1dd0a2fSth160488 * - the retry flag is set in the ns_conn_user_t or config was reloaded
2278e1dd0a2fSth160488 */
2279e1dd0a2fSth160488 int
__s_api_setup_retry_search(ns_conn_user_t ** conn_user,ns_conn_user_type_t type,int * try_cnt,int * rc,ns_ldap_error_t ** errorp)2280e1dd0a2fSth160488 __s_api_setup_retry_search(ns_conn_user_t **conn_user,
2281e1dd0a2fSth160488 ns_conn_user_type_t type, int *try_cnt, int *rc,
2282e1dd0a2fSth160488 ns_ldap_error_t **errorp)
2283e1dd0a2fSth160488 {
2284e1dd0a2fSth160488 boolean_t retry;
2285e1dd0a2fSth160488 ns_conn_user_t *cu = *conn_user;
2286e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
2287e1dd0a2fSth160488
2288e1dd0a2fSth160488 if (*try_cnt > 0 && cu != NULL) {
2289e1dd0a2fSth160488 /*
2290e1dd0a2fSth160488 * if called from firstEntry(), keep conn_mt for
2291e1dd0a2fSth160488 * the subsequent getnext requests
2292e1dd0a2fSth160488 */
2293e1dd0a2fSth160488 if (cu->type == NS_CONN_USER_GETENT && *rc == NS_LDAP_SUCCESS)
2294e1dd0a2fSth160488 return (0);
2295e1dd0a2fSth160488 cmg = cu->conn_mgmt;
2296e1dd0a2fSth160488 retry = cu->retry;
2297e1dd0a2fSth160488 if (cu->conn_mt != NULL)
2298e1dd0a2fSth160488 __s_api_conn_mt_return(cu);
2299e1dd0a2fSth160488 if (cmg != NULL && cmg->cfg_reloaded == B_TRUE)
2300e1dd0a2fSth160488 retry = B_TRUE;
2301e1dd0a2fSth160488 __s_api_conn_user_free(cu);
2302e1dd0a2fSth160488 *conn_user = NULL;
2303e1dd0a2fSth160488
2304e1dd0a2fSth160488 if (*rc == NS_LDAP_SUCCESS || retry != B_TRUE)
2305e1dd0a2fSth160488 return (0);
2306e1dd0a2fSth160488 }
2307e1dd0a2fSth160488
2308e1dd0a2fSth160488 *try_cnt = *try_cnt + 1;
2309e1dd0a2fSth160488 if (*try_cnt > NS_LIST_TRY_MAX)
2310e1dd0a2fSth160488 return (0);
2311e1dd0a2fSth160488
2312e1dd0a2fSth160488 *conn_user = __s_api_conn_user_init(type, NULL, B_FALSE);
2313e1dd0a2fSth160488 if (*conn_user == NULL) {
2314e1dd0a2fSth160488 if (*try_cnt == 1) { /* first call before any retry */
2315e1dd0a2fSth160488 *rc = NS_LDAP_MEMORY;
2316e1dd0a2fSth160488 *errorp = NULL;
2317e1dd0a2fSth160488 }
2318e1dd0a2fSth160488 /* for 1+ try, use previous rc and errorp */
2319e1dd0a2fSth160488 return (0);
2320e1dd0a2fSth160488 }
2321e1dd0a2fSth160488
2322e1dd0a2fSth160488 /* free ldap_error_t from previous search */
2323e1dd0a2fSth160488 if (*try_cnt > 1 && rc != NS_LDAP_SUCCESS && *errorp != NULL)
2324e1dd0a2fSth160488 (void) __ns_ldap_freeError(errorp);
2325e1dd0a2fSth160488
2326e1dd0a2fSth160488 return (1);
2327e1dd0a2fSth160488 }
2328e1dd0a2fSth160488
2329e1dd0a2fSth160488 /* prepare to get the next entry for an enumeration */
2330e1dd0a2fSth160488 int
__s_api_setup_getnext(ns_conn_user_t * cu,int * ns_err,ns_ldap_error_t ** errorp)2331e1dd0a2fSth160488 __s_api_setup_getnext(ns_conn_user_t *cu, int *ns_err,
2332e1dd0a2fSth160488 ns_ldap_error_t **errorp)
2333e1dd0a2fSth160488 {
2334e1dd0a2fSth160488 int rc;
2335e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
2336e1dd0a2fSth160488
2337e1dd0a2fSth160488 /*
2338e1dd0a2fSth160488 * if using an MT connection, ensure the thread-specific data are set,
2339e1dd0a2fSth160488 * but if the MT connection is no longer good, return the error saved.
2340e1dd0a2fSth160488 */
2341e1dd0a2fSth160488 if (cu->conn_mt != NULL && (cmg = cu->conn_mgmt) != NULL) {
2342e1dd0a2fSth160488
2343e1dd0a2fSth160488 if (cu->bad_mt_conn == B_TRUE) {
2344e1dd0a2fSth160488 __s_api_conn_mt_close(cu, 0, NULL);
2345e1dd0a2fSth160488 *ns_err = cu->ns_rc;
2346e1dd0a2fSth160488 *errorp = cu->ns_error;
2347e1dd0a2fSth160488 cu->ns_error = NULL;
2348e1dd0a2fSth160488 return (*ns_err);
2349e1dd0a2fSth160488 }
2350e1dd0a2fSth160488
2351e1dd0a2fSth160488 rc = conn_tsd_check(cmg);
2352e1dd0a2fSth160488 if (rc != NS_LDAP_SUCCESS) {
2353e1dd0a2fSth160488 *errorp = NULL;
2354e1dd0a2fSth160488 return (rc);
2355e1dd0a2fSth160488 }
2356e1dd0a2fSth160488 }
2357e1dd0a2fSth160488
2358e1dd0a2fSth160488 return (NS_LDAP_SUCCESS);
2359e1dd0a2fSth160488 }
2360e1dd0a2fSth160488
2361e1dd0a2fSth160488 /* wait for an MT connection to become available */
2362e1dd0a2fSth160488 static int
conn_wait(ns_conn_mt_t * conn_mt,ns_conn_user_t * conn_user)2363e1dd0a2fSth160488 conn_wait(ns_conn_mt_t *conn_mt, ns_conn_user_t *conn_user)
2364e1dd0a2fSth160488 {
2365e1dd0a2fSth160488 ns_conn_waiter_t mywait;
2366e1dd0a2fSth160488 ns_conn_waiter_t *head = &conn_mt->waiter;
2367e1dd0a2fSth160488
2368e1dd0a2fSth160488 (void) cond_init(&(mywait.waitcv), USYNC_THREAD, 0);
2369e1dd0a2fSth160488 mywait.key = conn_user;
2370e1dd0a2fSth160488 mywait.signaled = 0;
2371e1dd0a2fSth160488 mywait.next = head->next;
2372e1dd0a2fSth160488 mywait.prev = head;
2373e1dd0a2fSth160488 if (mywait.next)
2374e1dd0a2fSth160488 mywait.next->prev = &mywait;
2375e1dd0a2fSth160488 head->next = &mywait;
2376e1dd0a2fSth160488 atomic_inc_uint(&conn_mt->waiter_cnt);
2377e1dd0a2fSth160488
2378e1dd0a2fSth160488 while (!mywait.signaled)
2379e1dd0a2fSth160488 (void) cond_wait(&(mywait.waitcv), &conn_mt->lock);
2380e1dd0a2fSth160488 if (mywait.prev)
2381e1dd0a2fSth160488 mywait.prev->next = mywait.next;
2382e1dd0a2fSth160488 if (mywait.next)
2383e1dd0a2fSth160488 mywait.next->prev = mywait.prev;
2384e1dd0a2fSth160488 return (0);
2385e1dd0a2fSth160488 }
2386e1dd0a2fSth160488
2387e1dd0a2fSth160488 /* signal that an MT connection is now available */
2388e1dd0a2fSth160488 static int
conn_signal(ns_conn_mt_t * conn_mt)2389e1dd0a2fSth160488 conn_signal(ns_conn_mt_t *conn_mt)
2390e1dd0a2fSth160488 {
2391e1dd0a2fSth160488 int c = 0;
2392e1dd0a2fSth160488 ns_conn_waiter_t *head = &conn_mt->waiter;
2393e1dd0a2fSth160488 ns_conn_waiter_t *tmp = head->next;
2394e1dd0a2fSth160488
2395e1dd0a2fSth160488 while (tmp) {
2396e1dd0a2fSth160488 (void) cond_signal(&(tmp->waitcv));
2397e1dd0a2fSth160488 tmp->signaled = 1;
2398e1dd0a2fSth160488 atomic_dec_uint(&conn_mt->waiter_cnt);
2399e1dd0a2fSth160488 c++;
2400e1dd0a2fSth160488 tmp = tmp->next;
2401e1dd0a2fSth160488 }
2402e1dd0a2fSth160488
2403e1dd0a2fSth160488 return (c);
2404e1dd0a2fSth160488 }
2405e1dd0a2fSth160488
2406e1dd0a2fSth160488 /*
2407e1dd0a2fSth160488 * wait and process the server status and/or config change notification
2408e1dd0a2fSth160488 * from ldap_cachemgr
2409e1dd0a2fSth160488 */
2410e1dd0a2fSth160488 static void *
get_server_change(void * arg)2411e1dd0a2fSth160488 get_server_change(void *arg)
2412e1dd0a2fSth160488 {
2413e1dd0a2fSth160488 union {
2414e1dd0a2fSth160488 ldap_data_t s_d;
2415e1dd0a2fSth160488 char s_b[DOORBUFFERSIZE];
2416e1dd0a2fSth160488 } space;
2417e1dd0a2fSth160488 ldap_data_t *sptr = &space.s_d;
2418e1dd0a2fSth160488 int ndata;
2419e1dd0a2fSth160488 int adata;
2420e1dd0a2fSth160488 char *ptr;
2421e1dd0a2fSth160488 int ds_cnt;
2422e1dd0a2fSth160488 int door_rc;
2423e1dd0a2fSth160488 int which;
2424e1dd0a2fSth160488 int retry = 0;
2425e1dd0a2fSth160488 boolean_t loop = B_TRUE;
2426e1dd0a2fSth160488 char *c, *oc;
2427e1dd0a2fSth160488 int dslen = strlen(DOORLINESEP);
2428e1dd0a2fSth160488 char dsep = DOORLINESEP_CHR;
2429e1dd0a2fSth160488 char chg_data[DOORBUFFERSIZE];
2430e1dd0a2fSth160488 char **servers = NULL;
2431e1dd0a2fSth160488 boolean_t getchg_not_supported = B_FALSE;
2432e1dd0a2fSth160488 ns_conn_mgmt_t *ocmg = (ns_conn_mgmt_t *)arg;
2433e1dd0a2fSth160488 ns_conn_mgmt_t *cmg;
2434e1dd0a2fSth160488 ns_server_status_t *status = NULL;
2435e1dd0a2fSth160488 ns_server_status_change_t chg = { 0 };
2436e1dd0a2fSth160488 ldap_get_change_out_t *get_chg;
2437e1dd0a2fSth160488 ldap_get_chg_cookie_t cookie;
2438e1dd0a2fSth160488 ldap_get_chg_cookie_t new_cookie;
2439e1dd0a2fSth160488
2440e1dd0a2fSth160488 cmg = access_conn_mgmt(NS_CONN_MGMT_OP_REF);
2441e1dd0a2fSth160488 if (cmg != ocmg)
2442e1dd0a2fSth160488 thr_exit(NULL);
2443e1dd0a2fSth160488 /* cmg is locked before called */
2444e1dd0a2fSth160488 cmg->procchg_tid = thr_self();
2445e1dd0a2fSth160488
2446e1dd0a2fSth160488 /* make sure the thread specific data are set */
2447e1dd0a2fSth160488 (void) conn_tsd_setup(cmg);
2448e1dd0a2fSth160488 cookie = cmg->cfg_cookie;
2449e1dd0a2fSth160488
2450e1dd0a2fSth160488 while (loop) {
2451e1dd0a2fSth160488
2452e1dd0a2fSth160488 if (chg.servers != NULL)
2453e1dd0a2fSth160488 free(chg.servers);
2454e1dd0a2fSth160488 if (chg.changes != NULL)
2455e1dd0a2fSth160488 free(chg.changes);
2456e1dd0a2fSth160488 if (sptr != &space.s_d)
2457e1dd0a2fSth160488 (void) munmap((char *)sptr, sizeof (space));
2458e1dd0a2fSth160488
2459e1dd0a2fSth160488 /*
2460e1dd0a2fSth160488 * If the attached conn_mgmt has been deleted,
2461e1dd0a2fSth160488 * then exit. The new conn_mgmt will starts it
2462e1dd0a2fSth160488 * own monitor thread later. If libsldap is being
2463e1dd0a2fSth160488 * unloaded or configuration reloaded, OR
2464e1dd0a2fSth160488 * ldap_cachemgr rejected the GETSTATUSCHANGE door
2465e1dd0a2fSth160488 * call, then exit as well.
2466e1dd0a2fSth160488 */
2467e1dd0a2fSth160488 if (cmg == NULL || cmg->state == NS_CONN_MGMT_DETACHED ||
2468e1dd0a2fSth160488 getchg_not_supported == B_TRUE) {
2469e1dd0a2fSth160488
2470e1dd0a2fSth160488 if (cmg != NULL) {
2471e1dd0a2fSth160488 cmg->procchg_started = B_FALSE;
2472e1dd0a2fSth160488 (void) release_conn_mgmt(cmg, B_FALSE);
2473e1dd0a2fSth160488 }
2474e1dd0a2fSth160488
2475e1dd0a2fSth160488 conn_tsd_free();
2476e1dd0a2fSth160488 thr_exit(NULL);
2477e1dd0a2fSth160488 }
2478e1dd0a2fSth160488
2479e1dd0a2fSth160488 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
2480e1dd0a2fSth160488 (void) memset(&chg, 0, sizeof (chg));
2481e1dd0a2fSth160488 adata = sizeof (ldap_call_t) + 1;
2482e1dd0a2fSth160488 ndata = sizeof (space);
2483e1dd0a2fSth160488 space.s_d.ldap_call.ldap_callnumber = GETSTATUSCHANGE;
2484e1dd0a2fSth160488 space.s_d.ldap_call.ldap_u.get_change.op =
2485e1dd0a2fSth160488 NS_STATUS_CHANGE_OP_START;
2486e1dd0a2fSth160488 space.s_d.ldap_call.ldap_u.get_change.cookie = cookie;
2487e1dd0a2fSth160488 sptr = &space.s_d;
2488e1dd0a2fSth160488 door_rc = __ns_ldap_trydoorcall_getfd();
2489e1dd0a2fSth160488 cmg->procchg_door_call = B_TRUE;
2490e1dd0a2fSth160488 if (release_conn_mgmt(cmg, B_FALSE) == NULL) {
2491e1dd0a2fSth160488 conn_tsd_free();
2492e1dd0a2fSth160488 thr_exit(NULL);
2493e1dd0a2fSth160488 }
2494e1dd0a2fSth160488
2495e1dd0a2fSth160488 if (door_rc == NS_CACHE_SUCCESS)
2496e1dd0a2fSth160488 door_rc = __ns_ldap_trydoorcall_send(&sptr, &ndata,
2497e1dd0a2fSth160488 &adata);
2498e1dd0a2fSth160488
2499e1dd0a2fSth160488 /*
2500e1dd0a2fSth160488 * Check and see if the conn_mgmt is still current.
2501e1dd0a2fSth160488 * If not, no need to continue.
2502e1dd0a2fSth160488 */
2503e1dd0a2fSth160488 cmg = access_conn_mgmt(NS_CONN_MGMT_OP_REF);
2504e1dd0a2fSth160488 if (cmg != NULL)
2505e1dd0a2fSth160488 cmg->procchg_door_call = B_FALSE;
2506e1dd0a2fSth160488 if (cmg != ocmg) {
2507e1dd0a2fSth160488 if (cmg != NULL) {
2508e1dd0a2fSth160488 cmg->procchg_started = B_FALSE;
2509e1dd0a2fSth160488 (void) release_conn_mgmt(cmg, B_FALSE);
2510e1dd0a2fSth160488 }
2511e1dd0a2fSth160488 conn_tsd_free();
2512e1dd0a2fSth160488 thr_exit(NULL);
2513e1dd0a2fSth160488 }
2514e1dd0a2fSth160488
2515e1dd0a2fSth160488 if (door_rc != NS_CACHE_SUCCESS) {
2516e1dd0a2fSth160488 if (door_rc == NS_CACHE_NOSERVER) {
2517e1dd0a2fSth160488 if (retry++ > 10)
2518e1dd0a2fSth160488 getchg_not_supported = B_TRUE;
2519e1dd0a2fSth160488 else {
2520e1dd0a2fSth160488 /*
2521e1dd0a2fSth160488 * ldap_cachemgr may be down, give
2522e1dd0a2fSth160488 * it time to restart
2523e1dd0a2fSth160488 */
2524e1dd0a2fSth160488 (void) sleep(2);
2525e1dd0a2fSth160488 }
2526e1dd0a2fSth160488 } else if (door_rc == NS_CACHE_NOTFOUND)
2527e1dd0a2fSth160488 getchg_not_supported = B_TRUE;
2528e1dd0a2fSth160488 continue;
2529e1dd0a2fSth160488 } else
2530e1dd0a2fSth160488 retry = 0;
2531e1dd0a2fSth160488
2532e1dd0a2fSth160488 /* copy info from door call return structure */
2533e1dd0a2fSth160488 get_chg = &sptr->ldap_ret.ldap_u.changes;
2534e1dd0a2fSth160488 ptr = get_chg->data;
2535e1dd0a2fSth160488 /* configuration change ? */
2536e1dd0a2fSth160488 if (get_chg->type == NS_STATUS_CHANGE_TYPE_CONFIG) {
2537e1dd0a2fSth160488 chg.config_changed = B_TRUE;
2538e1dd0a2fSth160488 cmg = proc_server_change(&chg, cmg);
2539e1dd0a2fSth160488 continue;
2540e1dd0a2fSth160488 }
2541e1dd0a2fSth160488
2542e1dd0a2fSth160488 /* server status changes ? */
2543e1dd0a2fSth160488 if (get_chg->type == NS_STATUS_CHANGE_TYPE_SERVER) {
2544e1dd0a2fSth160488 /*
2545e1dd0a2fSth160488 * first check cookies, if don't match, config
2546e1dd0a2fSth160488 * has changed
2547e1dd0a2fSth160488 */
2548e1dd0a2fSth160488 new_cookie = get_chg->cookie;
2549e1dd0a2fSth160488 if (new_cookie.mgr_pid != cookie.mgr_pid ||
2550e1dd0a2fSth160488 new_cookie.seq_num != cookie.seq_num) {
2551e1dd0a2fSth160488 chg.config_changed = B_TRUE;
2552e1dd0a2fSth160488 cmg = proc_server_change(&chg, cmg);
2553e1dd0a2fSth160488 continue;
2554e1dd0a2fSth160488 }
2555e1dd0a2fSth160488
2556e1dd0a2fSth160488 (void) strlcpy(chg_data, ptr, sizeof (chg_data));
2557e1dd0a2fSth160488 chg.num_server = get_chg->server_count;
2558e1dd0a2fSth160488
2559e1dd0a2fSth160488 servers = (char **)calloc(chg.num_server,
2560e1dd0a2fSth160488 sizeof (char *));
2561e1dd0a2fSth160488 if (servers == NULL) {
2562e1dd0a2fSth160488 syslog(LOG_INFO, NS_CONN_MSG_MEMORY_ERROR);
2563e1dd0a2fSth160488 continue;
2564e1dd0a2fSth160488 }
2565e1dd0a2fSth160488 status = (ns_server_status_t *)calloc(chg.num_server,
2566e1dd0a2fSth160488 sizeof (int));
2567e1dd0a2fSth160488 if (status == NULL) {
2568e1dd0a2fSth160488 syslog(LOG_INFO, NS_CONN_MSG_MEMORY_ERROR);
2569e1dd0a2fSth160488 free(servers);
2570e1dd0a2fSth160488 continue;
2571e1dd0a2fSth160488 }
2572e1dd0a2fSth160488 ds_cnt = 0;
2573e1dd0a2fSth160488 which = 0;
2574e1dd0a2fSth160488 oc = ptr;
2575e1dd0a2fSth160488 for (c = ptr; which != 2; c++) {
2576e1dd0a2fSth160488 /* look for DOORLINESEP or end of string */
2577e1dd0a2fSth160488 if (*c != dsep && *c != '\0')
2578e1dd0a2fSth160488 continue;
2579e1dd0a2fSth160488 if (*c == dsep) { /* DOORLINESEP */
2580e1dd0a2fSth160488 *c = '\0'; /* current value */
2581e1dd0a2fSth160488 c += dslen; /* skip to next value */
2582e1dd0a2fSth160488 }
2583e1dd0a2fSth160488 if (which == 0) { /* get server info */
2584e1dd0a2fSth160488 servers[ds_cnt] = oc;
2585e1dd0a2fSth160488 oc = c;
2586e1dd0a2fSth160488 which = 1; /* get status next */
2587e1dd0a2fSth160488 continue;
2588e1dd0a2fSth160488 }
2589e1dd0a2fSth160488 /* which == 1, get up/down status */
2590e1dd0a2fSth160488 if (strcmp(NS_SERVER_CHANGE_UP, oc) == 0) {
2591e1dd0a2fSth160488 status[ds_cnt] = NS_SERVER_UP;
2592e1dd0a2fSth160488 } else if (strcmp(NS_SERVER_CHANGE_DOWN,
2593e1dd0a2fSth160488 oc) == 0)
2594e1dd0a2fSth160488 status[ds_cnt] = NS_SERVER_DOWN;
2595e1dd0a2fSth160488 else {
2596e1dd0a2fSth160488 syslog(LOG_INFO,
2597e1dd0a2fSth160488 NS_CONN_MSG_BAD_CACHEMGR_DATA);
2598e1dd0a2fSth160488 continue;
2599e1dd0a2fSth160488 }
2600e1dd0a2fSth160488 oc = c;
2601e1dd0a2fSth160488 ds_cnt++;
2602e1dd0a2fSth160488 if (*c == '\0')
2603e1dd0a2fSth160488 which = 2; /* exit the loop */
2604e1dd0a2fSth160488 else
2605e1dd0a2fSth160488 which = 0; /* get server info next */
2606e1dd0a2fSth160488 }
2607e1dd0a2fSth160488 chg.servers = servers;
2608e1dd0a2fSth160488 chg.changes = status;
2609e1dd0a2fSth160488 cmg = proc_server_change(&chg, cmg);
2610e1dd0a2fSth160488 continue;
2611e1dd0a2fSth160488 }
2612e1dd0a2fSth160488 }
2613e1dd0a2fSth160488
2614e1dd0a2fSth160488 return (NULL);
2615e1dd0a2fSth160488 }
2616e1dd0a2fSth160488
2617e1dd0a2fSth160488 /* start the thread handling the change notification from ldap_cachemgr */
2618e1dd0a2fSth160488 static void
start_thread(ns_conn_mgmt_t * cmg)2619e1dd0a2fSth160488 start_thread(ns_conn_mgmt_t *cmg) {
2620e1dd0a2fSth160488
2621e1dd0a2fSth160488 int errnum;
2622e1dd0a2fSth160488
2623e1dd0a2fSth160488 /*
2624e1dd0a2fSth160488 * start a thread to get and process config and server status changes
2625e1dd0a2fSth160488 */
2626e1dd0a2fSth160488 if (thr_create(NULL, NULL, get_server_change,
2627e1dd0a2fSth160488 (void *)cmg, THR_DETACHED, NULL) != 0) {
2628e1dd0a2fSth160488 errnum = errno;
2629e1dd0a2fSth160488 syslog(LOG_WARNING, NS_CONN_MSG_NO_PROCCHG_THREAD,
2630e1dd0a2fSth160488 strerror(errnum));
2631e1dd0a2fSth160488 }
2632e1dd0a2fSth160488 }
2633