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