10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51687Sjanga * Common Development and Distribution License (the "License"). 61687Sjanga * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 225840Smj162486 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <stdlib.h> 290Sstevel@tonic-gate #include <stdio.h> 300Sstevel@tonic-gate #include <errno.h> 310Sstevel@tonic-gate #include <string.h> 320Sstevel@tonic-gate #include <synch.h> 330Sstevel@tonic-gate #include <time.h> 340Sstevel@tonic-gate #include <libintl.h> 350Sstevel@tonic-gate #include <thread.h> 360Sstevel@tonic-gate #include <syslog.h> 370Sstevel@tonic-gate #include <sys/mman.h> 380Sstevel@tonic-gate #include <nsswitch.h> 390Sstevel@tonic-gate #include <nss_dbdefs.h> 400Sstevel@tonic-gate #include "solaris-priv.h" 412830Sdjl #include "solaris-int.h" 420Sstevel@tonic-gate #include "ns_sldap.h" 430Sstevel@tonic-gate #include "ns_internal.h" 440Sstevel@tonic-gate #include "ns_cache_door.h" 452333Sjanga #include "ldappr.h" 460Sstevel@tonic-gate #include <sys/stat.h> 470Sstevel@tonic-gate #include <fcntl.h> 480Sstevel@tonic-gate #include <procfs.h> 490Sstevel@tonic-gate #include <unistd.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate extern unsigned int _sleep(unsigned int); 520Sstevel@tonic-gate extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *, 530Sstevel@tonic-gate LDAPControl **, LDAPControl **); 540Sstevel@tonic-gate extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip); 550Sstevel@tonic-gate 560Sstevel@tonic-gate static int openConnection(LDAP **, const char *, const ns_cred_t *, 570Sstevel@tonic-gate int, ns_ldap_error_t **, int, int); 584048Schinlong static void 594048Schinlong _DropConnection(ConnectionID cID, int flag, int fini); 602830Sdjl /* 612830Sdjl * sessionLock, wait4session, sessionTid 622830Sdjl * are variables to synchronize the creation/retrieval of a connection. 632830Sdjl * MTperCon is a flag to enable/disable multiple threads sharing the same 642830Sdjl * connection. 652830Sdjl * sessionPoolLock is a mutex lock for the connection pool. 663387Schinlong * sharedConnNumber is the number of sharable connections in the pool. 673387Schinlong * sharedConnNumberLock is a mutex for sharedConnNumber. 682830Sdjl */ 692830Sdjl static mutex_t sessionLock = DEFAULTMUTEX; 702830Sdjl static int wait4session = 0; 712830Sdjl static thread_t sessionTid = 0; 722830Sdjl int MTperConn = 1; 732830Sdjl static rwlock_t sessionPoolLock = DEFAULTRWLOCK; 740Sstevel@tonic-gate 750Sstevel@tonic-gate static Connection **sessionPool = NULL; 760Sstevel@tonic-gate static int sessionPoolSize = 0; 773387Schinlong static int sharedConnNumber = 0; 783387Schinlong static mutex_t sharedConnNumberLock = DEFAULTMUTEX; 790Sstevel@tonic-gate 806072Smj162486 static int check_nscd_proc(pid_t pid, boolean_t check_uid); 810Sstevel@tonic-gate 822830Sdjl /* 832830Sdjl * SSF values are for SASL integrity & privacy. 842830Sdjl * JES DS5.2 does not support this feature but DS6 does. 852830Sdjl * The values between 0 and 65535 can work with both server versions. 862830Sdjl */ 872830Sdjl #define MAX_SASL_SSF 65535 882830Sdjl #define MIN_SASL_SSF 0 890Sstevel@tonic-gate 901687Sjanga /* Number of hostnames to allocate memory for */ 911687Sjanga #define NUMTOMALLOC 32 922830Sdjl /* 932830Sdjl * ns_mtckey is for sharing a ldap connection among multiple 942830Sdjl * threads; created by ns_ldap_init() in ns_init.c 952830Sdjl */ 962830Sdjl extern thread_key_t ns_mtckey; 971687Sjanga 982830Sdjl /* Per thread LDAP error resides in thread-specific data. */ 992830Sdjl struct ldap_error { 1002830Sdjl int le_errno; 1012830Sdjl char *le_matched; 1022830Sdjl char *le_errmsg; 1032830Sdjl }; 1042830Sdjl 1053428Smichen static struct ldap_error ldap_error_NULL = { LDAP_SUCCESS, NULL, NULL}; 1063428Smichen 1072830Sdjl /* destructor */ 1082830Sdjl void 1092830Sdjl ns_tsd_cleanup(void *key) { 1102830Sdjl struct ldap_error *le = (struct ldap_error *)key; 1112830Sdjl 1122830Sdjl if (le == NULL) 1132830Sdjl return; 1142830Sdjl if (le->le_matched != NULL) { 1152830Sdjl ldap_memfree(le->le_matched); 1162830Sdjl } 1172830Sdjl if (le->le_errmsg != NULL) { 1182830Sdjl ldap_memfree(le->le_errmsg); 1192830Sdjl } 1202830Sdjl free(le); 1212830Sdjl } 1222830Sdjl 1232830Sdjl /* Callback function for allocating a mutex */ 1242830Sdjl static void * 1252830Sdjl ns_mutex_alloc(void) 1262830Sdjl { 1272830Sdjl mutex_t *mutexp = NULL; 1282830Sdjl 1292830Sdjl if ((mutexp = malloc(sizeof (mutex_t))) != NULL) { 1302830Sdjl if (mutex_init(mutexp, USYNC_THREAD, NULL) != 0) { 1312830Sdjl free(mutexp); 1322830Sdjl mutexp = NULL; 1332830Sdjl } 1342830Sdjl } 1352830Sdjl return (mutexp); 1362830Sdjl } 1372830Sdjl 1382830Sdjl /* Callback function for freeing a mutex */ 1392830Sdjl static void 1402830Sdjl ns_mutex_free(void *mutexp) 1412830Sdjl { 1422830Sdjl (void) mutex_destroy((mutex_t *)mutexp); 1432830Sdjl free(mutexp); 1442830Sdjl } 1452830Sdjl 1462830Sdjl /* 1472830Sdjl * Function for setting up thread-specific data 1482830Sdjl * where per thread LDAP error is stored 1492830Sdjl */ 1502830Sdjl static int 1512830Sdjl tsd_setup() 1522830Sdjl { 1532830Sdjl void *tsd; 1542830Sdjl int rc; 1552830Sdjl 1562830Sdjl /* return success if TSD already set */ 1572830Sdjl rc = thr_getspecific(ns_mtckey, &tsd); 1582830Sdjl if (rc == 0 && tsd != NULL) 1592830Sdjl return (0); 1602830Sdjl 1612830Sdjl /* allocate and set TSD */ 1622830Sdjl tsd = (void *) calloc(1, sizeof (struct ldap_error)); 1632830Sdjl if (tsd == NULL) 1642830Sdjl return (-1); 1652830Sdjl rc = thr_setspecific(ns_mtckey, tsd); 1662830Sdjl if (rc != 0) { /* must be ENOMEM */ 1672830Sdjl free(tsd); 1682830Sdjl return (-1); 1692830Sdjl } 1702830Sdjl return (0); 1712830Sdjl 1722830Sdjl 1732830Sdjl } 1742830Sdjl 1752830Sdjl /* Callback function for setting the per thread LDAP error */ 1762830Sdjl /*ARGSUSED*/ 1772830Sdjl static void 1782830Sdjl set_ld_error(int err, char *matched, char *errmsg, void *dummy) 1792830Sdjl { 1802830Sdjl struct ldap_error *le; 1812830Sdjl 1822830Sdjl if (thr_getspecific(ns_mtckey, (void **)&le) != 0) { 1832830Sdjl syslog(LOG_ERR, "set_ld_error: thr_getspecific failed. errno" 1844522Schinlong " %d", errno); 1852830Sdjl return; 1862830Sdjl } 1873428Smichen 1883428Smichen /* play safe, do nothing if TSD pointer is NULL */ 1893428Smichen if (le == NULL) 1903428Smichen return; 1913428Smichen 1922830Sdjl le->le_errno = err; 1932830Sdjl if (le->le_matched != NULL) { 1942830Sdjl ldap_memfree(le->le_matched); 1952830Sdjl } 1962830Sdjl le->le_matched = matched; 1972830Sdjl if (le->le_errmsg != NULL) { 1982830Sdjl ldap_memfree(le->le_errmsg); 1992830Sdjl } 2002830Sdjl le->le_errmsg = errmsg; 2012830Sdjl } 2022830Sdjl 2033387Schinlong int 2043387Schinlong /* check and allocate the thread-specific data for using a shared connection */ 2053387Schinlong __s_api_check_MTC_tsd() 2063387Schinlong { 2073387Schinlong if (tsd_setup() != 0) 2083387Schinlong return (NS_LDAP_MEMORY); 2093387Schinlong 2103387Schinlong return (NS_LDAP_SUCCESS); 2113387Schinlong } 2123387Schinlong 2132830Sdjl /* Callback function for getting the per thread LDAP error */ 2142830Sdjl /*ARGSUSED*/ 2152830Sdjl static int 2162830Sdjl get_ld_error(char **matched, char **errmsg, void *dummy) 2172830Sdjl { 2182830Sdjl struct ldap_error *le; 2192830Sdjl 2202830Sdjl if (thr_getspecific(ns_mtckey, (void **)&le) != 0) { 2212830Sdjl syslog(LOG_ERR, "get_ld_error: thr_getspecific failed. errno" 2224522Schinlong " %d", errno); 2232830Sdjl return (errno); 2242830Sdjl } 2253428Smichen 2263428Smichen /* play safe, return NULL error data, if TSD pointer is NULL */ 2273428Smichen if (le == NULL) 2283428Smichen le = &ldap_error_NULL; 2293428Smichen 2302830Sdjl if (matched != NULL) { 2312830Sdjl *matched = le->le_matched; 2322830Sdjl } 2332830Sdjl if (errmsg != NULL) { 2342830Sdjl *errmsg = le->le_errmsg; 2352830Sdjl } 2362830Sdjl return (le->le_errno); 2372830Sdjl } 2382830Sdjl 2392830Sdjl /* Callback function for setting per thread errno */ 2402830Sdjl static void 2412830Sdjl set_errno(int err) 2422830Sdjl { 2432830Sdjl errno = err; 2442830Sdjl } 2452830Sdjl 2462830Sdjl /* Callback function for getting per thread errno */ 2472830Sdjl static int 2482830Sdjl get_errno(void) 2492830Sdjl { 2502830Sdjl return (errno); 2512830Sdjl } 2522830Sdjl 2532830Sdjl /* 2542830Sdjl * set up to allow multiple threads to use the same ldap connection 2552830Sdjl */ 2562830Sdjl static int 2572830Sdjl setup_mt_conn(LDAP *ld) 2582830Sdjl { 2592830Sdjl 2602830Sdjl struct ldap_thread_fns tfns; 2612830Sdjl struct ldap_extra_thread_fns extrafns; 2622830Sdjl int rc; 2632830Sdjl 2642830Sdjl /* 2652830Sdjl * Set the function pointers for dealing with mutexes 2662830Sdjl * and error information 2672830Sdjl */ 2682830Sdjl (void) memset(&tfns, '\0', sizeof (struct ldap_thread_fns)); 2692830Sdjl tfns.ltf_mutex_alloc = (void *(*)(void)) ns_mutex_alloc; 2702830Sdjl tfns.ltf_mutex_free = (void (*)(void *)) ns_mutex_free; 2712830Sdjl tfns.ltf_mutex_lock = (int (*)(void *)) mutex_lock; 2722830Sdjl tfns.ltf_mutex_unlock = (int (*)(void *)) mutex_unlock; 2732830Sdjl tfns.ltf_get_errno = get_errno; 2742830Sdjl tfns.ltf_set_errno = set_errno; 2752830Sdjl tfns.ltf_get_lderrno = get_ld_error; 2762830Sdjl tfns.ltf_set_lderrno = set_ld_error; 2772830Sdjl tfns.ltf_lderrno_arg = NULL; 2782830Sdjl 2792830Sdjl /* 2802830Sdjl * Set up this session to use those function pointers 2812830Sdjl */ 2822830Sdjl rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS, 2834522Schinlong (void *) &tfns); 2842830Sdjl if (rc < 0) { 2852830Sdjl syslog(LOG_WARNING, "libsldap: ldap_set_option " 2862830Sdjl "(LDAP_OPT_THREAD_FN_PTRS)"); 2872830Sdjl return (-1); 2882830Sdjl } 2892830Sdjl 2902830Sdjl /* 2912830Sdjl * Set the function pointers for working with semaphores 2922830Sdjl */ 2932830Sdjl (void) memset(&extrafns, '\0', 2944522Schinlong sizeof (struct ldap_extra_thread_fns)); 2952830Sdjl extrafns.ltf_threadid_fn = (void * (*)(void))thr_self; 2962830Sdjl extrafns.ltf_mutex_trylock = NULL; 2972830Sdjl extrafns.ltf_sema_alloc = NULL; 2982830Sdjl extrafns.ltf_sema_free = NULL; 2992830Sdjl extrafns.ltf_sema_wait = NULL; 3002830Sdjl extrafns.ltf_sema_post = NULL; 3012830Sdjl 3022830Sdjl /* Set up this session to use those function pointers */ 3032830Sdjl rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS, 3044522Schinlong (void *) &extrafns); 3052830Sdjl if (rc < 0) { 3062830Sdjl syslog(LOG_WARNING, "libsldap: ldap_set_option " 3072830Sdjl "(LDAP_OPT_EXTRA_THREAD_FN_PTRS)"); 3082830Sdjl return (-1); 3092830Sdjl } 3102830Sdjl 3112830Sdjl return (0); 3122830Sdjl } 3132830Sdjl 3142830Sdjl static void 3152830Sdjl ns_setup_mt_conn_and_tsd(LDAP *ld) { 3162830Sdjl thread_t t = thr_self(); 3172830Sdjl void *tsd; 3182830Sdjl /* set up to share this connection among threads */ 3192830Sdjl if (MTperConn == 1) { 3202830Sdjl if (tsd_setup() == -1) { 3212830Sdjl syslog(LOG_ERR, "tid= %d: unable " 3222830Sdjl "to set up TSD\n", t); 3232830Sdjl } else { 3242830Sdjl if (setup_mt_conn(ld) == -1) { 3252830Sdjl /* multiple threads per connection not supported */ 3262830Sdjl syslog(LOG_ERR, "tid= %d: multiple " 3272830Sdjl "threads per connection not " 3282830Sdjl "supported\n", t); 3292830Sdjl (void) thr_getspecific(ns_mtckey, &tsd); 3302830Sdjl ns_tsd_cleanup(tsd); 3312830Sdjl (void) thr_setspecific(ns_mtckey, NULL); 3322830Sdjl MTperConn = 0; 3332830Sdjl } 3342830Sdjl } 3352830Sdjl } 3362830Sdjl } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3396072Smj162486 * Check name and UID of process, if it is nscd. 3406072Smj162486 * 3416072Smj162486 * Input: 3426072Smj162486 * pid : PID of checked process 3436072Smj162486 * check_uid : check if UID == 0 3446072Smj162486 * Output: 3456072Smj162486 * 1 : nscd detected 3466072Smj162486 * 0 : nscd not confirmed 3476072Smj162486 */ 3486072Smj162486 static int 3496072Smj162486 check_nscd_proc(pid_t pid, boolean_t check_uid) 3506072Smj162486 { 3516072Smj162486 psinfo_t pinfo; 3526072Smj162486 char fname[MAXPATHLEN]; 3536072Smj162486 ssize_t ret; 3546072Smj162486 int fd; 3556072Smj162486 3566072Smj162486 if (snprintf(fname, MAXPATHLEN, "/proc/%d/psinfo", pid) > 0) { 3576072Smj162486 if ((fd = open(fname, O_RDONLY)) >= 0) { 3586072Smj162486 ret = read(fd, &pinfo, sizeof (psinfo_t)); 3596072Smj162486 (void) close(fd); 3606072Smj162486 if ((ret == sizeof (psinfo_t)) && 3616072Smj162486 (strcmp(pinfo.pr_fname, "nscd") == 0)) { 3626072Smj162486 if (check_uid && (pinfo.pr_uid != 0)) 3636072Smj162486 return (0); 3646072Smj162486 return (1); 3656072Smj162486 } 3666072Smj162486 } 3676072Smj162486 } 3686072Smj162486 return (0); 3696072Smj162486 } 3706072Smj162486 3716072Smj162486 /* 3726072Smj162486 * Check if this process is peruser nscd. 3736072Smj162486 */ 3746072Smj162486 int 3756072Smj162486 __s_api_peruser_proc(void) 3766072Smj162486 { 3776072Smj162486 pid_t my_ppid; 3786072Smj162486 static mutex_t nscdLock = DEFAULTMUTEX; 3796072Smj162486 static pid_t checkedPpid = (pid_t)-1; 3806072Smj162486 static int isPeruserNscd = 0; 3816072Smj162486 3826072Smj162486 my_ppid = getppid(); 3836072Smj162486 3846072Smj162486 /* 3856072Smj162486 * Already checked before for this process? If yes, return cached 3866072Smj162486 * response. 3876072Smj162486 */ 3886072Smj162486 if (my_ppid == checkedPpid) { 3896072Smj162486 return (isPeruserNscd); 3906072Smj162486 } 3916072Smj162486 3926072Smj162486 (void) mutex_lock(&nscdLock); 3936072Smj162486 3946072Smj162486 /* Check once more incase another thread has just complete this. */ 3956072Smj162486 if (my_ppid == checkedPpid) { 3966072Smj162486 (void) mutex_unlock(&nscdLock); 3976072Smj162486 return (isPeruserNscd); 3986072Smj162486 } 3996072Smj162486 4006072Smj162486 /* Reinitialize to be sure there is no residue after fork. */ 4016072Smj162486 isPeruserNscd = 0; 4026072Smj162486 4036072Smj162486 /* Am I the nscd process? */ 4046072Smj162486 if (check_nscd_proc(getpid(), B_FALSE)) { 4056072Smj162486 /* Is my parent the nscd process with UID == 0. */ 4066072Smj162486 isPeruserNscd = check_nscd_proc(my_ppid, B_TRUE); 4076072Smj162486 } 4086072Smj162486 4096072Smj162486 /* Remeber for whom isPeruserNscd is. */ 4106072Smj162486 checkedPpid = my_ppid; 4116072Smj162486 4126072Smj162486 (void) mutex_unlock(&nscdLock); 4136072Smj162486 return (isPeruserNscd); 4146072Smj162486 } 4156072Smj162486 4166072Smj162486 /* 4176072Smj162486 * Check if this process is main nscd. 4180Sstevel@tonic-gate */ 4195399Schinlong int 4205399Schinlong __s_api_nscd_proc(void) 4210Sstevel@tonic-gate { 4220Sstevel@tonic-gate pid_t my_pid; 4236072Smj162486 static mutex_t nscdLock = DEFAULTMUTEX; 4246072Smj162486 static pid_t checkedPid = (pid_t)-1; 4256072Smj162486 static int isMainNscd = 0; 4260Sstevel@tonic-gate 4276072Smj162486 /* 4286072Smj162486 * Don't bother checking if this process isn't root, this cannot 4296072Smj162486 * be main nscd. 4306072Smj162486 */ 4310Sstevel@tonic-gate if (getuid() != 0) 4320Sstevel@tonic-gate return (0); 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate my_pid = getpid(); 4356072Smj162486 4366072Smj162486 /* 4376072Smj162486 * Already checked before for this process? If yes, return cached 4386072Smj162486 * response. 4396072Smj162486 */ 4406072Smj162486 if (my_pid == checkedPid) { 4416072Smj162486 return (isMainNscd); 4420Sstevel@tonic-gate } 4436072Smj162486 4440Sstevel@tonic-gate (void) mutex_lock(&nscdLock); 4456072Smj162486 4466072Smj162486 /* Check once more incase another thread has just done this. */ 4476072Smj162486 if (my_pid == checkedPid) { 4480Sstevel@tonic-gate (void) mutex_unlock(&nscdLock); 4496072Smj162486 return (isMainNscd); 4500Sstevel@tonic-gate } 4516072Smj162486 4526072Smj162486 /* 4536072Smj162486 * Am I the nscd process? UID is already checked, not needed from 4546072Smj162486 * psinfo. 4556072Smj162486 */ 4566072Smj162486 isMainNscd = check_nscd_proc(my_pid, B_FALSE); 4576072Smj162486 4586072Smj162486 /* Remeber for whom isMainNscd is. */ 4590Sstevel@tonic-gate checkedPid = my_pid; 4606072Smj162486 4610Sstevel@tonic-gate (void) mutex_unlock(&nscdLock); 4626072Smj162486 return (isMainNscd); 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* 4660Sstevel@tonic-gate * This function requests a server from the cache manager through 4670Sstevel@tonic-gate * the door functionality 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate static int 4710Sstevel@tonic-gate __s_api_requestServer(const char *request, const char *server, 4722830Sdjl ns_server_info_t *ret, ns_ldap_error_t **error, const char *addrType) 4730Sstevel@tonic-gate { 4740Sstevel@tonic-gate union { 4750Sstevel@tonic-gate ldap_data_t s_d; 4760Sstevel@tonic-gate char s_b[DOORBUFFERSIZE]; 4770Sstevel@tonic-gate } space; 4780Sstevel@tonic-gate ldap_data_t *sptr; 4790Sstevel@tonic-gate int ndata; 4800Sstevel@tonic-gate int adata; 4810Sstevel@tonic-gate char errstr[MAXERROR]; 4820Sstevel@tonic-gate const char *ireq; 4830Sstevel@tonic-gate char *rbuf, *ptr, *rest; 4840Sstevel@tonic-gate char *dptr; 4850Sstevel@tonic-gate char **mptr, **mptr1, **cptr, **cptr1; 4860Sstevel@tonic-gate int mcnt, ccnt; 4870Sstevel@tonic-gate char **servers; 4882830Sdjl int rc, len; 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate if (ret == NULL || error == NULL) { 4910Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate (void) memset(ret, 0, sizeof (ns_server_info_t)); 4940Sstevel@tonic-gate *error = NULL; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate (void) memset(space.s_b, 0, DOORBUFFERSIZE); 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate if (request == NULL) 4990Sstevel@tonic-gate ireq = NS_CACHE_NEW; 5000Sstevel@tonic-gate else 5010Sstevel@tonic-gate ireq = request; 5020Sstevel@tonic-gate 5032830Sdjl adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1); 5040Sstevel@tonic-gate if (server != NULL) { 5050Sstevel@tonic-gate adata += strlen(DOORLINESEP) + 1; 5060Sstevel@tonic-gate adata += strlen(server) + 1; 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate ndata = sizeof (space); 5092830Sdjl len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber); 5100Sstevel@tonic-gate space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER; 5112830Sdjl if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len) 5122830Sdjl return (NS_LDAP_MEMORY); 5132830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >= 5144522Schinlong len) 5152830Sdjl return (NS_LDAP_MEMORY); 5160Sstevel@tonic-gate if (server != NULL) { 5172830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, 5184522Schinlong DOORLINESEP, len) >= len) 5192830Sdjl return (NS_LDAP_MEMORY); 5202830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, 5214522Schinlong len) >= len) 5222830Sdjl return (NS_LDAP_MEMORY); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate sptr = &space.s_d; 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) { 5270Sstevel@tonic-gate case SUCCESS: 5280Sstevel@tonic-gate break; 5290Sstevel@tonic-gate /* this case is for when the $mgr is not running, but ldapclient */ 5300Sstevel@tonic-gate /* is trying to initialize things */ 5310Sstevel@tonic-gate case NOSERVER: 5320Sstevel@tonic-gate /* get first server from config list unavailable otherwise */ 5330Sstevel@tonic-gate servers = NULL; 5340Sstevel@tonic-gate rc = __s_api_getServers(&servers, error); 5350Sstevel@tonic-gate if (rc != NS_LDAP_SUCCESS) { 5360Sstevel@tonic-gate if (servers != NULL) { 5370Sstevel@tonic-gate __s_api_free2dArray(servers); 5380Sstevel@tonic-gate servers = NULL; 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate return (rc); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate if (servers == NULL || servers[0] == NULL) { 5430Sstevel@tonic-gate __s_api_free2dArray(servers); 5440Sstevel@tonic-gate servers = NULL; 5450Sstevel@tonic-gate (void) sprintf(errstr, 5464522Schinlong gettext("No server found in configuration")); 5470Sstevel@tonic-gate MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT, 5484522Schinlong strdup(errstr), NULL); 5490Sstevel@tonic-gate return (NS_LDAP_CONFIG); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate ret->server = strdup(servers[0]); 5520Sstevel@tonic-gate if (ret->server == NULL) { 5530Sstevel@tonic-gate __s_api_free2dArray(servers); 5540Sstevel@tonic-gate return (NS_LDAP_MEMORY); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate ret->saslMechanisms = NULL; 5570Sstevel@tonic-gate ret->controls = NULL; 5580Sstevel@tonic-gate __s_api_free2dArray(servers); 5590Sstevel@tonic-gate servers = NULL; 5600Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 5610Sstevel@tonic-gate case NOTFOUND: 5620Sstevel@tonic-gate default: 5630Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* copy info from door call return structure here */ 5670Sstevel@tonic-gate rbuf = space.s_d.ldap_ret.ldap_u.config; 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate /* Get the host */ 5700Sstevel@tonic-gate ptr = strtok_r(rbuf, DOORLINESEP, &rest); 5710Sstevel@tonic-gate if (ptr == NULL) { 5720Sstevel@tonic-gate (void) sprintf(errstr, gettext("No server returned from " 5734522Schinlong "ldap_cachemgr")); 5740Sstevel@tonic-gate MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR, 5754522Schinlong strdup(errstr), NULL); 5760Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate ret->server = strdup(ptr); 5790Sstevel@tonic-gate if (ret->server == NULL) { 5800Sstevel@tonic-gate return (NS_LDAP_MEMORY); 5810Sstevel@tonic-gate } 5824522Schinlong /* Get the host FQDN format */ 5834522Schinlong if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) { 5844522Schinlong ptr = strtok_r(NULL, DOORLINESEP, &rest); 5854522Schinlong if (ptr == NULL) { 5864522Schinlong (void) sprintf(errstr, gettext("No server FQDN format " 5874522Schinlong "returned from ldap_cachemgr")); 5884522Schinlong MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR, 5894522Schinlong strdup(errstr), NULL); 5904522Schinlong free(ret->server); 5914522Schinlong ret->server = NULL; 5924522Schinlong return (NS_LDAP_OP_FAILED); 5934522Schinlong } 5944522Schinlong ret->serverFQDN = strdup(ptr); 5954522Schinlong if (ret->serverFQDN == NULL) { 5964522Schinlong free(ret->server); 5974522Schinlong ret->server = NULL; 5984522Schinlong return (NS_LDAP_MEMORY); 5994522Schinlong } 6004522Schinlong } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /* get the Supported Controls/SASL mechs */ 6030Sstevel@tonic-gate mptr = NULL; 6040Sstevel@tonic-gate mcnt = 0; 6050Sstevel@tonic-gate cptr = NULL; 6060Sstevel@tonic-gate ccnt = 0; 6070Sstevel@tonic-gate for (; ; ) { 6080Sstevel@tonic-gate ptr = strtok_r(NULL, DOORLINESEP, &rest); 6090Sstevel@tonic-gate if (ptr == NULL) 6100Sstevel@tonic-gate break; 6110Sstevel@tonic-gate if (strncasecmp(ptr, _SASLMECHANISM, 6124522Schinlong _SASLMECHANISM_LEN) == 0) { 6130Sstevel@tonic-gate dptr = strchr(ptr, '='); 6140Sstevel@tonic-gate if (dptr == NULL) 6150Sstevel@tonic-gate continue; 6160Sstevel@tonic-gate dptr++; 6170Sstevel@tonic-gate mptr1 = (char **)realloc((void *)mptr, 6184522Schinlong sizeof (char *) * (mcnt+2)); 6190Sstevel@tonic-gate if (mptr1 == NULL) { 6200Sstevel@tonic-gate __s_api_free2dArray(mptr); 6210Sstevel@tonic-gate if (sptr != &space.s_d) { 6224522Schinlong (void) munmap((char *)sptr, ndata); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate __s_api_free2dArray(cptr); 6254522Schinlong __s_api_free_server_info(ret); 6260Sstevel@tonic-gate return (NS_LDAP_MEMORY); 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate mptr = mptr1; 6290Sstevel@tonic-gate mptr[mcnt] = strdup(dptr); 6300Sstevel@tonic-gate if (mptr[mcnt] == NULL) { 6310Sstevel@tonic-gate if (sptr != &space.s_d) { 6324522Schinlong (void) munmap((char *)sptr, ndata); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate __s_api_free2dArray(cptr); 6350Sstevel@tonic-gate cptr = NULL; 6360Sstevel@tonic-gate __s_api_free2dArray(mptr); 6370Sstevel@tonic-gate mptr = NULL; 6384522Schinlong __s_api_free_server_info(ret); 6390Sstevel@tonic-gate return (NS_LDAP_MEMORY); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate mcnt++; 6420Sstevel@tonic-gate mptr[mcnt] = NULL; 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate if (strncasecmp(ptr, _SUPPORTEDCONTROL, 6454522Schinlong _SUPPORTEDCONTROL_LEN) == 0) { 6460Sstevel@tonic-gate dptr = strchr(ptr, '='); 6470Sstevel@tonic-gate if (dptr == NULL) 6480Sstevel@tonic-gate continue; 6490Sstevel@tonic-gate dptr++; 6500Sstevel@tonic-gate cptr1 = (char **)realloc((void *)cptr, 6514522Schinlong sizeof (char *) * (ccnt+2)); 6520Sstevel@tonic-gate if (cptr1 == NULL) { 6530Sstevel@tonic-gate if (sptr != &space.s_d) { 6544522Schinlong (void) munmap((char *)sptr, ndata); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate __s_api_free2dArray(cptr); 6570Sstevel@tonic-gate __s_api_free2dArray(mptr); 6580Sstevel@tonic-gate mptr = NULL; 6594522Schinlong __s_api_free_server_info(ret); 6600Sstevel@tonic-gate return (NS_LDAP_MEMORY); 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate cptr = cptr1; 6630Sstevel@tonic-gate cptr[ccnt] = strdup(dptr); 6640Sstevel@tonic-gate if (cptr[ccnt] == NULL) { 6650Sstevel@tonic-gate if (sptr != &space.s_d) { 6664522Schinlong (void) munmap((char *)sptr, ndata); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate __s_api_free2dArray(cptr); 6690Sstevel@tonic-gate cptr = NULL; 6700Sstevel@tonic-gate __s_api_free2dArray(mptr); 6710Sstevel@tonic-gate mptr = NULL; 6724522Schinlong __s_api_free_server_info(ret); 6730Sstevel@tonic-gate return (NS_LDAP_MEMORY); 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate ccnt++; 6760Sstevel@tonic-gate cptr[ccnt] = NULL; 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate if (mptr != NULL) { 6800Sstevel@tonic-gate ret->saslMechanisms = mptr; 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate if (cptr != NULL) { 6830Sstevel@tonic-gate ret->controls = cptr; 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* clean up door call */ 6880Sstevel@tonic-gate if (sptr != &space.s_d) { 6890Sstevel@tonic-gate (void) munmap((char *)sptr, ndata); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate *error = NULL; 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate /* 6980Sstevel@tonic-gate * printCred(): prints the credential structure 6990Sstevel@tonic-gate */ 7000Sstevel@tonic-gate static void 7012830Sdjl printCred(int pri, const ns_cred_t *cred) 7020Sstevel@tonic-gate { 7032830Sdjl thread_t t = thr_self(); 7042830Sdjl 7050Sstevel@tonic-gate if (cred == NULL) { 7062830Sdjl syslog(LOG_ERR, "tid= %d: printCred: cred is NULL\n", t); 7070Sstevel@tonic-gate return; 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7102830Sdjl syslog(pri, "tid= %d: AuthType=%d", t, cred->auth.type); 7112830Sdjl syslog(pri, "tid= %d: TlsType=%d", t, cred->auth.tlstype); 7122830Sdjl syslog(pri, "tid= %d: SaslMech=%d", t, cred->auth.saslmech); 7132830Sdjl syslog(pri, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt); 7140Sstevel@tonic-gate if (cred->hostcertpath) 7152830Sdjl syslog(pri, "tid= %d: hostCertPath=%s\n", 7164522Schinlong t, cred->hostcertpath); 7170Sstevel@tonic-gate if (cred->cred.unix_cred.userID) 7182830Sdjl syslog(pri, "tid= %d: userID=%s\n", 7194522Schinlong t, cred->cred.unix_cred.userID); 7203387Schinlong #ifdef DEBUG 7210Sstevel@tonic-gate if (cred->cred.unix_cred.passwd) 7222830Sdjl syslog(pri, "tid= %d: passwd=%s\n", 7234522Schinlong t, cred->cred.unix_cred.passwd); 7243387Schinlong #endif 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate /* 7280Sstevel@tonic-gate * printConnection(): prints the connection structure 7290Sstevel@tonic-gate */ 7300Sstevel@tonic-gate static void 7312830Sdjl printConnection(int pri, Connection *con) 7320Sstevel@tonic-gate { 7332830Sdjl thread_t t = thr_self(); 7342830Sdjl 7352830Sdjl if (con == NULL) 7360Sstevel@tonic-gate return; 7370Sstevel@tonic-gate 7382830Sdjl syslog(pri, "tid= %d: connectionID=%d\n", t, con->connectionId); 7392830Sdjl syslog(pri, "tid= %d: shared=%d\n", t, con->shared); 7402830Sdjl syslog(pri, "tid= %d: usedBit=%d\n", t, con->usedBit); 7412830Sdjl syslog(pri, "tid= %d: threadID=%d\n", t, con->threadID); 7420Sstevel@tonic-gate if (con->serverAddr) { 7432830Sdjl syslog(pri, "tid= %d: serverAddr=%s\n", 7444522Schinlong t, con->serverAddr); 7450Sstevel@tonic-gate } 7462830Sdjl printCred(pri, con->auth); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate /* 7522830Sdjl * addConnection(): set up a connection so that it can be shared 7532830Sdjl * among multiple threads and then insert the connection in the 7542830Sdjl * connection list. 7550Sstevel@tonic-gate * Returns: -1 = failure, new Connection ID = success 7562830Sdjl * 7572830Sdjl * This function could exit with sessionLock locked. It will be 7582830Sdjl * be unlocked in __s_api_getConnection() when it exits without getting a 7592830Sdjl * connection. 7600Sstevel@tonic-gate */ 7610Sstevel@tonic-gate static int 7620Sstevel@tonic-gate addConnection(Connection *con) 7630Sstevel@tonic-gate { 7642830Sdjl int i, noMTperC = 0; 7652830Sdjl thread_t t = thr_self(); 7662830Sdjl struct ldap_thread_fns tfns; 7672830Sdjl void *tsd; 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate if (!con) 7700Sstevel@tonic-gate return (-1); 7712830Sdjl 7722830Sdjl syslog(LOG_DEBUG, "tid= %d: Adding connection (serverAddr=%s)", 7734522Schinlong t, con->serverAddr); 7742830Sdjl 7752830Sdjl if (MTperConn == 1) { 7762830Sdjl /* 7772830Sdjl * Make sure ld has proper thread functions and tsd 7782830Sdjl * is set up. 7792830Sdjl */ 7802830Sdjl (void) memset(&tfns, 0, sizeof (struct ldap_thread_fns)); 7812830Sdjl /* 7822830Sdjl * ldap_init sets ltf_get_lderrno and ltf_set_lderrno to NULLs. 7832830Sdjl * It's supposed to be overwritten by ns_setup_mt_conn_and_tsd. 7842830Sdjl */ 7852830Sdjl if (ldap_get_option(con->ld, LDAP_OPT_THREAD_FN_PTRS, 7864522Schinlong (void *)&tfns) != 0 || 7874522Schinlong tfns.ltf_get_lderrno != get_ld_error || 7884522Schinlong tfns.ltf_set_lderrno != set_ld_error) { 7892830Sdjl MTperConn = 0; 7902830Sdjl noMTperC = 1; 7912830Sdjl } else { 7922830Sdjl if (thr_getspecific(ns_mtckey, &tsd) != 0 || 7934522Schinlong tsd == NULL) 7942830Sdjl noMTperC = 1; 7952830Sdjl } 7962830Sdjl 7972830Sdjl } else { 7982830Sdjl noMTperC = 1; 7992830Sdjl } 8002830Sdjl 8012830Sdjl (void) rw_wrlock(&sessionPoolLock); 8020Sstevel@tonic-gate if (sessionPool == NULL) { 8030Sstevel@tonic-gate sessionPoolSize = SESSION_CACHE_INC; 8040Sstevel@tonic-gate sessionPool = calloc(sessionPoolSize, 8054522Schinlong sizeof (struct connection **)); 8060Sstevel@tonic-gate if (!sessionPool) { 8072830Sdjl (void) rw_unlock(&sessionPoolLock); 8080Sstevel@tonic-gate return (-1); 8090Sstevel@tonic-gate } 8102830Sdjl 8112830Sdjl syslog(LOG_DEBUG, "tid= %d: Initialized sessionPool", t); 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i) 8140Sstevel@tonic-gate ; 8150Sstevel@tonic-gate if (i == sessionPoolSize) { 8160Sstevel@tonic-gate /* run out of array, need to increase sessionPool */ 8170Sstevel@tonic-gate Connection **cl; 8180Sstevel@tonic-gate cl = (Connection **) realloc(sessionPool, 8194522Schinlong (sessionPoolSize + SESSION_CACHE_INC) * 8204522Schinlong sizeof (Connection *)); 8210Sstevel@tonic-gate if (!cl) { 8222830Sdjl (void) rw_unlock(&sessionPoolLock); 8230Sstevel@tonic-gate return (-1); 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate (void) memset(cl + sessionPoolSize, 0, 8264522Schinlong SESSION_CACHE_INC * sizeof (struct connection *)); 8270Sstevel@tonic-gate sessionPool = cl; 8280Sstevel@tonic-gate sessionPoolSize += SESSION_CACHE_INC; 8292830Sdjl syslog(LOG_DEBUG, "tid: %d: Increased " 8304522Schinlong "sessionPoolSize to: %d\n", 8314522Schinlong t, sessionPoolSize); 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate sessionPool[i] = con; 8343387Schinlong if (noMTperC == 0) { 8352830Sdjl con->shared++; 8363387Schinlong con->pid = getpid(); 8373387Schinlong (void) mutex_lock(&sharedConnNumberLock); 8383387Schinlong sharedConnNumber++; 8393387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 8403387Schinlong } else 8412830Sdjl con->usedBit = B_TRUE; 8422830Sdjl 8432830Sdjl (void) rw_unlock(&sessionPoolLock); 8442830Sdjl 8450Sstevel@tonic-gate con->connectionId = i + CONID_OFFSET; 8462830Sdjl 8472830Sdjl syslog(LOG_DEBUG, "tid= %d: Connection added [%d]\n", 8484522Schinlong t, i); 8492830Sdjl printConnection(LOG_DEBUG, con); 8502830Sdjl 8512830Sdjl /* 8522830Sdjl * A connection can be shared now, unlock 8532830Sdjl * the session mutex and let other 8542830Sdjl * threads try to use this connection or 8552830Sdjl * get their own. 8562830Sdjl */ 8572830Sdjl if (wait4session != 0 && sessionTid == thr_self()) { 8582830Sdjl wait4session = 0; 8592830Sdjl sessionTid = 0; 8602830Sdjl syslog(LOG_DEBUG, "tid= %d: unlocking sessionLock\n", t); 8612830Sdjl (void) mutex_unlock(&sessionLock); 8622830Sdjl } 8632830Sdjl 8640Sstevel@tonic-gate return (i + CONID_OFFSET); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * See if the specified session matches a currently available 8690Sstevel@tonic-gate */ 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate static int 8720Sstevel@tonic-gate findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, 8730Sstevel@tonic-gate Connection **conp) 8740Sstevel@tonic-gate { 8750Sstevel@tonic-gate Connection *cp; 8760Sstevel@tonic-gate int id; 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate if ((conp == NULL) || (auth == NULL) || cID < CONID_OFFSET) 8790Sstevel@tonic-gate return (-1); 8802830Sdjl 8815532Smj162486 /* 8825532Smj162486 * If a new connection is requested, no need to continue. 8835532Smj162486 * If the process is not nscd and is not requesting keep connections 8845532Smj162486 * alive, no need to continue. 8855532Smj162486 */ 8865532Smj162486 if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() && 8876072Smj162486 !__s_api_peruser_proc() && !(flags & NS_LDAP_KEEP_CONN))) 8882830Sdjl return (-1); 8892830Sdjl 8900Sstevel@tonic-gate *conp = NULL; 8910Sstevel@tonic-gate if (sessionPool == NULL) 8920Sstevel@tonic-gate return (-1); 8930Sstevel@tonic-gate id = cID - CONID_OFFSET; 8940Sstevel@tonic-gate if (id < 0 || id >= sessionPoolSize) 8950Sstevel@tonic-gate return (-1); 8960Sstevel@tonic-gate 8972830Sdjl (void) rw_rdlock(&sessionPoolLock); 8980Sstevel@tonic-gate if (sessionPool[id] == NULL) { 8992830Sdjl (void) rw_unlock(&sessionPoolLock); 9000Sstevel@tonic-gate return (-1); 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate cp = sessionPool[id]; 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate /* 9050Sstevel@tonic-gate * Make sure the connection has the same type of authentication method 9060Sstevel@tonic-gate */ 9070Sstevel@tonic-gate if ((cp->usedBit) || 9082830Sdjl (cp->notAvail) || 9090Sstevel@tonic-gate (cp->auth->auth.type != auth->auth.type) || 9100Sstevel@tonic-gate (cp->auth->auth.tlstype != auth->auth.tlstype) || 9110Sstevel@tonic-gate (cp->auth->auth.saslmech != auth->auth.saslmech) || 9120Sstevel@tonic-gate (cp->auth->auth.saslopt != auth->auth.saslopt)) { 9132830Sdjl (void) rw_unlock(&sessionPoolLock); 9140Sstevel@tonic-gate return (-1); 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && 9174522Schinlong ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) || 9184522Schinlong (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) || 9194522Schinlong (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) && 9204522Schinlong ((cp->auth->cred.unix_cred.userID == NULL) || 9214522Schinlong (strcasecmp(cp->auth->cred.unix_cred.userID, 9224522Schinlong auth->cred.unix_cred.userID) != 0))) { 9232830Sdjl (void) rw_unlock(&sessionPoolLock); 9240Sstevel@tonic-gate return (-1); 9250Sstevel@tonic-gate } 9262830Sdjl 9270Sstevel@tonic-gate /* An existing connection is found but it needs to be reset */ 9280Sstevel@tonic-gate if (flags & NS_LDAP_NEW_CONN) { 9292830Sdjl (void) rw_unlock(&sessionPoolLock); 9300Sstevel@tonic-gate DropConnection(cID, 0); 9310Sstevel@tonic-gate return (-1); 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate /* found an available connection */ 9340Sstevel@tonic-gate cp->usedBit = B_TRUE; 9352830Sdjl (void) rw_unlock(&sessionPoolLock); 9360Sstevel@tonic-gate cp->threadID = thr_self(); 9370Sstevel@tonic-gate *conp = cp; 9380Sstevel@tonic-gate return (cID); 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate /* 9420Sstevel@tonic-gate * findConnection(): find an available connection from the list 9430Sstevel@tonic-gate * that matches the criteria specified in Connection structure. 9440Sstevel@tonic-gate * If serverAddr is NULL, then find a connection to any server 9450Sstevel@tonic-gate * as long as it matches the rest of the parameters. 9460Sstevel@tonic-gate * Returns: -1 = failure, the Connection ID found = success. 9472830Sdjl * 9482830Sdjl * This function could exit with sessionLock locked. It will be 9492830Sdjl * be unlocked in addConnection() when this thread adds the connection 9502830Sdjl * to the pool or in __s_api_getConnection() when it exits without getting a 9512830Sdjl * connection. 9520Sstevel@tonic-gate */ 9532830Sdjl #define TRY_TIMES 10 9540Sstevel@tonic-gate static int 9552830Sdjl findConnection(int flags, const char *serverAddr, 9562830Sdjl const ns_cred_t *auth, Connection **conp) 9570Sstevel@tonic-gate { 9580Sstevel@tonic-gate Connection *cp; 9594048Schinlong int i, j, conn_server_index, up_server_index, drop_conn; 9602830Sdjl int rc; 9612830Sdjl int try; 9624048Schinlong ns_server_info_t sinfo; 9634048Schinlong ns_ldap_error_t *errorp = NULL; 9644522Schinlong char **servers; 9654048Schinlong void **paramVal = NULL; 9662830Sdjl #ifdef DEBUG 9672830Sdjl thread_t t = thr_self(); 9682830Sdjl #endif /* DEBUG */ 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate if (auth == NULL || conp == NULL) 9710Sstevel@tonic-gate return (-1); 9720Sstevel@tonic-gate *conp = NULL; 9730Sstevel@tonic-gate 9745840Smj162486 /* 9755840Smj162486 * If a new connection is requested, no need to continue. 9765840Smj162486 * If the process is not nscd and is not requesting keep connections 9775840Smj162486 * alive, no need to continue. 9785840Smj162486 */ 9795840Smj162486 if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() && 9806072Smj162486 !__s_api_peruser_proc() && !(flags & NS_LDAP_KEEP_CONN))) 9812830Sdjl return (-1); 9822830Sdjl 9830Sstevel@tonic-gate #ifdef DEBUG 9842830Sdjl (void) fprintf(stderr, "tid= %d: Find connection\n", t); 9852830Sdjl (void) fprintf(stderr, "tid= %d: Looking for ....\n", t); 9860Sstevel@tonic-gate if (serverAddr && *serverAddr) 9872830Sdjl (void) fprintf(stderr, "tid= %d: serverAddr=%s\n", 9884522Schinlong t, serverAddr); 9890Sstevel@tonic-gate else 9902830Sdjl (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t); 9914048Schinlong printCred(LOG_DEBUG, auth); 9920Sstevel@tonic-gate fflush(stderr); 9930Sstevel@tonic-gate #endif /* DEBUG */ 9942830Sdjl 9952830Sdjl /* 9962830Sdjl * If multiple threads per connection not supported, 9972830Sdjl * no sessionPool means no connection 9982830Sdjl */ 9992830Sdjl (void) rw_rdlock(&sessionPoolLock); 10002830Sdjl if (MTperConn == 0 && sessionPool == NULL) { 10012830Sdjl (void) rw_unlock(&sessionPoolLock); 10020Sstevel@tonic-gate return (-1); 10032830Sdjl } 10042830Sdjl 10052830Sdjl /* 10063387Schinlong * If no sharable connections in cache, then serialize the opening 10072830Sdjl * of connections. Make sure only one is being opened 10082830Sdjl * at a time. Otherwise, we may end up with more 10092830Sdjl * connections than we want (if multiple threads get 10102830Sdjl * here at the same time) 10112830Sdjl */ 10123387Schinlong (void) mutex_lock(&sharedConnNumberLock); 10133387Schinlong if (sessionPool == NULL || (sharedConnNumber == 0 && MTperConn == 1)) { 10143387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 10152830Sdjl (void) rw_unlock(&sessionPoolLock); 10162830Sdjl (void) mutex_lock(&sessionLock); 10173387Schinlong (void) mutex_lock(&sharedConnNumberLock); 10183387Schinlong if (sessionPool == NULL || (sharedConnNumber == 0 && 10194522Schinlong MTperConn == 1)) { 10203387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 10212830Sdjl wait4session = 1; 10222830Sdjl sessionTid = thr_self(); 10232830Sdjl #ifdef DEBUG 10242830Sdjl (void) fprintf(stderr, "tid= %d: get " 10254522Schinlong "connection ... \n", t); 10262830Sdjl fflush(stderr); 10272830Sdjl #endif /* DEBUG */ 10282830Sdjl /* 10292830Sdjl * Exit with sessionLock locked. It will be 10302830Sdjl * be unlocked in addConnection() when this 10312830Sdjl * thread adds the connection to the pool or 10322830Sdjl * in __s_api_getConnection() when it exits 10332830Sdjl * without getting a connection. 10342830Sdjl */ 10352830Sdjl return (-1); 10362830Sdjl } 10372830Sdjl 10382830Sdjl #ifdef DEBUG 10393387Schinlong (void) fprintf(stderr, "tid= %d: shareable connections " 10404522Schinlong "exist\n", t); 10412830Sdjl fflush(stderr); 10422830Sdjl #endif /* DEBUG */ 10433387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 10442830Sdjl /* 10453387Schinlong * There are sharable connections, check to see if 10462830Sdjl * one can be shared. 10472830Sdjl */ 10482830Sdjl (void) mutex_unlock(&sessionLock); 10492830Sdjl (void) rw_rdlock(&sessionPoolLock); 10503387Schinlong } else 10513387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 10523387Schinlong 10532830Sdjl try = 0; 10542830Sdjl check_again: 10552830Sdjl 10560Sstevel@tonic-gate for (i = 0; i < sessionPoolSize; ++i) { 10570Sstevel@tonic-gate if (sessionPool[i] == NULL) 10580Sstevel@tonic-gate continue; 10590Sstevel@tonic-gate cp = sessionPool[i]; 10600Sstevel@tonic-gate #ifdef DEBUG 10612830Sdjl (void) fprintf(stderr, "tid= %d: checking connection " 10624522Schinlong "[%d] ....\n", t, i); 10634048Schinlong printConnection(LOG_DEBUG, cp); 10640Sstevel@tonic-gate #endif /* DEBUG */ 10652830Sdjl if ((cp->usedBit) || (cp->notAvail) || 10660Sstevel@tonic-gate (cp->auth->auth.type != auth->auth.type) || 10670Sstevel@tonic-gate (cp->auth->auth.tlstype != auth->auth.tlstype) || 10680Sstevel@tonic-gate (cp->auth->auth.saslmech != auth->auth.saslmech) || 10690Sstevel@tonic-gate (cp->auth->auth.saslopt != auth->auth.saslopt) || 10700Sstevel@tonic-gate (serverAddr && *serverAddr && 10710Sstevel@tonic-gate (strcasecmp(serverAddr, cp->serverAddr) != 0))) 10720Sstevel@tonic-gate continue; 10730Sstevel@tonic-gate if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && 10740Sstevel@tonic-gate ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) || 10750Sstevel@tonic-gate (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) || 10760Sstevel@tonic-gate (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) && 10770Sstevel@tonic-gate ((cp->auth->cred.unix_cred.userID == NULL) || 10780Sstevel@tonic-gate (cp->auth->cred.unix_cred.passwd == NULL) || 10790Sstevel@tonic-gate ((strcasecmp(cp->auth->cred.unix_cred.userID, 10804522Schinlong auth->cred.unix_cred.userID) != 0)) || 10810Sstevel@tonic-gate ((strcmp(cp->auth->cred.unix_cred.passwd, 10824522Schinlong auth->cred.unix_cred.passwd) != 0)))) 10830Sstevel@tonic-gate continue; 10844048Schinlong if (!(serverAddr && *serverAddr)) { 10854048Schinlong /* 10864048Schinlong * Get preferred server list. 10874048Schinlong * When preferred servers are merged with default 10884048Schinlong * servers (S_LDAP_SERVER_P) by __s_api_getServer, 10894048Schinlong * preferred servers are copied sequencially. 10904048Schinlong * The order should be the same as the order retrieved 10914048Schinlong * by __ns_ldap_getParam. 10924048Schinlong */ 10934048Schinlong if ((rc = __ns_ldap_getParam(NS_LDAP_SERVER_PREF_P, 10944522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 10954048Schinlong (void) __ns_ldap_freeError(&errorp); 10964048Schinlong (void) __ns_ldap_freeParam(¶mVal); 10974048Schinlong (void) rw_unlock(&sessionPoolLock); 10984048Schinlong return (-1); 10994048Schinlong } 11004048Schinlong servers = (char **)paramVal; 11014048Schinlong /* 11024048Schinlong * Do fallback only if preferred servers are defined. 11034048Schinlong */ 11044048Schinlong if (servers != NULL) { 11054048Schinlong /* 11064048Schinlong * Find the 1st available server 11074048Schinlong */ 11084048Schinlong rc = __s_api_requestServer(NS_CACHE_NEW, NULL, 11094522Schinlong &sinfo, &errorp, NS_CACHE_ADDR_IP); 11104048Schinlong if (rc != NS_LDAP_SUCCESS) { 11114048Schinlong /* 11124048Schinlong * Drop the connection. 11134048Schinlong * Pass 1 to fini so it won't be locked 11144048Schinlong * inside _DropConnection 11154048Schinlong */ 11164048Schinlong _DropConnection( 11174522Schinlong cp->connectionId, 11184522Schinlong NS_LDAP_NEW_CONN, 1); 11194048Schinlong (void) rw_unlock( 11204048Schinlong &sessionPoolLock); 11214522Schinlong (void) __ns_ldap_freeError(&errorp); 11224048Schinlong (void) __ns_ldap_freeParam( 11234522Schinlong (void ***)&servers); 11244048Schinlong return (-1); 11254048Schinlong } 11264048Schinlong 11274048Schinlong if (sinfo.server) { 11284048Schinlong /* 11294048Schinlong * Test if cp->serverAddr is a 11304048Schinlong * preferred server. 11314048Schinlong */ 11324048Schinlong conn_server_index = -1; 11334048Schinlong for (j = 0; servers[j] != NULL; j++) { 11344048Schinlong if (strcasecmp(servers[j], 11354522Schinlong cp->serverAddr) == 0) { 11364048Schinlong conn_server_index = j; 11374048Schinlong break; 11384048Schinlong } 11394048Schinlong } 11404048Schinlong /* 11414048Schinlong * Test if sinfo.server is a preferred 11424048Schinlong * server. 11434048Schinlong */ 11444048Schinlong up_server_index = -1; 11454048Schinlong for (j = 0; servers[j] != NULL; j++) { 11464048Schinlong if (strcasecmp(sinfo.server, 11474522Schinlong servers[j]) == 0) { 11484048Schinlong up_server_index = j; 11494048Schinlong break; 11504048Schinlong } 11514048Schinlong } 11524048Schinlong 11534048Schinlong /* 11544048Schinlong * The following code is to fall back 11554048Schinlong * to preferred servers if servers 11564048Schinlong * are previously down but are up now. 11574048Schinlong * If cp->serverAddr is a preferred 11584048Schinlong * server, it falls back to the servers 11594048Schinlong * ahead of it. If cp->serverAddr is 11604048Schinlong * not a preferred server, it falls 11614048Schinlong * back to any of preferred servers 11624048Schinlong * returned by ldap_cachemgr. 11634048Schinlong */ 11644048Schinlong if (conn_server_index >= 0 && 11654522Schinlong up_server_index >= 0) { 11664048Schinlong /* 11674048Schinlong * cp->serverAddr and 11684048Schinlong * sinfo.server are preferred 11694048Schinlong * servers. 11704048Schinlong */ 11714048Schinlong if (up_server_index == 11724522Schinlong conn_server_index) 11734048Schinlong /* 11744048Schinlong * sinfo.server is the 11754048Schinlong * same as 11764048Schinlong * cp->serverAddr. 11774048Schinlong * Keep the connection. 11784048Schinlong */ 11794048Schinlong drop_conn = 0; 11804048Schinlong else 11814048Schinlong /* 11824048Schinlong * 1. 11834048Schinlong * up_server_index < 11844048Schinlong * conn_server_index 11854048Schinlong * 11864048Schinlong * sinfo is ahead of 11874048Schinlong * cp->serverAddr in 11884048Schinlong * Need to fall back. 11894048Schinlong * 2. 11904048Schinlong * up_server_index > 11914048Schinlong * conn_server_index 11924048Schinlong * cp->serverAddr is 11934048Schinlong * down. Drop it. 11944048Schinlong */ 11954048Schinlong drop_conn = 1; 11964048Schinlong } else if (conn_server_index >= 0 && 11974522Schinlong up_server_index == -1) { 11984048Schinlong /* 11994048Schinlong * cp->serverAddr is a preferred 12004048Schinlong * server but sinfo.server is 12014048Schinlong * not. Preferred servers are 12024048Schinlong * ahead of default servers. 12034048Schinlong * This means cp->serverAddr is 12044048Schinlong * down. Drop it. 12054048Schinlong */ 12064048Schinlong drop_conn = 1; 12074048Schinlong } else if (conn_server_index == -1 && 12084522Schinlong up_server_index >= 0) { 12094048Schinlong /* 12104048Schinlong * cp->serverAddr is not a 12114048Schinlong * preferred server but 12124048Schinlong * sinfo.server is. 12134048Schinlong * Fall back. 12144048Schinlong */ 12154048Schinlong drop_conn = 1; 12164048Schinlong } else { 12174048Schinlong /* 12184048Schinlong * Both index are -1 12194048Schinlong * cp->serverAddr and 12204048Schinlong * sinfo.server are not 12214048Schinlong * preferred servers. 12224048Schinlong * No fallback. 12234048Schinlong */ 12244048Schinlong drop_conn = 0; 12254048Schinlong } 12264048Schinlong if (drop_conn) { 12274048Schinlong /* 12284048Schinlong * Drop the connection so the 12294048Schinlong * new conection can fall back 12304048Schinlong * to a new server later. 12314048Schinlong * Pass 1 to fini so it won't 12324048Schinlong * be locked inside 12334048Schinlong * _DropConnection 12344048Schinlong */ 12354048Schinlong _DropConnection( 12364522Schinlong cp->connectionId, 12374522Schinlong NS_LDAP_NEW_CONN, 1); 12384048Schinlong (void) rw_unlock( 12394048Schinlong &sessionPoolLock); 12404048Schinlong (void) __ns_ldap_freeParam( 12414522Schinlong (void ***)&servers); 12424522Schinlong __s_api_free_server_info( 12434522Schinlong &sinfo); 12444048Schinlong return (-1); 12454048Schinlong } else { 12464048Schinlong /* 12474048Schinlong * Keep the connection 12484048Schinlong */ 12494048Schinlong (void) __ns_ldap_freeParam( 12504522Schinlong (void ***)&servers); 12514522Schinlong __s_api_free_server_info( 12524522Schinlong &sinfo); 12534048Schinlong } 12544048Schinlong } else { 12554048Schinlong (void) rw_unlock(&sessionPoolLock); 12564048Schinlong syslog(LOG_WARNING, "libsldap: Null " 12574522Schinlong "sinfo.server from " 12584522Schinlong "__s_api_requestServer"); 12594048Schinlong (void) __ns_ldap_freeParam( 12604522Schinlong (void ***)&servers); 12614048Schinlong return (-1); 12624048Schinlong } 12634048Schinlong } 12644048Schinlong } 12654048Schinlong 12660Sstevel@tonic-gate /* found an available connection */ 12672830Sdjl if (MTperConn == 0) 12682830Sdjl cp->usedBit = B_TRUE; 12692830Sdjl else { 12703387Schinlong /* 12713387Schinlong * if connection was established in a different 12723387Schinlong * process, drop it and get a new one 12733387Schinlong */ 12743387Schinlong if (cp->pid != getpid()) { 12753387Schinlong (void) rw_unlock(&sessionPoolLock); 12763387Schinlong DropConnection(cp->connectionId, 12774522Schinlong NS_LDAP_NEW_CONN); 12783387Schinlong 12793387Schinlong goto get_conn; 12803387Schinlong } 12812830Sdjl /* allocate TSD for per thread ldap error */ 12822830Sdjl rc = tsd_setup(); 12832830Sdjl 12842830Sdjl /* if we got TSD, this connection is shared */ 12852830Sdjl if (rc != -1) 12862830Sdjl cp->shared++; 12872830Sdjl else if (cp->shared == 0) { 12882830Sdjl cp->usedBit = B_TRUE; 12892830Sdjl cp->threadID = thr_self(); 12902830Sdjl (void) rw_unlock(&sessionPoolLock); 12912830Sdjl return (-1); 12922830Sdjl } 12932830Sdjl } 12942830Sdjl (void) rw_unlock(&sessionPoolLock); 12952830Sdjl 12960Sstevel@tonic-gate *conp = cp; 12970Sstevel@tonic-gate #ifdef DEBUG 12982830Sdjl (void) fprintf(stderr, "tid= %d: Connection found " 12994522Schinlong "cID=%d, shared =%d\n", t, i, cp->shared); 13000Sstevel@tonic-gate fflush(stderr); 13010Sstevel@tonic-gate #endif /* DEBUG */ 13020Sstevel@tonic-gate return (i + CONID_OFFSET); 13030Sstevel@tonic-gate } 13043387Schinlong 13053387Schinlong get_conn: 13063387Schinlong 13072830Sdjl (void) rw_unlock(&sessionPoolLock); 13082830Sdjl 13092830Sdjl /* 13102830Sdjl * If multiple threads per connection not supported, 13112830Sdjl * we are done, just return -1 to tell the caller to 13122830Sdjl * proceed with opening a connection 13132830Sdjl */ 13142830Sdjl if (MTperConn == 0) 13152830Sdjl return (-1); 13162830Sdjl 13172830Sdjl /* 13182830Sdjl * No connection can be shared, test to see if 13192830Sdjl * one is being opened. If trylock returns 13202830Sdjl * EBUSY then it is, so wait until the opening 13212830Sdjl * is done and try to see if the new connection 13222830Sdjl * can be shared. 13232830Sdjl */ 13242830Sdjl rc = mutex_trylock(&sessionLock); 13252830Sdjl if (rc == EBUSY) { 13262830Sdjl (void) mutex_lock(&sessionLock); 13272830Sdjl (void) mutex_unlock(&sessionLock); 13282830Sdjl (void) rw_rdlock(&sessionPoolLock); 13292830Sdjl #ifdef DEBUG 13302830Sdjl (void) fprintf(stderr, "tid= %d: check session " 13314522Schinlong "pool again\n", t); 13322830Sdjl fflush(stderr); 13332830Sdjl #endif /* DEBUG */ 13342830Sdjl if (try < TRY_TIMES) { 13352830Sdjl try++; 13362830Sdjl goto check_again; 13372830Sdjl } else { 13382830Sdjl syslog(LOG_WARNING, "libsldap: mutex_trylock " 13394522Schinlong "%d times. Stop.", TRY_TIMES); 13403387Schinlong (void) rw_unlock(&sessionPoolLock); 13412830Sdjl return (-1); 13422830Sdjl } 13432830Sdjl } else if (rc == 0) { 13442830Sdjl /* 13452830Sdjl * No connection can be shared, none being opened, 13462830Sdjl * exit with sessionLock locked to open one. The 13472830Sdjl * mutex will be unlocked in addConnection() when 13482830Sdjl * this thread adds the new connection to the pool 13492830Sdjl * or in __s_api_getConnection() when it exits 13502830Sdjl * without getting a connection. 13512830Sdjl */ 13522830Sdjl wait4session = 1; 13532830Sdjl sessionTid = thr_self(); 13542830Sdjl #ifdef DEBUG 13552830Sdjl (void) fprintf(stderr, "tid= %d: no connection found, " 13564522Schinlong "none being opened, get connection ...\n", t); 13572830Sdjl fflush(stderr); 13582830Sdjl #endif /* DEBUG */ 13592830Sdjl return (-1); 13602830Sdjl } else { 13612830Sdjl syslog(LOG_WARNING, "libsldap: mutex_trylock unexpected " 13624522Schinlong "error %d", rc); 13632830Sdjl return (-1); 13642830Sdjl } 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate /* 13680Sstevel@tonic-gate * Free a Connection structure 13690Sstevel@tonic-gate */ 13700Sstevel@tonic-gate static void 13710Sstevel@tonic-gate freeConnection(Connection *con) 13720Sstevel@tonic-gate { 13730Sstevel@tonic-gate if (con == NULL) 13740Sstevel@tonic-gate return; 13750Sstevel@tonic-gate if (con->serverAddr) 13760Sstevel@tonic-gate free(con->serverAddr); 13770Sstevel@tonic-gate if (con->auth) 13780Sstevel@tonic-gate (void) __ns_ldap_freeCred(&(con->auth)); 13790Sstevel@tonic-gate if (con->saslMechanisms) { 13800Sstevel@tonic-gate __s_api_free2dArray(con->saslMechanisms); 13810Sstevel@tonic-gate } 13820Sstevel@tonic-gate if (con->controls) { 13830Sstevel@tonic-gate __s_api_free2dArray(con->controls); 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate free(con); 13860Sstevel@tonic-gate } 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate /* 13890Sstevel@tonic-gate * Find a connection matching the passed in criteria. If an open 13900Sstevel@tonic-gate * connection with that criteria exists use it, otherwise open a 13910Sstevel@tonic-gate * new connection. 13920Sstevel@tonic-gate * Success: returns the pointer to the Connection structure 13930Sstevel@tonic-gate * Failure: returns NULL, error code and message should be in errorp 13940Sstevel@tonic-gate */ 13951687Sjanga 13960Sstevel@tonic-gate static int 13970Sstevel@tonic-gate makeConnection(Connection **conp, const char *serverAddr, 13980Sstevel@tonic-gate const ns_cred_t *auth, ConnectionID *cID, int timeoutSec, 13991179Svv149972 ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd, 14002830Sdjl int nopasswd_acct_mgmt, int flags, char ***badsrvrs) 14010Sstevel@tonic-gate { 14020Sstevel@tonic-gate Connection *con = NULL; 14030Sstevel@tonic-gate ConnectionID id; 14040Sstevel@tonic-gate char errmsg[MAXERROR]; 14050Sstevel@tonic-gate int rc, exit_rc = NS_LDAP_SUCCESS; 14060Sstevel@tonic-gate ns_server_info_t sinfo; 14070Sstevel@tonic-gate char *hReq, *host = NULL; 14080Sstevel@tonic-gate LDAP *ld = NULL; 14090Sstevel@tonic-gate int passwd_mgmt = 0; 14101687Sjanga int totalbad = 0; /* Number of servers contacted unsuccessfully */ 14112830Sdjl short memerr = 0; /* Variable for tracking memory allocation */ 14124522Schinlong char *serverAddrType = NULL, **bindHost = NULL; 14132830Sdjl 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate if (conp == NULL || errorp == NULL || auth == NULL) 14160Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 14170Sstevel@tonic-gate *errorp = NULL; 14180Sstevel@tonic-gate *conp = NULL; 14194522Schinlong (void) memset(&sinfo, 0, sizeof (sinfo)); 14200Sstevel@tonic-gate 14214048Schinlong if ((wait4session == 0 || sessionTid != thr_self()) && 14224522Schinlong (id = findConnection(flags, serverAddr, auth, &con)) != -1) { 14230Sstevel@tonic-gate /* connection found in cache */ 14240Sstevel@tonic-gate #ifdef DEBUG 14252830Sdjl (void) fprintf(stderr, "tid= %d: connection found in " 14264522Schinlong "cache %d\n", thr_self(), id); 14270Sstevel@tonic-gate fflush(stderr); 14280Sstevel@tonic-gate #endif /* DEBUG */ 14290Sstevel@tonic-gate *cID = id; 14300Sstevel@tonic-gate *conp = con; 14310Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 14320Sstevel@tonic-gate } 14330Sstevel@tonic-gate 14344522Schinlong if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 14352830Sdjl serverAddrType = NS_CACHE_ADDR_HOSTNAME; 14364522Schinlong bindHost = &sinfo.serverFQDN; 14374522Schinlong } else { 14382830Sdjl serverAddrType = NS_CACHE_ADDR_IP; 14394522Schinlong bindHost = &sinfo.server; 14404522Schinlong } 14412830Sdjl 14420Sstevel@tonic-gate if (serverAddr) { 14435559Ssdussud /* 14445559Ssdussud * We're given the server address, just use it. 14455559Ssdussud * In case of sasl/GSSAPI, serverAddr would need to be a FQDN. 14465559Ssdussud * We assume this is the case for now. 14475559Ssdussud * 14485559Ssdussud * Only the server address fields of sinfo structure are filled 14495559Ssdussud * in since these are the only relevant data that we have. Other 14505559Ssdussud * fields of this structure (controls, saslMechanisms) are 14515559Ssdussud * kept to NULL. 14525559Ssdussud */ 14535559Ssdussud sinfo.server = strdup(serverAddr); 14545559Ssdussud if (sinfo.server == NULL) { 14555559Ssdussud return (NS_LDAP_MEMORY); 14565559Ssdussud } 14575559Ssdussud if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 14585559Ssdussud sinfo.serverFQDN = strdup(serverAddr); 14595559Ssdussud if (sinfo.serverFQDN == NULL) { 14605559Ssdussud free(sinfo.server); 14615559Ssdussud return (NS_LDAP_MEMORY); 14625559Ssdussud } 14632830Sdjl } 14644522Schinlong rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp, 14654522Schinlong fail_if_new_pwd_reqd, passwd_mgmt); 14660Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || rc == 14674522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 14680Sstevel@tonic-gate exit_rc = rc; 14690Sstevel@tonic-gate goto create_con; 14700Sstevel@tonic-gate } else { 14715559Ssdussud if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 14725559Ssdussud (void) snprintf(errmsg, sizeof (errmsg), 14735559Ssdussud "%s %s", gettext("makeConnection: " 14745559Ssdussud "failed to open connection using " 14755559Ssdussud "sasl/GSSAPI to"), *bindHost); 14765559Ssdussud } else { 14775559Ssdussud (void) snprintf(errmsg, sizeof (errmsg), 14785559Ssdussud "%s %s", gettext("makeConnection: " 14795559Ssdussud "failed to open connection to"), 14805559Ssdussud *bindHost); 14815559Ssdussud } 14825559Ssdussud syslog(LOG_ERR, "libsldap: %s", errmsg); 14835559Ssdussud __s_api_free_server_info(&sinfo); 14840Sstevel@tonic-gate return (rc); 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate /* No cached connection, create one */ 14890Sstevel@tonic-gate for (; ; ) { 14900Sstevel@tonic-gate if (host == NULL) 14910Sstevel@tonic-gate hReq = NS_CACHE_NEW; 14920Sstevel@tonic-gate else 14930Sstevel@tonic-gate hReq = NS_CACHE_NEXT; 14942830Sdjl rc = __s_api_requestServer(hReq, host, &sinfo, errorp, 14954522Schinlong serverAddrType); 14960Sstevel@tonic-gate if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) || 14974522Schinlong (host && (strcasecmp(host, sinfo.server) == 0))) { 14980Sstevel@tonic-gate /* Log the error */ 14990Sstevel@tonic-gate if (*errorp) { 15000Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 15010Sstevel@tonic-gate "%s: (%s)", gettext("makeConnection: " 15020Sstevel@tonic-gate "unable to make LDAP connection, " 15030Sstevel@tonic-gate "request for a server failed"), 15040Sstevel@tonic-gate (*errorp)->message); 15050Sstevel@tonic-gate syslog(LOG_ERR, "libsldap: %s", errmsg); 15060Sstevel@tonic-gate } 15070Sstevel@tonic-gate 15084522Schinlong __s_api_free_server_info(&sinfo); 15090Sstevel@tonic-gate if (host) 15100Sstevel@tonic-gate free(host); 15110Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 15120Sstevel@tonic-gate } 15130Sstevel@tonic-gate if (host) 15140Sstevel@tonic-gate free(host); 15150Sstevel@tonic-gate host = strdup(sinfo.server); 15160Sstevel@tonic-gate if (host == NULL) { 15174522Schinlong __s_api_free_server_info(&sinfo); 15180Sstevel@tonic-gate return (NS_LDAP_MEMORY); 15190Sstevel@tonic-gate } 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate /* check if server supports password management */ 15220Sstevel@tonic-gate passwd_mgmt = __s_api_contain_passwd_control_oid( 15234522Schinlong sinfo.controls); 15241179Svv149972 /* check if server supports password less account mgmt */ 15251179Svv149972 if (nopasswd_acct_mgmt && 15264522Schinlong !__s_api_contain_account_usable_control_oid( 15274522Schinlong sinfo.controls)) { 15281179Svv149972 syslog(LOG_WARNING, "libsldap: server %s does not " 15294522Schinlong "provide account information without password", 15304522Schinlong host); 15311179Svv149972 free(host); 15324522Schinlong __s_api_free_server_info(&sinfo); 15331179Svv149972 return (NS_LDAP_OP_FAILED); 15341179Svv149972 } 15350Sstevel@tonic-gate /* make the connection */ 15364522Schinlong rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp, 15374522Schinlong fail_if_new_pwd_reqd, passwd_mgmt); 15380Sstevel@tonic-gate /* if success, go to create connection structure */ 15390Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 15404522Schinlong rc == NS_LDAP_SUCCESS_WITH_INFO) { 15410Sstevel@tonic-gate exit_rc = rc; 15420Sstevel@tonic-gate break; 15430Sstevel@tonic-gate } 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate /* 15460Sstevel@tonic-gate * If not able to reach the server, inform the ldap 15470Sstevel@tonic-gate * cache manager that the server should be removed 15480Sstevel@tonic-gate * from its server list. Thus, the manager will not 15490Sstevel@tonic-gate * return this server on the next get-server request 15500Sstevel@tonic-gate * and will also reduce the server list refresh TTL, 15510Sstevel@tonic-gate * so that it will find out sooner when the server 15520Sstevel@tonic-gate * is up again. 15530Sstevel@tonic-gate */ 15540Sstevel@tonic-gate if (rc == NS_LDAP_INTERNAL && *errorp != NULL) { 15550Sstevel@tonic-gate if ((*errorp)->status == LDAP_CONNECT_ERROR || 15564522Schinlong (*errorp)->status == LDAP_SERVER_DOWN) { 15571687Sjanga /* Reset memory allocation error */ 15581687Sjanga memerr = 0; 15591687Sjanga /* 15601687Sjanga * We contacted a server that we could 15611687Sjanga * not either authenticate to or contact. 15621687Sjanga * If it is due to authentication, then 15631687Sjanga * we need to try the server again. So, 15641687Sjanga * do not remove the server yet, but 15651687Sjanga * add it to the bad server list. 15661687Sjanga * The caller routine will remove 15671687Sjanga * the servers if: 15681687Sjanga * a). A good server is found or 15691687Sjanga * b). All the possible methods 15701687Sjanga * are tried without finding 15711687Sjanga * a good server 15721687Sjanga */ 15731687Sjanga if (*badsrvrs == NULL) { 15744522Schinlong if (!(*badsrvrs = (char **)malloc 15754522Schinlong (sizeof (char *) * NUMTOMALLOC))) { 15764522Schinlong memerr = 1; 15774522Schinlong } 15781687Sjanga /* Allocate memory in chunks of NUMTOMALLOC */ 15791687Sjanga } else if ((totalbad % NUMTOMALLOC) == 15804522Schinlong NUMTOMALLOC - 1) { 15814522Schinlong char **tmpptr; 15824522Schinlong if (!(tmpptr = (char **)realloc( 15834522Schinlong *badsrvrs, 15841687Sjanga (sizeof (char *) * NUMTOMALLOC * 15851687Sjanga ((totalbad/NUMTOMALLOC) + 2))))) { 15864522Schinlong memerr = 1; 15874522Schinlong } else { 15884522Schinlong *badsrvrs = tmpptr; 15894522Schinlong } 1590493Ssdussud } 15911687Sjanga /* 15921687Sjanga * Store host only if there were no unsuccessful 15931687Sjanga * memory allocations above 15941687Sjanga */ 15951687Sjanga if (!memerr && 15961687Sjanga !((*badsrvrs)[totalbad++] = strdup(host))) { 15971687Sjanga memerr = 1; 15981687Sjanga totalbad--; 15991687Sjanga } 16001687Sjanga (*badsrvrs)[totalbad] = NULL; 1601493Ssdussud } 16020Sstevel@tonic-gate } 16030Sstevel@tonic-gate 16040Sstevel@tonic-gate /* else, cleanup and go for the next server */ 16054522Schinlong __s_api_free_server_info(&sinfo); 16064522Schinlong 16071687Sjanga /* Return if we had memory allocation errors */ 16081687Sjanga if (memerr) 16091687Sjanga return (NS_LDAP_MEMORY); 16100Sstevel@tonic-gate if (*errorp) { 16110Sstevel@tonic-gate /* 16120Sstevel@tonic-gate * If openConnection() failed due to 16130Sstevel@tonic-gate * password policy, or invalid credential, 16140Sstevel@tonic-gate * keep *errorp and exit 16150Sstevel@tonic-gate */ 16160Sstevel@tonic-gate if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD || 16170Sstevel@tonic-gate (*errorp)->status == LDAP_INVALID_CREDENTIALS) { 16180Sstevel@tonic-gate free(host); 16190Sstevel@tonic-gate return (rc); 16200Sstevel@tonic-gate } else { 16210Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 16220Sstevel@tonic-gate *errorp = NULL; 16230Sstevel@tonic-gate } 16240Sstevel@tonic-gate } 16250Sstevel@tonic-gate } 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate create_con: 16280Sstevel@tonic-gate /* we have created ld, setup con structure */ 16290Sstevel@tonic-gate if (host) 16300Sstevel@tonic-gate free(host); 16310Sstevel@tonic-gate if ((con = calloc(1, sizeof (Connection))) == NULL) { 16324522Schinlong __s_api_free_server_info(&sinfo); 16330Sstevel@tonic-gate /* 16340Sstevel@tonic-gate * If password control attached in **errorp, 16350Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 16360Sstevel@tonic-gate * free the error structure 16370Sstevel@tonic-gate */ 16380Sstevel@tonic-gate if (*errorp) { 16390Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 16400Sstevel@tonic-gate *errorp = NULL; 16410Sstevel@tonic-gate } 16425559Ssdussud (void) ldap_unbind(ld); 16430Sstevel@tonic-gate return (NS_LDAP_MEMORY); 16440Sstevel@tonic-gate } 16450Sstevel@tonic-gate 16464522Schinlong con->serverAddr = sinfo.server; /* Store original format */ 16474522Schinlong if (sinfo.serverFQDN != NULL) { 16484522Schinlong free(sinfo.serverFQDN); 16494522Schinlong sinfo.serverFQDN = NULL; 16504522Schinlong } 16510Sstevel@tonic-gate con->saslMechanisms = sinfo.saslMechanisms; 16520Sstevel@tonic-gate con->controls = sinfo.controls; 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate con->auth = __ns_ldap_dupAuth(auth); 16550Sstevel@tonic-gate if (con->auth == NULL) { 16565559Ssdussud (void) ldap_unbind(ld); 16575559Ssdussud freeConnection(con); 16580Sstevel@tonic-gate /* 16590Sstevel@tonic-gate * If password control attached in **errorp, 16600Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 16610Sstevel@tonic-gate * free the error structure 16620Sstevel@tonic-gate */ 16630Sstevel@tonic-gate if (*errorp) { 16640Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 16650Sstevel@tonic-gate *errorp = NULL; 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate return (NS_LDAP_MEMORY); 16680Sstevel@tonic-gate } 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate con->threadID = thr_self(); 16713387Schinlong con->pid = getpid(); 16722830Sdjl 16730Sstevel@tonic-gate con->ld = ld; 16740Sstevel@tonic-gate if ((id = addConnection(con)) == -1) { 16755559Ssdussud (void) ldap_unbind(ld); 16760Sstevel@tonic-gate freeConnection(con); 16770Sstevel@tonic-gate /* 16780Sstevel@tonic-gate * If password control attached in **errorp, 16790Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 16800Sstevel@tonic-gate * free the error structure 16810Sstevel@tonic-gate */ 16820Sstevel@tonic-gate if (*errorp) { 16830Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 16840Sstevel@tonic-gate *errorp = NULL; 16850Sstevel@tonic-gate } 16860Sstevel@tonic-gate return (NS_LDAP_MEMORY); 16870Sstevel@tonic-gate } 16880Sstevel@tonic-gate #ifdef DEBUG 16892830Sdjl (void) fprintf(stderr, "tid= %d: connection added into " 16904522Schinlong "cache %d\n", thr_self(), id); 16910Sstevel@tonic-gate fflush(stderr); 16920Sstevel@tonic-gate #endif /* DEBUG */ 16930Sstevel@tonic-gate *cID = id; 16940Sstevel@tonic-gate *conp = con; 16950Sstevel@tonic-gate return (exit_rc); 16960Sstevel@tonic-gate } 16970Sstevel@tonic-gate 16980Sstevel@tonic-gate /* 16990Sstevel@tonic-gate * Return the specified connection to the pool. If necessary 17000Sstevel@tonic-gate * delete the connection. 17010Sstevel@tonic-gate */ 17020Sstevel@tonic-gate 17030Sstevel@tonic-gate static void 17040Sstevel@tonic-gate _DropConnection(ConnectionID cID, int flag, int fini) 17050Sstevel@tonic-gate { 17060Sstevel@tonic-gate Connection *cp; 17070Sstevel@tonic-gate int id; 17082830Sdjl int use_lock = !fini; 1709*6722Smj162486 struct timeval zerotime; 1710*6722Smj162486 LDAPMessage *res; 1711*6722Smj162486 1712*6722Smj162486 zerotime.tv_sec = zerotime.tv_usec = 0L; 1713*6722Smj162486 17142830Sdjl #ifdef DEBUG 17152830Sdjl thread_t t = thr_self(); 17162830Sdjl #endif /* DEBUG */ 17170Sstevel@tonic-gate 17180Sstevel@tonic-gate id = cID - CONID_OFFSET; 17190Sstevel@tonic-gate if (id < 0 || id >= sessionPoolSize) 17200Sstevel@tonic-gate return; 17210Sstevel@tonic-gate #ifdef DEBUG 17222830Sdjl (void) fprintf(stderr, "tid= %d: " 17234522Schinlong "Dropping connection cID=%d flag=0x%x, fini = %d\n", 17244522Schinlong t, cID, flag, fini); 17250Sstevel@tonic-gate fflush(stderr); 17260Sstevel@tonic-gate #endif /* DEBUG */ 17272830Sdjl if (use_lock) 17282830Sdjl (void) rw_wrlock(&sessionPoolLock); 17290Sstevel@tonic-gate 17300Sstevel@tonic-gate cp = sessionPool[id]; 17310Sstevel@tonic-gate /* sanity check before removing */ 17324048Schinlong if (!cp || (!fini && !cp->shared && !cp->usedBit)) { 17332830Sdjl #ifdef DEBUG 17342830Sdjl if (cp == NULL) 17352830Sdjl (void) fprintf(stderr, "tid= %d: no " 17364522Schinlong "need to remove (fini = %d, cp = %p)\n", t, 17374522Schinlong fini, cp); 17382830Sdjl else 17392830Sdjl (void) fprintf(stderr, "tid= %d: no " 17404522Schinlong "need to remove (fini = %d, cp = %p, shared = %d)" 17414522Schinlong "\n", t, fini, cp, cp->shared); 17422830Sdjl fflush(stderr); 17432830Sdjl #endif /* DEBUG */ 17442830Sdjl if (use_lock) 17452830Sdjl (void) rw_unlock(&sessionPoolLock); 17460Sstevel@tonic-gate return; 17470Sstevel@tonic-gate } 17480Sstevel@tonic-gate 17490Sstevel@tonic-gate if (!fini && 17504522Schinlong ((flag & NS_LDAP_NEW_CONN) == 0) && !cp->notAvail && 17516072Smj162486 ((flag & NS_LDAP_KEEP_CONN) || __s_api_nscd_proc() || 17526072Smj162486 __s_api_peruser_proc())) { 17532830Sdjl #ifdef DEBUG 17542830Sdjl (void) fprintf(stderr, "tid= %d: keep alive (fini = %d " 17554522Schinlong "shared = %d)\n", t, fini, cp->shared); 17562830Sdjl #endif /* DEBUG */ 17570Sstevel@tonic-gate /* release Connection (keep alive) */ 17582830Sdjl if (cp->shared) 17592830Sdjl cp->shared--; 17600Sstevel@tonic-gate cp->usedBit = B_FALSE; 17610Sstevel@tonic-gate cp->threadID = 0; /* unmark the threadID */ 1762*6722Smj162486 /* 1763*6722Smj162486 * Do sanity cleanup of remaining results if connection is not 1764*6722Smj162486 * shared by any requests. 1765*6722Smj162486 */ 1766*6722Smj162486 if (cp->shared <= 0) { 1767*6722Smj162486 while (ldap_result(cp->ld, LDAP_RES_ANY, LDAP_MSG_ALL, 1768*6722Smj162486 &zerotime, &res) > 0) { 1769*6722Smj162486 if (res != NULL) 1770*6722Smj162486 (void) ldap_msgfree(res); 1771*6722Smj162486 } 1772*6722Smj162486 } 17732830Sdjl if (use_lock) 17742830Sdjl (void) rw_unlock(&sessionPoolLock); 17750Sstevel@tonic-gate } else { 17760Sstevel@tonic-gate /* delete Connection (disconnect) */ 17772830Sdjl if (cp->shared > 0) { 17782830Sdjl #ifdef DEBUG 17792830Sdjl (void) fprintf(stderr, "tid= %d: Connection no " 17804522Schinlong "longer available (fini = %d, shared = %d)\n", 17814522Schinlong t, fini, cp->shared); 17822830Sdjl fflush(stderr); 17832830Sdjl #endif /* DEBUG */ 17842830Sdjl cp->shared--; 17853387Schinlong /* 17863387Schinlong * Mark this connection not available and decrement 17873387Schinlong * sharedConnNumber. There could be multiple threads 17883387Schinlong * sharing this connection so decrement 17893387Schinlong * sharedConnNumber only once per connection. 17903387Schinlong */ 17913387Schinlong if (cp->notAvail == 0) { 17923387Schinlong cp->notAvail = 1; 17933387Schinlong (void) mutex_lock(&sharedConnNumberLock); 17943387Schinlong sharedConnNumber--; 17953387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 17963387Schinlong } 17972830Sdjl } 17982830Sdjl 17992830Sdjl if (cp->shared <= 0) { 18002830Sdjl #ifdef DEBUG 18012830Sdjl (void) fprintf(stderr, "tid= %d: unbind " 18024522Schinlong "(fini = %d, shared = %d)\n", 18034522Schinlong t, fini, cp->shared); 18042830Sdjl fflush(stderr); 18052830Sdjl #endif /* DEBUG */ 18062830Sdjl sessionPool[id] = NULL; 18072830Sdjl (void) ldap_unbind(cp->ld); 18082830Sdjl freeConnection(cp); 18092830Sdjl } 18102830Sdjl 18112830Sdjl if (use_lock) 18122830Sdjl (void) rw_unlock(&sessionPoolLock); 18130Sstevel@tonic-gate } 18140Sstevel@tonic-gate } 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate void 18170Sstevel@tonic-gate DropConnection(ConnectionID cID, int flag) 18180Sstevel@tonic-gate { 18190Sstevel@tonic-gate _DropConnection(cID, flag, 0); 18200Sstevel@tonic-gate } 18210Sstevel@tonic-gate 18220Sstevel@tonic-gate /* 18230Sstevel@tonic-gate * This routine is called after a bind operation is 18240Sstevel@tonic-gate * done in openConnection() to process the password 18250Sstevel@tonic-gate * management information, if any. 18260Sstevel@tonic-gate * 18270Sstevel@tonic-gate * Input: 18280Sstevel@tonic-gate * bind_type: "simple" or "sasl/DIGEST-MD5" 18290Sstevel@tonic-gate * ldaprc : ldap rc from the ldap bind operation 18300Sstevel@tonic-gate * controls : controls returned by the server 18310Sstevel@tonic-gate * errmsg : error message from the server 18320Sstevel@tonic-gate * fail_if_new_pwd_reqd: 18330Sstevel@tonic-gate * flag indicating if connection should be open 18340Sstevel@tonic-gate * when password needs to change immediately 18350Sstevel@tonic-gate * passwd_mgmt: 18360Sstevel@tonic-gate * flag indicating if server supports password 18370Sstevel@tonic-gate * policy/management 18380Sstevel@tonic-gate * 18390Sstevel@tonic-gate * Output : ns_ldap_error structure, which may contain 18400Sstevel@tonic-gate * password status and number of seconds until 18410Sstevel@tonic-gate * expired 18420Sstevel@tonic-gate * 18430Sstevel@tonic-gate * return rc: 18440Sstevel@tonic-gate * NS_LDAP_EXTERNAL: error, connection should not open 18450Sstevel@tonic-gate * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached 18460Sstevel@tonic-gate * NS_LDAP_SUCCESS: OK to open connection 18470Sstevel@tonic-gate * 18480Sstevel@tonic-gate */ 18490Sstevel@tonic-gate 18500Sstevel@tonic-gate static int 18510Sstevel@tonic-gate process_pwd_mgmt(char *bind_type, int ldaprc, 18520Sstevel@tonic-gate LDAPControl **controls, 18530Sstevel@tonic-gate char *errmsg, ns_ldap_error_t **errorp, 18540Sstevel@tonic-gate int fail_if_new_pwd_reqd, 18550Sstevel@tonic-gate int passwd_mgmt) 18560Sstevel@tonic-gate { 18570Sstevel@tonic-gate char errstr[MAXERROR]; 18580Sstevel@tonic-gate LDAPControl **ctrl = NULL; 18590Sstevel@tonic-gate int exit_rc; 18600Sstevel@tonic-gate ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD; 18610Sstevel@tonic-gate int sec_until_exp = 0; 18620Sstevel@tonic-gate 18630Sstevel@tonic-gate /* 18640Sstevel@tonic-gate * errmsg may be an empty string, 18650Sstevel@tonic-gate * even if ldaprc is LDAP_SUCCESS, 18660Sstevel@tonic-gate * free the empty string if that's the case 18670Sstevel@tonic-gate */ 18680Sstevel@tonic-gate if (errmsg && 18694522Schinlong (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) { 18700Sstevel@tonic-gate ldap_memfree(errmsg); 18710Sstevel@tonic-gate errmsg = NULL; 18720Sstevel@tonic-gate } 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate if (ldaprc != LDAP_SUCCESS) { 18750Sstevel@tonic-gate /* 18760Sstevel@tonic-gate * try to map ldap rc and error message to 18770Sstevel@tonic-gate * a password status 18780Sstevel@tonic-gate */ 18790Sstevel@tonic-gate if (errmsg) { 18800Sstevel@tonic-gate if (passwd_mgmt) 18810Sstevel@tonic-gate pwd_status = 18824522Schinlong __s_api_set_passwd_status( 18834522Schinlong ldaprc, errmsg); 18840Sstevel@tonic-gate ldap_memfree(errmsg); 18850Sstevel@tonic-gate } 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 18884522Schinlong gettext("openConnection: " 18894522Schinlong "%s bind failed " 18904522Schinlong "- %s"), bind_type, ldap_err2string(ldaprc)); 18910Sstevel@tonic-gate 18920Sstevel@tonic-gate if (pwd_status != NS_PASSWD_GOOD) { 18930Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 18944522Schinlong ldaprc, strdup(errstr), 18954522Schinlong pwd_status, 0, NULL); 18960Sstevel@tonic-gate } else { 18970Sstevel@tonic-gate MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr), 18984522Schinlong NULL); 18990Sstevel@tonic-gate } 19000Sstevel@tonic-gate if (controls) 19010Sstevel@tonic-gate ldap_controls_free(controls); 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 19040Sstevel@tonic-gate } 19050Sstevel@tonic-gate 19060Sstevel@tonic-gate /* 19070Sstevel@tonic-gate * ldaprc is LDAP_SUCCESS, 19080Sstevel@tonic-gate * process the password management controls, if any 19090Sstevel@tonic-gate */ 19100Sstevel@tonic-gate exit_rc = NS_LDAP_SUCCESS; 19110Sstevel@tonic-gate if (controls && passwd_mgmt) { 19120Sstevel@tonic-gate /* 19130Sstevel@tonic-gate * The control with the OID 19140Sstevel@tonic-gate * 2.16.840.1.113730.3.4.4 (or 19150Sstevel@tonic-gate * LDAP_CONTROL_PWEXPIRED, as defined 19160Sstevel@tonic-gate * in the ldap.h header file) is the 19170Sstevel@tonic-gate * expired password control. 19180Sstevel@tonic-gate * 19190Sstevel@tonic-gate * This control is used if the server 19200Sstevel@tonic-gate * is configured to require users to 19210Sstevel@tonic-gate * change their passwords when first 19220Sstevel@tonic-gate * logging in and whenever the 19230Sstevel@tonic-gate * passwords are reset. 19240Sstevel@tonic-gate * 19250Sstevel@tonic-gate * If the user is logging in for the 19260Sstevel@tonic-gate * first time or if the user's 19270Sstevel@tonic-gate * password has been reset, the 19280Sstevel@tonic-gate * server sends this control to 19290Sstevel@tonic-gate * indicate that the client needs to 19300Sstevel@tonic-gate * change the password immediately. 19310Sstevel@tonic-gate * 19320Sstevel@tonic-gate * At this point, the only operation 19330Sstevel@tonic-gate * that the client can perform is to 19340Sstevel@tonic-gate * change the user's password. If the 19350Sstevel@tonic-gate * client requests any other LDAP 19360Sstevel@tonic-gate * operation, the server sends back 19370Sstevel@tonic-gate * an LDAP_UNWILLING_TO_PERFORM 19380Sstevel@tonic-gate * result code with an expired 19390Sstevel@tonic-gate * password control. 19400Sstevel@tonic-gate * 19410Sstevel@tonic-gate * The control with the OID 19420Sstevel@tonic-gate * 2.16.840.1.113730.3.4.5 (or 19430Sstevel@tonic-gate * LDAP_CONTROL_PWEXPIRING, as 19440Sstevel@tonic-gate * defined in the ldap.h header file) 19450Sstevel@tonic-gate * is the password expiration warning 19460Sstevel@tonic-gate * control. 19470Sstevel@tonic-gate * 19480Sstevel@tonic-gate * This control is used if the server 19490Sstevel@tonic-gate * is configured to expire user 19500Sstevel@tonic-gate * passwords after a certain amount 19510Sstevel@tonic-gate * of time. 19520Sstevel@tonic-gate * 19530Sstevel@tonic-gate * The server sends this control back 19540Sstevel@tonic-gate * to the client if the client binds 19550Sstevel@tonic-gate * using a password that will soon 19560Sstevel@tonic-gate * expire. The ldctl_value field of 19570Sstevel@tonic-gate * the LDAPControl structure 19580Sstevel@tonic-gate * specifies the number of seconds 19590Sstevel@tonic-gate * before the password will expire. 19600Sstevel@tonic-gate */ 19610Sstevel@tonic-gate for (ctrl = controls; *ctrl; ctrl++) { 19620Sstevel@tonic-gate 19630Sstevel@tonic-gate if (strcmp((*ctrl)->ldctl_oid, 19644522Schinlong LDAP_CONTROL_PWEXPIRED) == 0) { 19650Sstevel@tonic-gate /* 19660Sstevel@tonic-gate * if the caller wants this bind 19670Sstevel@tonic-gate * to fail, set up the error info. 19680Sstevel@tonic-gate * If call to this function is 19690Sstevel@tonic-gate * for searching the LDAP directory, 19700Sstevel@tonic-gate * e.g., __ns_ldap_list(), 19710Sstevel@tonic-gate * there's really no sense to 19720Sstevel@tonic-gate * let a connection open and 19730Sstevel@tonic-gate * then fail immediately afterward 19740Sstevel@tonic-gate * on the LDAP search operation with 19750Sstevel@tonic-gate * the LDAP_UNWILLING_TO_PERFORM rc 19760Sstevel@tonic-gate */ 19770Sstevel@tonic-gate pwd_status = 19784522Schinlong NS_PASSWD_CHANGE_NEEDED; 19790Sstevel@tonic-gate if (fail_if_new_pwd_reqd) { 19800Sstevel@tonic-gate (void) snprintf(errstr, 19814522Schinlong sizeof (errstr), 19824522Schinlong gettext( 19834522Schinlong "openConnection: " 19844522Schinlong "%s bind " 19854522Schinlong "failed " 19864522Schinlong "- password " 19874522Schinlong "expired. It " 19884522Schinlong " needs to change " 19894522Schinlong "immediately!"), 19904522Schinlong bind_type); 19910Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 19924522Schinlong LDAP_SUCCESS, 19934522Schinlong strdup(errstr), 19944522Schinlong pwd_status, 19954522Schinlong 0, 19964522Schinlong NULL); 19970Sstevel@tonic-gate exit_rc = NS_LDAP_INTERNAL; 19980Sstevel@tonic-gate } else { 19990Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 20004522Schinlong LDAP_SUCCESS, 20014522Schinlong NULL, 20024522Schinlong pwd_status, 20034522Schinlong 0, 20044522Schinlong NULL); 20050Sstevel@tonic-gate exit_rc = 20064522Schinlong NS_LDAP_SUCCESS_WITH_INFO; 20070Sstevel@tonic-gate } 20080Sstevel@tonic-gate break; 20090Sstevel@tonic-gate } else if (strcmp((*ctrl)->ldctl_oid, 20104522Schinlong LDAP_CONTROL_PWEXPIRING) == 0) { 20110Sstevel@tonic-gate pwd_status = 20124522Schinlong NS_PASSWD_ABOUT_TO_EXPIRE; 20130Sstevel@tonic-gate if ((*ctrl)-> 20144522Schinlong ldctl_value.bv_len > 0 && 20154522Schinlong (*ctrl)-> 20164522Schinlong ldctl_value.bv_val) 20170Sstevel@tonic-gate sec_until_exp = 20184522Schinlong atoi((*ctrl)-> 20194522Schinlong ldctl_value.bv_val); 20200Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 20214522Schinlong LDAP_SUCCESS, 20224522Schinlong NULL, 20234522Schinlong pwd_status, 20244522Schinlong sec_until_exp, 20254522Schinlong NULL); 20260Sstevel@tonic-gate exit_rc = 20274522Schinlong NS_LDAP_SUCCESS_WITH_INFO; 20280Sstevel@tonic-gate break; 20290Sstevel@tonic-gate } 20300Sstevel@tonic-gate } 20310Sstevel@tonic-gate } 20320Sstevel@tonic-gate 20330Sstevel@tonic-gate if (controls) 20340Sstevel@tonic-gate ldap_controls_free(controls); 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate return (exit_rc); 20370Sstevel@tonic-gate } 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate static int 20400Sstevel@tonic-gate ldap_in_hosts_switch() 20410Sstevel@tonic-gate { 20420Sstevel@tonic-gate enum __nsw_parse_err pserr; 20430Sstevel@tonic-gate struct __nsw_switchconfig *conf; 20440Sstevel@tonic-gate struct __nsw_lookup *lkp; 20450Sstevel@tonic-gate const char *name; 20460Sstevel@tonic-gate int found = 0; 20470Sstevel@tonic-gate 20480Sstevel@tonic-gate conf = __nsw_getconfig("hosts", &pserr); 20490Sstevel@tonic-gate if (conf == NULL) { 20500Sstevel@tonic-gate return (-1); 20510Sstevel@tonic-gate } 20520Sstevel@tonic-gate 20530Sstevel@tonic-gate /* check for skip and count other backends */ 20540Sstevel@tonic-gate for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 20550Sstevel@tonic-gate name = lkp->service_name; 20560Sstevel@tonic-gate if (strcmp(name, "ldap") == 0) { 20570Sstevel@tonic-gate found = 1; 20580Sstevel@tonic-gate break; 20590Sstevel@tonic-gate } 20600Sstevel@tonic-gate } 20610Sstevel@tonic-gate __nsw_freeconfig(conf); 20620Sstevel@tonic-gate return (found); 20630Sstevel@tonic-gate } 20640Sstevel@tonic-gate 20650Sstevel@tonic-gate static int 20660Sstevel@tonic-gate openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, 20670Sstevel@tonic-gate int timeoutSec, ns_ldap_error_t **errorp, 20680Sstevel@tonic-gate int fail_if_new_pwd_reqd, int passwd_mgmt) 20690Sstevel@tonic-gate { 20700Sstevel@tonic-gate LDAP *ld = NULL; 20710Sstevel@tonic-gate char *binddn, *passwd; 20720Sstevel@tonic-gate char *digest_md5_name; 20730Sstevel@tonic-gate const char *s; 20740Sstevel@tonic-gate int ldapVersion = LDAP_VERSION3; 20750Sstevel@tonic-gate int derefOption = LDAP_DEREF_ALWAYS; 20760Sstevel@tonic-gate int zero = 0; 20770Sstevel@tonic-gate int rc; 20780Sstevel@tonic-gate char errstr[MAXERROR]; 20790Sstevel@tonic-gate int errnum = 0; 20800Sstevel@tonic-gate LDAPMessage *resultMsg; 20810Sstevel@tonic-gate int msgId; 20822830Sdjl int useSSL = 0, port = 0; 20830Sstevel@tonic-gate struct timeval tv; 20840Sstevel@tonic-gate AuthType_t bindType; 20850Sstevel@tonic-gate int timeoutMilliSec = timeoutSec * 1000; 20860Sstevel@tonic-gate struct berval cred; 20870Sstevel@tonic-gate char *sslServerAddr; 20880Sstevel@tonic-gate char *s1; 20892830Sdjl char *errmsg, *end = NULL; 20900Sstevel@tonic-gate LDAPControl **controls; 20912830Sdjl int pwd_rc, min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF; 20922830Sdjl ns_sasl_cb_param_t sasl_param; 20930Sstevel@tonic-gate 20940Sstevel@tonic-gate *errorp = NULL; 20950Sstevel@tonic-gate *ldp = NULL; 20960Sstevel@tonic-gate 20970Sstevel@tonic-gate switch (auth->auth.type) { 20980Sstevel@tonic-gate case NS_LDAP_AUTH_NONE: 20990Sstevel@tonic-gate case NS_LDAP_AUTH_SIMPLE: 21000Sstevel@tonic-gate case NS_LDAP_AUTH_SASL: 21010Sstevel@tonic-gate bindType = auth->auth.type; 21020Sstevel@tonic-gate break; 21030Sstevel@tonic-gate case NS_LDAP_AUTH_TLS: 21040Sstevel@tonic-gate useSSL = 1; 21050Sstevel@tonic-gate switch (auth->auth.tlstype) { 21060Sstevel@tonic-gate case NS_LDAP_TLS_NONE: 21070Sstevel@tonic-gate bindType = NS_LDAP_AUTH_NONE; 21080Sstevel@tonic-gate break; 21090Sstevel@tonic-gate case NS_LDAP_TLS_SIMPLE: 21100Sstevel@tonic-gate bindType = NS_LDAP_AUTH_SIMPLE; 21110Sstevel@tonic-gate break; 21120Sstevel@tonic-gate case NS_LDAP_TLS_SASL: 21130Sstevel@tonic-gate bindType = NS_LDAP_AUTH_SASL; 21140Sstevel@tonic-gate break; 21150Sstevel@tonic-gate default: 21160Sstevel@tonic-gate (void) sprintf(errstr, 21170Sstevel@tonic-gate gettext("openConnection: unsupported " 21184522Schinlong "TLS authentication method " 21194522Schinlong "(%d)"), auth->auth.tlstype); 21200Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, 21214522Schinlong LDAP_AUTH_METHOD_NOT_SUPPORTED, 21224522Schinlong strdup(errstr), NULL); 21230Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 21240Sstevel@tonic-gate } 21250Sstevel@tonic-gate break; 21260Sstevel@tonic-gate default: 21270Sstevel@tonic-gate (void) sprintf(errstr, 21284522Schinlong gettext("openConnection: unsupported " 21294522Schinlong "authentication method (%d)"), auth->auth.type); 21300Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, 21314522Schinlong LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 21324522Schinlong NULL); 21330Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 21340Sstevel@tonic-gate } 21350Sstevel@tonic-gate 21360Sstevel@tonic-gate if (useSSL) { 21370Sstevel@tonic-gate const char *hostcertpath; 21380Sstevel@tonic-gate char *alloc_hcp = NULL; 21390Sstevel@tonic-gate #ifdef DEBUG 21402830Sdjl (void) fprintf(stderr, "tid= %d: +++TLS transport\n", 21414522Schinlong thr_self()); 21420Sstevel@tonic-gate #endif /* DEBUG */ 21432333Sjanga 21442333Sjanga if (prldap_set_session_option(NULL, NULL, 21452333Sjanga PRLDAP_OPT_IO_MAX_TIMEOUT, 21462333Sjanga timeoutMilliSec) != LDAP_SUCCESS) { 21472333Sjanga (void) snprintf(errstr, sizeof (errstr), 21484522Schinlong gettext("openConnection: failed to initialize " 21494522Schinlong "TLS security")); 21502333Sjanga MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 21514522Schinlong strdup(errstr), NULL); 21522333Sjanga return (NS_LDAP_INTERNAL); 21532333Sjanga } 21542333Sjanga 21550Sstevel@tonic-gate hostcertpath = auth->hostcertpath; 21560Sstevel@tonic-gate if (hostcertpath == NULL) { 21570Sstevel@tonic-gate alloc_hcp = __s_get_hostcertpath(); 21580Sstevel@tonic-gate hostcertpath = alloc_hcp; 21590Sstevel@tonic-gate } 21600Sstevel@tonic-gate 21610Sstevel@tonic-gate if (hostcertpath == NULL) 21620Sstevel@tonic-gate return (NS_LDAP_MEMORY); 21630Sstevel@tonic-gate 21640Sstevel@tonic-gate if ((rc = ldapssl_client_init(hostcertpath, NULL)) < 0) { 21650Sstevel@tonic-gate if (alloc_hcp) 21660Sstevel@tonic-gate free(alloc_hcp); 21670Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 21684522Schinlong gettext("openConnection: failed to initialize " 21694522Schinlong "TLS security (%s)"), 21704522Schinlong ldapssl_err2string(rc)); 21710Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 21724522Schinlong strdup(errstr), NULL); 21730Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 21740Sstevel@tonic-gate } 21750Sstevel@tonic-gate if (alloc_hcp) 21760Sstevel@tonic-gate free(alloc_hcp); 21770Sstevel@tonic-gate 21780Sstevel@tonic-gate /* determine if the host name contains a port number */ 21790Sstevel@tonic-gate s = strchr(serverAddr, ']'); /* skip over ipv6 addr */ 21800Sstevel@tonic-gate if (s == NULL) 21810Sstevel@tonic-gate s = serverAddr; 21820Sstevel@tonic-gate s = strchr(s, ':'); 21830Sstevel@tonic-gate if (s != NULL) { 21840Sstevel@tonic-gate /* 21850Sstevel@tonic-gate * If we do get a port number, we will try stripping 21860Sstevel@tonic-gate * it. At present, referrals will always have a 21870Sstevel@tonic-gate * port number. 21880Sstevel@tonic-gate */ 21890Sstevel@tonic-gate sslServerAddr = strdup(serverAddr); 21900Sstevel@tonic-gate if (sslServerAddr == NULL) 21910Sstevel@tonic-gate return (NS_LDAP_MEMORY); 21920Sstevel@tonic-gate s1 = strrchr(sslServerAddr, ':'); 21930Sstevel@tonic-gate if (s1 != NULL) 21940Sstevel@tonic-gate *s1 = '\0'; 21950Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 21960Sstevel@tonic-gate gettext("openConnection: cannot use tls with %s. " 21974522Schinlong "Trying %s"), 21984522Schinlong serverAddr, sslServerAddr); 21990Sstevel@tonic-gate syslog(LOG_ERR, "libsldap: %s", errstr); 22000Sstevel@tonic-gate } else 22010Sstevel@tonic-gate sslServerAddr = (char *)serverAddr; 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate ld = ldapssl_init(sslServerAddr, LDAPS_PORT, 1); 22040Sstevel@tonic-gate 22050Sstevel@tonic-gate if (sslServerAddr != serverAddr) 22060Sstevel@tonic-gate free(sslServerAddr); 22070Sstevel@tonic-gate 22080Sstevel@tonic-gate if (ld == NULL || 22090Sstevel@tonic-gate ldapssl_install_gethostbyaddr(ld, "ldap") != 0) { 22100Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 22114522Schinlong gettext("openConnection: failed to connect " 22124522Schinlong "using TLS (%s)"), strerror(errno)); 22130Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 22144522Schinlong strdup(errstr), NULL); 22150Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 22160Sstevel@tonic-gate } 22170Sstevel@tonic-gate } else { 22180Sstevel@tonic-gate #ifdef DEBUG 22192830Sdjl (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n", 22204522Schinlong thr_self()); 22210Sstevel@tonic-gate #endif /* DEBUG */ 22222830Sdjl port = LDAP_PORT; 22232830Sdjl if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI && 22244522Schinlong (end = strchr(serverAddr, ':')) != NULL) { 22252830Sdjl /* 22262830Sdjl * The IP is converted to hostname so it's a 22272830Sdjl * hostname:port up to this point. 22282830Sdjl * 22292830Sdjl * libldap passes hostname:port to the sasl layer. 22302830Sdjl * The ldap service principal is constructed as 22312830Sdjl * ldap/hostname:port@REALM. Kerberos authentication 22322830Sdjl * will fail. So it needs to be parsed to construct 22332830Sdjl * a valid principal ldap/hostname@REALM. 22342830Sdjl * 22352830Sdjl * For useSSL case above, it already parses port so 22362830Sdjl * no need to parse serverAddr 22372830Sdjl */ 22382830Sdjl *end = '\0'; 22392830Sdjl port = atoi(end + 1); 22402830Sdjl } 22412830Sdjl 22422830Sdjl /* Warning message IF cannot connect to host(s) */ 22432830Sdjl if ((ld = ldap_init((char *)serverAddr, port)) == NULL) { 22440Sstevel@tonic-gate char *p = strerror(errno); 22450Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 22464522Schinlong strdup(p), NULL); 22472830Sdjl if (end) 22482830Sdjl *end = ':'; 22490Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 22500Sstevel@tonic-gate } else { 22512830Sdjl if (end) 22522830Sdjl *end = ':'; 22530Sstevel@tonic-gate /* check and avoid gethostname recursion */ 22540Sstevel@tonic-gate if (ldap_in_hosts_switch() > 0 && 22554522Schinlong ! __s_api_isipv4((char *)serverAddr) && 22564522Schinlong ! __s_api_isipv6((char *)serverAddr)) { 22570Sstevel@tonic-gate /* host: ldap - found, attempt to recover */ 22580Sstevel@tonic-gate if (ldap_set_option(ld, LDAP_X_OPT_DNS_SKIPDB, 22594522Schinlong "ldap") != 0) { 22604522Schinlong (void) snprintf(errstr, sizeof (errstr), 22612830Sdjl gettext("openConnection: " 22622830Sdjl "unrecoverable gethostname " 22632830Sdjl "recursion detected " 22642830Sdjl "in /etc/nsswitch.conf")); 22654522Schinlong MKERROR(LOG_WARNING, *errorp, 22662830Sdjl LDAP_CONNECT_ERROR, 22672830Sdjl strdup(errstr), NULL); 22684522Schinlong (void) ldap_unbind(ld); 22694522Schinlong return (NS_LDAP_INTERNAL); 22700Sstevel@tonic-gate } 22710Sstevel@tonic-gate } 22720Sstevel@tonic-gate } 22730Sstevel@tonic-gate } 22740Sstevel@tonic-gate 22752830Sdjl ns_setup_mt_conn_and_tsd(ld); 22760Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); 22770Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 22780Sstevel@tonic-gate /* 22790Sstevel@tonic-gate * set LDAP_OPT_REFERRALS to OFF. 22800Sstevel@tonic-gate * This library will handle the referral itself 22810Sstevel@tonic-gate * based on API flags or configuration file 22820Sstevel@tonic-gate * specification. If this option is not set 22830Sstevel@tonic-gate * to OFF, libldap will never pass the 22840Sstevel@tonic-gate * referral info up to this library 22850Sstevel@tonic-gate */ 22860Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 22870Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 22880Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 22890Sstevel@tonic-gate /* setup TCP/IP connect timeout */ 22900Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 22914522Schinlong &timeoutMilliSec); 22920Sstevel@tonic-gate /* retry if LDAP I/O was interrupted */ 22930Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 22940Sstevel@tonic-gate 22950Sstevel@tonic-gate switch (bindType) { 22960Sstevel@tonic-gate case NS_LDAP_AUTH_NONE: 22970Sstevel@tonic-gate #ifdef DEBUG 22982830Sdjl (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n", 22994522Schinlong thr_self()); 23000Sstevel@tonic-gate #endif /* DEBUG */ 23010Sstevel@tonic-gate break; 23020Sstevel@tonic-gate case NS_LDAP_AUTH_SIMPLE: 23030Sstevel@tonic-gate binddn = auth->cred.unix_cred.userID; 23040Sstevel@tonic-gate passwd = auth->cred.unix_cred.passwd; 23050Sstevel@tonic-gate if (passwd == NULL || *passwd == '\0' || 23060Sstevel@tonic-gate binddn == NULL || *binddn == '\0') { 23070Sstevel@tonic-gate (void) sprintf(errstr, gettext("openConnection: " 23084522Schinlong "missing credentials for Simple bind")); 23090Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, 23104522Schinlong strdup(errstr), NULL); 23110Sstevel@tonic-gate (void) ldap_unbind(ld); 23120Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23130Sstevel@tonic-gate } 23140Sstevel@tonic-gate 23150Sstevel@tonic-gate #ifdef DEBUG 23162830Sdjl (void) fprintf(stderr, "tid= %d: +++Simple bind\n", 23174522Schinlong thr_self()); 23180Sstevel@tonic-gate #endif /* DEBUG */ 23190Sstevel@tonic-gate msgId = ldap_simple_bind(ld, binddn, passwd); 23200Sstevel@tonic-gate 23210Sstevel@tonic-gate if (msgId == -1) { 23220Sstevel@tonic-gate (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 23234522Schinlong (void *)&errnum); 23240Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 23254522Schinlong gettext("openConnection: simple bind failed " 23264522Schinlong "- %s"), ldap_err2string(errnum)); 23270Sstevel@tonic-gate (void) ldap_unbind(ld); 23280Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 23294522Schinlong NULL); 23300Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23310Sstevel@tonic-gate } 23320Sstevel@tonic-gate 23330Sstevel@tonic-gate tv.tv_sec = timeoutSec; 23340Sstevel@tonic-gate tv.tv_usec = 0; 23350Sstevel@tonic-gate rc = ldap_result(ld, msgId, 0, &tv, &resultMsg); 23360Sstevel@tonic-gate 23370Sstevel@tonic-gate if ((rc == -1) || (rc == 0)) { 23380Sstevel@tonic-gate (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 23394522Schinlong (void *)&errnum); 23400Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 23414522Schinlong gettext("openConnection: simple bind failed " 23424522Schinlong "- %s"), ldap_err2string(errnum)); 23430Sstevel@tonic-gate (void) ldap_msgfree(resultMsg); 23440Sstevel@tonic-gate (void) ldap_unbind(ld); 23450Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 23464522Schinlong NULL); 23470Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23480Sstevel@tonic-gate } 23490Sstevel@tonic-gate 23500Sstevel@tonic-gate /* 23510Sstevel@tonic-gate * get ldaprc, controls, and error msg 23520Sstevel@tonic-gate */ 23530Sstevel@tonic-gate rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 23544522Schinlong &errmsg, NULL, &controls, 1); 23550Sstevel@tonic-gate 23560Sstevel@tonic-gate if (rc != LDAP_SUCCESS) { 23570Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 23584522Schinlong gettext("openConnection: simple bind failed " 23594522Schinlong "- unable to parse result")); 23600Sstevel@tonic-gate (void) ldap_unbind(ld); 23610Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 23624522Schinlong strdup(errstr), NULL); 23630Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23640Sstevel@tonic-gate } 23650Sstevel@tonic-gate 23660Sstevel@tonic-gate /* process the password management info, if any */ 23670Sstevel@tonic-gate pwd_rc = process_pwd_mgmt("simple", 23684522Schinlong errnum, controls, errmsg, 23694522Schinlong errorp, 23704522Schinlong fail_if_new_pwd_reqd, 23714522Schinlong passwd_mgmt); 23720Sstevel@tonic-gate 23730Sstevel@tonic-gate if (pwd_rc == NS_LDAP_INTERNAL) { 23740Sstevel@tonic-gate (void) ldap_unbind(ld); 23750Sstevel@tonic-gate return (pwd_rc); 23760Sstevel@tonic-gate } 23770Sstevel@tonic-gate 23780Sstevel@tonic-gate if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) { 23790Sstevel@tonic-gate *ldp = ld; 23800Sstevel@tonic-gate return (pwd_rc); 23810Sstevel@tonic-gate } 23820Sstevel@tonic-gate 23830Sstevel@tonic-gate break; 23840Sstevel@tonic-gate case NS_LDAP_AUTH_SASL: 23852830Sdjl if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE && 23864522Schinlong auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 23870Sstevel@tonic-gate (void) sprintf(errstr, 23884522Schinlong gettext("openConnection: SASL options are " 23894522Schinlong "not supported (%d) for non-GSSAPI sasl bind"), 23904522Schinlong auth->auth.saslopt); 23910Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, 23924522Schinlong LDAP_AUTH_METHOD_NOT_SUPPORTED, 23934522Schinlong strdup(errstr), NULL); 23940Sstevel@tonic-gate (void) ldap_unbind(ld); 23950Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23960Sstevel@tonic-gate } 23972830Sdjl if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 23982830Sdjl binddn = auth->cred.unix_cred.userID; 23992830Sdjl passwd = auth->cred.unix_cred.passwd; 24002830Sdjl if (passwd == NULL || *passwd == '\0' || 24014522Schinlong binddn == NULL || *binddn == '\0') { 24022830Sdjl (void) sprintf(errstr, 24034522Schinlong gettext("openConnection: missing " 24044522Schinlong "credentials for SASL bind")); 24052830Sdjl MKERROR(LOG_WARNING, *errorp, 24064522Schinlong LDAP_INVALID_CREDENTIALS, 24074522Schinlong strdup(errstr), NULL); 24082830Sdjl (void) ldap_unbind(ld); 24092830Sdjl return (NS_LDAP_INTERNAL); 24102830Sdjl } 24112830Sdjl cred.bv_val = passwd; 24122830Sdjl cred.bv_len = strlen(passwd); 24130Sstevel@tonic-gate } 24140Sstevel@tonic-gate 24150Sstevel@tonic-gate switch (auth->auth.saslmech) { 24160Sstevel@tonic-gate case NS_LDAP_SASL_CRAM_MD5: 24170Sstevel@tonic-gate /* 24180Sstevel@tonic-gate * NOTE: if iDS changes to support cram_md5, 24190Sstevel@tonic-gate * please add password management code here. 24200Sstevel@tonic-gate * Since ldap_sasl_cram_md5_bind_s does not 24210Sstevel@tonic-gate * return anything that could be used to 24220Sstevel@tonic-gate * extract the ldap rc/errmsg/control to 24230Sstevel@tonic-gate * determine if bind failed due to password 24240Sstevel@tonic-gate * policy, a new cram_md5_bind API will need 24250Sstevel@tonic-gate * to be introduced. See 24260Sstevel@tonic-gate * ldap_x_sasl_digest_md5_bind() and case 24270Sstevel@tonic-gate * NS_LDAP_SASL_DIGEST_MD5 below for details. 24280Sstevel@tonic-gate */ 24290Sstevel@tonic-gate if ((rc = ldap_sasl_cram_md5_bind_s(ld, binddn, 24304522Schinlong &cred, NULL, NULL)) != LDAP_SUCCESS) { 24310Sstevel@tonic-gate (void) ldap_get_option(ld, 24324522Schinlong LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 24330Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 24344522Schinlong gettext("openConnection: " 24354522Schinlong "sasl/CRAM-MD5 bind failed - %s"), 24364522Schinlong ldap_err2string(errnum)); 24370Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, errnum, 24384522Schinlong strdup(errstr), NULL); 24390Sstevel@tonic-gate (void) ldap_unbind(ld); 24400Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 24410Sstevel@tonic-gate } 24420Sstevel@tonic-gate break; 24430Sstevel@tonic-gate case NS_LDAP_SASL_DIGEST_MD5: 24440Sstevel@tonic-gate digest_md5_name = malloc(strlen(binddn) + 5); 24450Sstevel@tonic-gate /* 5 = strlen("dn: ") + 1 */ 24460Sstevel@tonic-gate if (digest_md5_name == NULL) { 24470Sstevel@tonic-gate (void) ldap_unbind(ld); 24480Sstevel@tonic-gate return (NS_LDAP_MEMORY); 24490Sstevel@tonic-gate } 24500Sstevel@tonic-gate (void) strcpy(digest_md5_name, "dn: "); 24510Sstevel@tonic-gate (void) strcat(digest_md5_name, binddn); 24520Sstevel@tonic-gate 24530Sstevel@tonic-gate tv.tv_sec = timeoutSec; 24540Sstevel@tonic-gate tv.tv_usec = 0; 24550Sstevel@tonic-gate rc = ldap_x_sasl_digest_md5_bind(ld, 24564522Schinlong digest_md5_name, &cred, NULL, NULL, 24574522Schinlong &tv, &resultMsg); 24580Sstevel@tonic-gate 24590Sstevel@tonic-gate if (resultMsg == NULL) { 24600Sstevel@tonic-gate free(digest_md5_name); 24610Sstevel@tonic-gate (void) ldap_get_option(ld, 24624522Schinlong LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 24630Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 24644522Schinlong gettext("openConnection: " 24654522Schinlong "DIGEST-MD5 bind failed - %s"), 24664522Schinlong ldap_err2string(errnum)); 24670Sstevel@tonic-gate (void) ldap_unbind(ld); 24680Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, errnum, 24694522Schinlong strdup(errstr), NULL); 24700Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 24710Sstevel@tonic-gate } 24720Sstevel@tonic-gate 24730Sstevel@tonic-gate /* 24740Sstevel@tonic-gate * get ldaprc, controls, and error msg 24750Sstevel@tonic-gate */ 24760Sstevel@tonic-gate rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 24774522Schinlong &errmsg, NULL, &controls, 1); 24780Sstevel@tonic-gate 24790Sstevel@tonic-gate if (rc != LDAP_SUCCESS) { 24800Sstevel@tonic-gate free(digest_md5_name); 24810Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 24824522Schinlong gettext("openConnection: " 24834522Schinlong "DIGEST-MD5 bind failed " 24844522Schinlong "- unable to parse result")); 24850Sstevel@tonic-gate (void) ldap_unbind(ld); 24860Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 24874522Schinlong strdup(errstr), NULL); 24880Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 24890Sstevel@tonic-gate } 24900Sstevel@tonic-gate 24910Sstevel@tonic-gate /* process the password management info, if any */ 24920Sstevel@tonic-gate pwd_rc = process_pwd_mgmt("sasl/DIGEST-MD5", 24934522Schinlong errnum, controls, errmsg, 24944522Schinlong errorp, 24954522Schinlong fail_if_new_pwd_reqd, 24964522Schinlong passwd_mgmt); 24970Sstevel@tonic-gate 24980Sstevel@tonic-gate if (pwd_rc == NS_LDAP_INTERNAL) { 24990Sstevel@tonic-gate free(digest_md5_name); 25000Sstevel@tonic-gate (void) ldap_unbind(ld); 25010Sstevel@tonic-gate return (pwd_rc); 25020Sstevel@tonic-gate } 25030Sstevel@tonic-gate 25040Sstevel@tonic-gate if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) { 25050Sstevel@tonic-gate *ldp = ld; 25060Sstevel@tonic-gate return (pwd_rc); 25070Sstevel@tonic-gate } 25080Sstevel@tonic-gate 25090Sstevel@tonic-gate free(digest_md5_name); 25100Sstevel@tonic-gate break; 25112830Sdjl case NS_LDAP_SASL_GSSAPI: 25122830Sdjl if (sasl_gssapi_inited == 0) { 25132830Sdjl rc = __s_api_sasl_gssapi_init(); 25142830Sdjl if (rc != NS_LDAP_SUCCESS) { 25152830Sdjl (void) snprintf(errstr, sizeof (errstr), 25164522Schinlong gettext("openConnection: " 25174522Schinlong "GSSAPI initialization " 25184522Schinlong "failed")); 25192830Sdjl (void) ldap_unbind(ld); 25202830Sdjl MKERROR(LOG_WARNING, *errorp, rc, 25214522Schinlong strdup(errstr), NULL); 25222830Sdjl return (rc); 25232830Sdjl } 25242830Sdjl } 25252830Sdjl (void) memset(&sasl_param, 0, 25264522Schinlong sizeof (ns_sasl_cb_param_t)); 25272830Sdjl sasl_param.authid = NULL; 25282830Sdjl sasl_param.authzid = ""; 25292830Sdjl (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN, 25304522Schinlong (void *)&min_ssf); 25312830Sdjl (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX, 25324522Schinlong (void *)&max_ssf); 25332830Sdjl 25342830Sdjl rc = ldap_sasl_interactive_bind_s( 25354522Schinlong ld, NULL, "GSSAPI", 25364522Schinlong NULL, NULL, LDAP_SASL_INTERACTIVE, 25374522Schinlong __s_api_sasl_bind_callback, 25384522Schinlong &sasl_param); 25392830Sdjl 25402830Sdjl if (rc != LDAP_SUCCESS) { 25412830Sdjl (void) snprintf(errstr, sizeof (errstr), 25424522Schinlong gettext("openConnection: " 25434522Schinlong "GSSAPI bind failed " 25444522Schinlong "- %d %s"), rc, ldap_err2string(rc)); 25452830Sdjl (void) ldap_unbind(ld); 25462830Sdjl MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 25474522Schinlong strdup(errstr), NULL); 25482830Sdjl return (NS_LDAP_INTERNAL); 25492830Sdjl } 25502830Sdjl 25512830Sdjl break; 25520Sstevel@tonic-gate default: 25530Sstevel@tonic-gate (void) ldap_unbind(ld); 25540Sstevel@tonic-gate (void) sprintf(errstr, 25554522Schinlong gettext("openConnection: unsupported SASL " 25564522Schinlong "mechanism (%d)"), auth->auth.saslmech); 25570Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, 25584522Schinlong LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 25594522Schinlong NULL); 25600Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 25610Sstevel@tonic-gate } 25620Sstevel@tonic-gate } 25630Sstevel@tonic-gate 25640Sstevel@tonic-gate *ldp = ld; 25650Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 25660Sstevel@tonic-gate } 25670Sstevel@tonic-gate 25680Sstevel@tonic-gate /* 25690Sstevel@tonic-gate * FUNCTION: __s_api_getDefaultAuth 25700Sstevel@tonic-gate * 25710Sstevel@tonic-gate * Constructs a credential for authentication using the config module. 25720Sstevel@tonic-gate * 25730Sstevel@tonic-gate * RETURN VALUES: 25740Sstevel@tonic-gate * 25750Sstevel@tonic-gate * NS_LDAP_SUCCESS If successful 25760Sstevel@tonic-gate * NS_LDAP_CONFIG If there are any config errors. 25770Sstevel@tonic-gate * NS_LDAP_MEMORY Memory errors. 25780Sstevel@tonic-gate * NS_LDAP_OP_FAILED If there are no more authentication methods so can 25790Sstevel@tonic-gate * not build a new authp. 25800Sstevel@tonic-gate * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the 25810Sstevel@tonic-gate * necessary fields of a cred for a given auth method 25820Sstevel@tonic-gate * are not provided. 25830Sstevel@tonic-gate * INPUT: 25840Sstevel@tonic-gate * 25850Sstevel@tonic-gate * cLevel Currently requested credential level to be tried 25860Sstevel@tonic-gate * 25870Sstevel@tonic-gate * aMethod Currently requested authentication method to be tried 25880Sstevel@tonic-gate * 25890Sstevel@tonic-gate * OUTPUT: 25900Sstevel@tonic-gate * 25910Sstevel@tonic-gate * authp authentication method to use. 25920Sstevel@tonic-gate */ 25930Sstevel@tonic-gate static int 25940Sstevel@tonic-gate __s_api_getDefaultAuth( 25950Sstevel@tonic-gate int *cLevel, 25960Sstevel@tonic-gate ns_auth_t *aMethod, 25970Sstevel@tonic-gate ns_cred_t **authp) 25980Sstevel@tonic-gate { 25990Sstevel@tonic-gate void **paramVal = NULL; 26000Sstevel@tonic-gate char *modparamVal = NULL; 26010Sstevel@tonic-gate int getUid = 0; 26020Sstevel@tonic-gate int getPasswd = 0; 26030Sstevel@tonic-gate int getCertpath = 0; 26040Sstevel@tonic-gate int rc = 0; 26050Sstevel@tonic-gate ns_ldap_error_t *errorp = NULL; 26060Sstevel@tonic-gate 26070Sstevel@tonic-gate #ifdef DEBUG 26080Sstevel@tonic-gate (void) fprintf(stderr, "__s_api_getDefaultAuth START\n"); 26090Sstevel@tonic-gate #endif 26100Sstevel@tonic-gate 26110Sstevel@tonic-gate if (aMethod == NULL) { 26120Sstevel@tonic-gate /* Require an Auth */ 26130Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 26140Sstevel@tonic-gate 26150Sstevel@tonic-gate } 26160Sstevel@tonic-gate /* 26172830Sdjl * credential level "self" can work with auth method sasl/GSSAPI only 26180Sstevel@tonic-gate */ 26192830Sdjl if (cLevel && *cLevel == NS_LDAP_CRED_SELF && 26204522Schinlong aMethod->saslmech != NS_LDAP_SASL_GSSAPI) 26210Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 26220Sstevel@tonic-gate 26230Sstevel@tonic-gate *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); 26240Sstevel@tonic-gate if ((*authp) == NULL) 26250Sstevel@tonic-gate return (NS_LDAP_MEMORY); 26260Sstevel@tonic-gate 26270Sstevel@tonic-gate (*authp)->auth = *aMethod; 26280Sstevel@tonic-gate 26290Sstevel@tonic-gate switch (aMethod->type) { 26300Sstevel@tonic-gate case NS_LDAP_AUTH_NONE: 26310Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 26320Sstevel@tonic-gate case NS_LDAP_AUTH_SIMPLE: 26330Sstevel@tonic-gate getUid++; 26340Sstevel@tonic-gate getPasswd++; 26350Sstevel@tonic-gate break; 26360Sstevel@tonic-gate case NS_LDAP_AUTH_SASL: 26370Sstevel@tonic-gate if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 26380Sstevel@tonic-gate (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) { 26390Sstevel@tonic-gate getUid++; 26400Sstevel@tonic-gate getPasswd++; 26412830Sdjl } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) { 26420Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26430Sstevel@tonic-gate *authp = NULL; 26440Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 26450Sstevel@tonic-gate } 26460Sstevel@tonic-gate break; 26470Sstevel@tonic-gate case NS_LDAP_AUTH_TLS: 26480Sstevel@tonic-gate if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) || 26490Sstevel@tonic-gate ((aMethod->tlstype == NS_LDAP_TLS_SASL) && 26500Sstevel@tonic-gate ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 26510Sstevel@tonic-gate (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) { 26520Sstevel@tonic-gate getUid++; 26530Sstevel@tonic-gate getPasswd++; 26540Sstevel@tonic-gate getCertpath++; 26550Sstevel@tonic-gate } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) { 26560Sstevel@tonic-gate getCertpath++; 26570Sstevel@tonic-gate } else { 26580Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26590Sstevel@tonic-gate *authp = NULL; 26600Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 26610Sstevel@tonic-gate } 26620Sstevel@tonic-gate break; 26630Sstevel@tonic-gate } 26640Sstevel@tonic-gate 26650Sstevel@tonic-gate if (getUid) { 26660Sstevel@tonic-gate paramVal = NULL; 26670Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, 26684522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 26690Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26700Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 26710Sstevel@tonic-gate *authp = NULL; 26720Sstevel@tonic-gate return (rc); 26730Sstevel@tonic-gate } 26740Sstevel@tonic-gate 26750Sstevel@tonic-gate if (paramVal == NULL || *paramVal == NULL) { 26760Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26770Sstevel@tonic-gate *authp = NULL; 26780Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 26790Sstevel@tonic-gate } 26800Sstevel@tonic-gate 26810Sstevel@tonic-gate (*authp)->cred.unix_cred.userID = strdup((char *)*paramVal); 26820Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 26830Sstevel@tonic-gate if ((*authp)->cred.unix_cred.userID == NULL) { 26840Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26850Sstevel@tonic-gate *authp = NULL; 26860Sstevel@tonic-gate return (NS_LDAP_MEMORY); 26870Sstevel@tonic-gate } 26880Sstevel@tonic-gate } 26890Sstevel@tonic-gate if (getPasswd) { 26900Sstevel@tonic-gate paramVal = NULL; 26910Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, 26924522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 26930Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26940Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 26950Sstevel@tonic-gate *authp = NULL; 26960Sstevel@tonic-gate return (rc); 26970Sstevel@tonic-gate } 26980Sstevel@tonic-gate 26990Sstevel@tonic-gate if (paramVal == NULL || *paramVal == NULL) { 27000Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 27010Sstevel@tonic-gate *authp = NULL; 27020Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 27030Sstevel@tonic-gate } 27040Sstevel@tonic-gate 27050Sstevel@tonic-gate modparamVal = dvalue((char *)*paramVal); 27060Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 27070Sstevel@tonic-gate if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) { 27080Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 27090Sstevel@tonic-gate if (modparamVal != NULL) 27100Sstevel@tonic-gate free(modparamVal); 27110Sstevel@tonic-gate *authp = NULL; 27120Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 27130Sstevel@tonic-gate } 27140Sstevel@tonic-gate 27150Sstevel@tonic-gate (*authp)->cred.unix_cred.passwd = modparamVal; 27160Sstevel@tonic-gate } 27170Sstevel@tonic-gate if (getCertpath) { 27180Sstevel@tonic-gate paramVal = NULL; 27190Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 27204522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 27210Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 27220Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 27230Sstevel@tonic-gate *authp = NULL; 27240Sstevel@tonic-gate return (rc); 27250Sstevel@tonic-gate } 27260Sstevel@tonic-gate 27270Sstevel@tonic-gate if (paramVal == NULL || *paramVal == NULL) { 27280Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 27290Sstevel@tonic-gate *authp = NULL; 27300Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 27310Sstevel@tonic-gate } 27320Sstevel@tonic-gate 27330Sstevel@tonic-gate (*authp)->hostcertpath = strdup((char *)*paramVal); 27340Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 27350Sstevel@tonic-gate if ((*authp)->hostcertpath == NULL) { 27360Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 27370Sstevel@tonic-gate *authp = NULL; 27380Sstevel@tonic-gate return (NS_LDAP_MEMORY); 27390Sstevel@tonic-gate } 27400Sstevel@tonic-gate } 27410Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 27420Sstevel@tonic-gate } 27430Sstevel@tonic-gate 27440Sstevel@tonic-gate /* 27450Sstevel@tonic-gate * FUNCTION: __s_api_getConnection 27460Sstevel@tonic-gate * 27470Sstevel@tonic-gate * Bind to the specified server or one from the server 27480Sstevel@tonic-gate * list and return the pointer. 27490Sstevel@tonic-gate * 27500Sstevel@tonic-gate * This function can rebind or not (NS_LDAP_HARD), it can require a 27510Sstevel@tonic-gate * credential or bind anonymously 27520Sstevel@tonic-gate * 27530Sstevel@tonic-gate * This function follows the DUA configuration schema algorithm 27540Sstevel@tonic-gate * 27550Sstevel@tonic-gate * RETURN VALUES: 27560Sstevel@tonic-gate * 27570Sstevel@tonic-gate * NS_LDAP_SUCCESS A connection was made successfully. 27580Sstevel@tonic-gate * NS_LDAP_SUCCESS_WITH_INFO 27590Sstevel@tonic-gate * A connection was made successfully, but with 27600Sstevel@tonic-gate * password management info in *errorp 27610Sstevel@tonic-gate * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function. 27620Sstevel@tonic-gate * NS_LDAP_CONFIG If there are any config errors. 27630Sstevel@tonic-gate * NS_LDAP_MEMORY Memory errors. 27640Sstevel@tonic-gate * NS_LDAP_INTERNAL If there was a ldap error. 27650Sstevel@tonic-gate * 27660Sstevel@tonic-gate * INPUT: 27670Sstevel@tonic-gate * 27680Sstevel@tonic-gate * server Bind to this LDAP server only 27690Sstevel@tonic-gate * flags If NS_LDAP_HARD is set function will not return until it has 27700Sstevel@tonic-gate * a connection unless there is a authentication problem. 27710Sstevel@tonic-gate * If NS_LDAP_NEW_CONN is set the function must force a new 27720Sstevel@tonic-gate * connection to be created 27730Sstevel@tonic-gate * If NS_LDAP_KEEP_CONN is set the connection is to be kept open 27740Sstevel@tonic-gate * auth Credentials for bind. This could be NULL in which case 27750Sstevel@tonic-gate * a default cred built from the config module is used. 27760Sstevel@tonic-gate * sessionId cookie that points to a previous session 27770Sstevel@tonic-gate * fail_if_new_pwd_reqd 27780Sstevel@tonic-gate * a flag indicating this function should fail if the passwd 27790Sstevel@tonic-gate * in auth needs to change immediately 27801179Svv149972 * nopasswd_acct_mgmt 27811179Svv149972 * a flag indicating that makeConnection should check before 27821179Svv149972 * binding if server supports LDAP V3 password less 27831179Svv149972 * account management 27840Sstevel@tonic-gate * 27850Sstevel@tonic-gate * OUTPUT: 27860Sstevel@tonic-gate * 27870Sstevel@tonic-gate * session pointer to a session with connection information 27880Sstevel@tonic-gate * errorp Set if there are any INTERNAL, or CONFIG error. 27890Sstevel@tonic-gate */ 27900Sstevel@tonic-gate int 27910Sstevel@tonic-gate __s_api_getConnection( 27920Sstevel@tonic-gate const char *server, 27930Sstevel@tonic-gate const int flags, 27940Sstevel@tonic-gate const ns_cred_t *cred, /* credentials for bind */ 27950Sstevel@tonic-gate ConnectionID *sessionId, 27960Sstevel@tonic-gate Connection **session, 27970Sstevel@tonic-gate ns_ldap_error_t **errorp, 27981179Svv149972 int fail_if_new_pwd_reqd, 27991179Svv149972 int nopasswd_acct_mgmt) 28000Sstevel@tonic-gate { 28010Sstevel@tonic-gate char errmsg[MAXERROR]; 28020Sstevel@tonic-gate ns_auth_t **aMethod = NULL; 28030Sstevel@tonic-gate ns_auth_t **aNext = NULL; 28040Sstevel@tonic-gate int **cLevel = NULL; 28050Sstevel@tonic-gate int **cNext = NULL; 28060Sstevel@tonic-gate int timeoutSec = NS_DEFAULT_BIND_TIMEOUT; 28070Sstevel@tonic-gate int rc; 28080Sstevel@tonic-gate Connection *con = NULL; 28090Sstevel@tonic-gate int sec = 1; 28100Sstevel@tonic-gate ns_cred_t *authp = NULL; 28110Sstevel@tonic-gate ns_cred_t anon; 28122830Sdjl int version = NS_LDAP_V2, self_gssapi_only = 0; 28130Sstevel@tonic-gate void **paramVal = NULL; 28141687Sjanga char **badSrvrs = NULL; /* List of problem hostnames */ 28150Sstevel@tonic-gate 28160Sstevel@tonic-gate if ((session == NULL) || (sessionId == NULL)) { 28170Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 28180Sstevel@tonic-gate } 28190Sstevel@tonic-gate *session = NULL; 28200Sstevel@tonic-gate 28210Sstevel@tonic-gate /* if we already have a session id try to reuse connection */ 28220Sstevel@tonic-gate if (*sessionId > 0) { 28230Sstevel@tonic-gate rc = findConnectionById(flags, cred, *sessionId, &con); 28240Sstevel@tonic-gate if (rc == *sessionId && con) { 28250Sstevel@tonic-gate *session = con; 28260Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 28270Sstevel@tonic-gate } 28280Sstevel@tonic-gate *sessionId = 0; 28290Sstevel@tonic-gate } 28300Sstevel@tonic-gate 28310Sstevel@tonic-gate /* get profile version number */ 28320Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, 28334522Schinlong ¶mVal, errorp)) != NS_LDAP_SUCCESS) 28340Sstevel@tonic-gate return (rc); 28350Sstevel@tonic-gate if (paramVal == NULL) { 28360Sstevel@tonic-gate (void) sprintf(errmsg, gettext("getConnection: no file " 28374522Schinlong "version")); 28380Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg), 28394522Schinlong NS_LDAP_CONFIG); 28400Sstevel@tonic-gate return (NS_LDAP_CONFIG); 28410Sstevel@tonic-gate } 28420Sstevel@tonic-gate if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0) 28430Sstevel@tonic-gate version = NS_LDAP_V1; 28440Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)¶mVal); 28450Sstevel@tonic-gate 28460Sstevel@tonic-gate /* Get the bind timeout value */ 28470Sstevel@tonic-gate (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp); 28480Sstevel@tonic-gate if (paramVal != NULL && *paramVal != NULL) { 28490Sstevel@tonic-gate timeoutSec = **((int **)paramVal); 28500Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 28510Sstevel@tonic-gate } 28520Sstevel@tonic-gate if (*errorp) 28530Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 28540Sstevel@tonic-gate 28550Sstevel@tonic-gate if (cred == NULL) { 28560Sstevel@tonic-gate /* Get the authentication method list */ 28570Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, 28584522Schinlong (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS) 28590Sstevel@tonic-gate return (rc); 28600Sstevel@tonic-gate if (aMethod == NULL) { 28610Sstevel@tonic-gate aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *)); 28620Sstevel@tonic-gate if (aMethod == NULL) 28630Sstevel@tonic-gate return (NS_LDAP_MEMORY); 28640Sstevel@tonic-gate aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t)); 28650Sstevel@tonic-gate if (aMethod[0] == NULL) { 28660Sstevel@tonic-gate free(aMethod); 28670Sstevel@tonic-gate return (NS_LDAP_MEMORY); 28680Sstevel@tonic-gate } 28690Sstevel@tonic-gate if (version == NS_LDAP_V1) 28700Sstevel@tonic-gate (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE; 28710Sstevel@tonic-gate else { 28720Sstevel@tonic-gate (aMethod[0])->type = NS_LDAP_AUTH_SASL; 28730Sstevel@tonic-gate (aMethod[0])->saslmech = 28744522Schinlong NS_LDAP_SASL_DIGEST_MD5; 28750Sstevel@tonic-gate (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE; 28760Sstevel@tonic-gate } 28770Sstevel@tonic-gate } 28780Sstevel@tonic-gate 28790Sstevel@tonic-gate /* Get the credential level list */ 28800Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P, 28814522Schinlong (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) { 28820Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&aMethod); 28830Sstevel@tonic-gate return (rc); 28840Sstevel@tonic-gate } 28850Sstevel@tonic-gate if (cLevel == NULL) { 28860Sstevel@tonic-gate cLevel = (int **)calloc(2, sizeof (int *)); 28870Sstevel@tonic-gate if (cLevel == NULL) 28880Sstevel@tonic-gate return (NS_LDAP_MEMORY); 28890Sstevel@tonic-gate cLevel[0] = (int *)calloc(1, sizeof (int)); 28900Sstevel@tonic-gate if (cLevel[0] == NULL) 28910Sstevel@tonic-gate return (NS_LDAP_MEMORY); 28920Sstevel@tonic-gate if (version == NS_LDAP_V1) 28930Sstevel@tonic-gate *(cLevel[0]) = NS_LDAP_CRED_PROXY; 28940Sstevel@tonic-gate else 28950Sstevel@tonic-gate *(cLevel[0]) = NS_LDAP_CRED_ANON; 28960Sstevel@tonic-gate } 28970Sstevel@tonic-gate } 28980Sstevel@tonic-gate 28990Sstevel@tonic-gate /* setup the anon credential for anonymous connection */ 29000Sstevel@tonic-gate (void) memset(&anon, 0, sizeof (ns_cred_t)); 29010Sstevel@tonic-gate anon.auth.type = NS_LDAP_AUTH_NONE; 29020Sstevel@tonic-gate 29030Sstevel@tonic-gate for (; ; ) { 29040Sstevel@tonic-gate if (cred != NULL) { 29050Sstevel@tonic-gate /* using specified auth method */ 29060Sstevel@tonic-gate rc = makeConnection(&con, server, cred, 29074522Schinlong sessionId, timeoutSec, errorp, 29084522Schinlong fail_if_new_pwd_reqd, 29094522Schinlong nopasswd_acct_mgmt, flags, &badSrvrs); 29104387Smj162486 /* not using bad server if credentials were supplied */ 29114387Smj162486 if (badSrvrs && *badSrvrs) { 29124387Smj162486 __s_api_free2dArray(badSrvrs); 29134387Smj162486 badSrvrs = NULL; 29144387Smj162486 } 29150Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 29164522Schinlong rc == NS_LDAP_SUCCESS_WITH_INFO) { 29170Sstevel@tonic-gate *session = con; 29180Sstevel@tonic-gate break; 29190Sstevel@tonic-gate } 29200Sstevel@tonic-gate } else { 29212830Sdjl self_gssapi_only = __s_api_self_gssapi_only_get(); 29220Sstevel@tonic-gate /* for every cred level */ 29230Sstevel@tonic-gate for (cNext = cLevel; *cNext != NULL; cNext++) { 29242830Sdjl if (self_gssapi_only && 29254522Schinlong **cNext != NS_LDAP_CRED_SELF) 29262830Sdjl continue; 29270Sstevel@tonic-gate if (**cNext == NS_LDAP_CRED_ANON) { 29281687Sjanga /* 29291687Sjanga * make connection anonymously 29301687Sjanga * Free the down server list before 29311687Sjanga * looping through 29321687Sjanga */ 29331687Sjanga if (badSrvrs && *badSrvrs) { 29341687Sjanga __s_api_free2dArray(badSrvrs); 29351687Sjanga badSrvrs = NULL; 29361687Sjanga } 29370Sstevel@tonic-gate rc = makeConnection(&con, server, &anon, 29384522Schinlong sessionId, timeoutSec, errorp, 29394522Schinlong fail_if_new_pwd_reqd, 29404522Schinlong nopasswd_acct_mgmt, flags, 29414522Schinlong &badSrvrs); 29420Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 29434522Schinlong rc == 29444522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 29450Sstevel@tonic-gate *session = con; 29460Sstevel@tonic-gate goto done; 29470Sstevel@tonic-gate } 29480Sstevel@tonic-gate continue; 29490Sstevel@tonic-gate } 29500Sstevel@tonic-gate /* for each cred level */ 29510Sstevel@tonic-gate for (aNext = aMethod; *aNext != NULL; aNext++) { 29522830Sdjl if (self_gssapi_only && 29534522Schinlong (*aNext)->saslmech != 29544522Schinlong NS_LDAP_SASL_GSSAPI) 29552830Sdjl continue; 29562830Sdjl /* 29572830Sdjl * self coexists with sasl/GSSAPI only 29582830Sdjl * and non-self coexists with non-gssapi 29592830Sdjl * only 29602830Sdjl */ 29612830Sdjl if ((**cNext == NS_LDAP_CRED_SELF && 29624522Schinlong (*aNext)->saslmech != 29634522Schinlong NS_LDAP_SASL_GSSAPI) || 29644522Schinlong (**cNext != NS_LDAP_CRED_SELF && 29654522Schinlong (*aNext)->saslmech == 29664522Schinlong NS_LDAP_SASL_GSSAPI)) 29672830Sdjl continue; 29680Sstevel@tonic-gate /* make connection and authenticate */ 29690Sstevel@tonic-gate /* with default credentials */ 29700Sstevel@tonic-gate authp = NULL; 29710Sstevel@tonic-gate rc = __s_api_getDefaultAuth(*cNext, 29724522Schinlong *aNext, &authp); 29730Sstevel@tonic-gate if (rc != NS_LDAP_SUCCESS) { 29740Sstevel@tonic-gate continue; 29750Sstevel@tonic-gate } 29761687Sjanga /* 29771687Sjanga * Free the down server list before 29781687Sjanga * looping through 29791687Sjanga */ 29801687Sjanga if (badSrvrs && *badSrvrs) { 29811687Sjanga __s_api_free2dArray(badSrvrs); 29821687Sjanga badSrvrs = NULL; 29831687Sjanga } 29840Sstevel@tonic-gate rc = makeConnection(&con, server, authp, 29854522Schinlong sessionId, timeoutSec, errorp, 29864522Schinlong fail_if_new_pwd_reqd, 29874522Schinlong nopasswd_acct_mgmt, flags, 29884522Schinlong &badSrvrs); 29890Sstevel@tonic-gate (void) __ns_ldap_freeCred(&authp); 29900Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 29914522Schinlong rc == 29924522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 29930Sstevel@tonic-gate *session = con; 29940Sstevel@tonic-gate goto done; 29950Sstevel@tonic-gate } 29960Sstevel@tonic-gate } 29970Sstevel@tonic-gate } 29980Sstevel@tonic-gate } 29990Sstevel@tonic-gate if (flags & NS_LDAP_HARD) { 30000Sstevel@tonic-gate if (sec < LDAPMAXHARDLOOKUPTIME) 30010Sstevel@tonic-gate sec *= 2; 30020Sstevel@tonic-gate _sleep(sec); 30030Sstevel@tonic-gate } else { 30040Sstevel@tonic-gate break; 30050Sstevel@tonic-gate } 30060Sstevel@tonic-gate } 30070Sstevel@tonic-gate 30080Sstevel@tonic-gate done: 30092830Sdjl /* 30102830Sdjl * If unable to get a connection, and this is 30112830Sdjl * the thread opening the shared connection, 30122830Sdjl * unlock the session mutex and let other 30132830Sdjl * threads try to get their own connection. 30142830Sdjl */ 30152830Sdjl if (wait4session != 0 && sessionTid == thr_self()) { 30162830Sdjl wait4session = 0; 30172830Sdjl sessionTid = 0; 30182830Sdjl #ifdef DEBUG 30192830Sdjl (void) fprintf(stderr, "tid= %d: __s_api_getConnection: " 30204522Schinlong "unlocking sessionLock \n", thr_self()); 30212830Sdjl fflush(stderr); 30222830Sdjl #endif /* DEBUG */ 30232830Sdjl (void) mutex_unlock(&sessionLock); 30242830Sdjl } 30252830Sdjl if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) { 30262830Sdjl /* 30272830Sdjl * self_gssapi_only is true but no self/sasl/gssapi is 30282830Sdjl * configured 30292830Sdjl */ 30302830Sdjl rc = NS_LDAP_CONFIG; 30312830Sdjl } 30322830Sdjl 30330Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&aMethod); 30340Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&cLevel); 30351687Sjanga 30361687Sjanga if (badSrvrs && *badSrvrs) { 30371687Sjanga /* 30381687Sjanga * At this point, either we have a successful 30391687Sjanga * connection or exhausted all the possible auths. 30401687Sjanga * and creds. Mark the problem servers as down 30411687Sjanga * so that the problem servers are not contacted 30421687Sjanga * again until the refresh_ttl expires. 30431687Sjanga */ 30441687Sjanga (void) __s_api_removeBadServers(badSrvrs); 30451687Sjanga __s_api_free2dArray(badSrvrs); 30461687Sjanga } 30470Sstevel@tonic-gate return (rc); 30480Sstevel@tonic-gate } 30490Sstevel@tonic-gate 30500Sstevel@tonic-gate #pragma fini(_free_sessionPool) 30510Sstevel@tonic-gate static void 30520Sstevel@tonic-gate _free_sessionPool() 30530Sstevel@tonic-gate { 30540Sstevel@tonic-gate int id; 30550Sstevel@tonic-gate 30562830Sdjl (void) rw_wrlock(&sessionPoolLock); 30570Sstevel@tonic-gate if (sessionPool != NULL) { 30580Sstevel@tonic-gate for (id = 0; id < sessionPoolSize; id++) 30590Sstevel@tonic-gate _DropConnection(id + CONID_OFFSET, 0, 1); 30600Sstevel@tonic-gate free(sessionPool); 30610Sstevel@tonic-gate sessionPool = NULL; 30620Sstevel@tonic-gate sessionPoolSize = 0; 30630Sstevel@tonic-gate } 30642830Sdjl (void) rw_unlock(&sessionPoolLock); 30650Sstevel@tonic-gate } 3066