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 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 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 * 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 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 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 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 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 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 303e1dd0a2fSth160488 set_errno(int err) 304e1dd0a2fSth160488 { 305e1dd0a2fSth160488 errno = err; 306e1dd0a2fSth160488 } 307e1dd0a2fSth160488 308e1dd0a2fSth160488 /* Callback function for getting per thread errno */ 309e1dd0a2fSth160488 static int 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 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 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 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 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 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 * 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 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 * 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 * 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 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 * 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 * 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 * 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 * 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 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