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 /* 22*5840Smj162486 * 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 800Sstevel@tonic-gate 810Sstevel@tonic-gate static mutex_t nscdLock = DEFAULTMUTEX; 820Sstevel@tonic-gate static int nscdChecked = 0; 830Sstevel@tonic-gate static pid_t checkedPid = -1; 840Sstevel@tonic-gate static int isNscd = 0; 852830Sdjl /* 862830Sdjl * SSF values are for SASL integrity & privacy. 872830Sdjl * JES DS5.2 does not support this feature but DS6 does. 882830Sdjl * The values between 0 and 65535 can work with both server versions. 892830Sdjl */ 902830Sdjl #define MAX_SASL_SSF 65535 912830Sdjl #define MIN_SASL_SSF 0 920Sstevel@tonic-gate 931687Sjanga /* Number of hostnames to allocate memory for */ 941687Sjanga #define NUMTOMALLOC 32 952830Sdjl /* 962830Sdjl * ns_mtckey is for sharing a ldap connection among multiple 972830Sdjl * threads; created by ns_ldap_init() in ns_init.c 982830Sdjl */ 992830Sdjl extern thread_key_t ns_mtckey; 1001687Sjanga 1012830Sdjl /* Per thread LDAP error resides in thread-specific data. */ 1022830Sdjl struct ldap_error { 1032830Sdjl int le_errno; 1042830Sdjl char *le_matched; 1052830Sdjl char *le_errmsg; 1062830Sdjl }; 1072830Sdjl 1083428Smichen static struct ldap_error ldap_error_NULL = { LDAP_SUCCESS, NULL, NULL}; 1093428Smichen 1102830Sdjl /* destructor */ 1112830Sdjl void 1122830Sdjl ns_tsd_cleanup(void *key) { 1132830Sdjl struct ldap_error *le = (struct ldap_error *)key; 1142830Sdjl 1152830Sdjl if (le == NULL) 1162830Sdjl return; 1172830Sdjl if (le->le_matched != NULL) { 1182830Sdjl ldap_memfree(le->le_matched); 1192830Sdjl } 1202830Sdjl if (le->le_errmsg != NULL) { 1212830Sdjl ldap_memfree(le->le_errmsg); 1222830Sdjl } 1232830Sdjl free(le); 1242830Sdjl } 1252830Sdjl 1262830Sdjl /* Callback function for allocating a mutex */ 1272830Sdjl static void * 1282830Sdjl ns_mutex_alloc(void) 1292830Sdjl { 1302830Sdjl mutex_t *mutexp = NULL; 1312830Sdjl 1322830Sdjl if ((mutexp = malloc(sizeof (mutex_t))) != NULL) { 1332830Sdjl if (mutex_init(mutexp, USYNC_THREAD, NULL) != 0) { 1342830Sdjl free(mutexp); 1352830Sdjl mutexp = NULL; 1362830Sdjl } 1372830Sdjl } 1382830Sdjl return (mutexp); 1392830Sdjl } 1402830Sdjl 1412830Sdjl /* Callback function for freeing a mutex */ 1422830Sdjl static void 1432830Sdjl ns_mutex_free(void *mutexp) 1442830Sdjl { 1452830Sdjl (void) mutex_destroy((mutex_t *)mutexp); 1462830Sdjl free(mutexp); 1472830Sdjl } 1482830Sdjl 1492830Sdjl /* 1502830Sdjl * Function for setting up thread-specific data 1512830Sdjl * where per thread LDAP error is stored 1522830Sdjl */ 1532830Sdjl static int 1542830Sdjl tsd_setup() 1552830Sdjl { 1562830Sdjl void *tsd; 1572830Sdjl int rc; 1582830Sdjl 1592830Sdjl /* return success if TSD already set */ 1602830Sdjl rc = thr_getspecific(ns_mtckey, &tsd); 1612830Sdjl if (rc == 0 && tsd != NULL) 1622830Sdjl return (0); 1632830Sdjl 1642830Sdjl /* allocate and set TSD */ 1652830Sdjl tsd = (void *) calloc(1, sizeof (struct ldap_error)); 1662830Sdjl if (tsd == NULL) 1672830Sdjl return (-1); 1682830Sdjl rc = thr_setspecific(ns_mtckey, tsd); 1692830Sdjl if (rc != 0) { /* must be ENOMEM */ 1702830Sdjl free(tsd); 1712830Sdjl return (-1); 1722830Sdjl } 1732830Sdjl return (0); 1742830Sdjl 1752830Sdjl 1762830Sdjl } 1772830Sdjl 1782830Sdjl /* Callback function for setting the per thread LDAP error */ 1792830Sdjl /*ARGSUSED*/ 1802830Sdjl static void 1812830Sdjl set_ld_error(int err, char *matched, char *errmsg, void *dummy) 1822830Sdjl { 1832830Sdjl struct ldap_error *le; 1842830Sdjl 1852830Sdjl if (thr_getspecific(ns_mtckey, (void **)&le) != 0) { 1862830Sdjl syslog(LOG_ERR, "set_ld_error: thr_getspecific failed. errno" 1874522Schinlong " %d", errno); 1882830Sdjl return; 1892830Sdjl } 1903428Smichen 1913428Smichen /* play safe, do nothing if TSD pointer is NULL */ 1923428Smichen if (le == NULL) 1933428Smichen return; 1943428Smichen 1952830Sdjl le->le_errno = err; 1962830Sdjl if (le->le_matched != NULL) { 1972830Sdjl ldap_memfree(le->le_matched); 1982830Sdjl } 1992830Sdjl le->le_matched = matched; 2002830Sdjl if (le->le_errmsg != NULL) { 2012830Sdjl ldap_memfree(le->le_errmsg); 2022830Sdjl } 2032830Sdjl le->le_errmsg = errmsg; 2042830Sdjl } 2052830Sdjl 2063387Schinlong int 2073387Schinlong /* check and allocate the thread-specific data for using a shared connection */ 2083387Schinlong __s_api_check_MTC_tsd() 2093387Schinlong { 2103387Schinlong if (tsd_setup() != 0) 2113387Schinlong return (NS_LDAP_MEMORY); 2123387Schinlong 2133387Schinlong return (NS_LDAP_SUCCESS); 2143387Schinlong } 2153387Schinlong 2162830Sdjl /* Callback function for getting the per thread LDAP error */ 2172830Sdjl /*ARGSUSED*/ 2182830Sdjl static int 2192830Sdjl get_ld_error(char **matched, char **errmsg, void *dummy) 2202830Sdjl { 2212830Sdjl struct ldap_error *le; 2222830Sdjl 2232830Sdjl if (thr_getspecific(ns_mtckey, (void **)&le) != 0) { 2242830Sdjl syslog(LOG_ERR, "get_ld_error: thr_getspecific failed. errno" 2254522Schinlong " %d", errno); 2262830Sdjl return (errno); 2272830Sdjl } 2283428Smichen 2293428Smichen /* play safe, return NULL error data, if TSD pointer is NULL */ 2303428Smichen if (le == NULL) 2313428Smichen le = &ldap_error_NULL; 2323428Smichen 2332830Sdjl if (matched != NULL) { 2342830Sdjl *matched = le->le_matched; 2352830Sdjl } 2362830Sdjl if (errmsg != NULL) { 2372830Sdjl *errmsg = le->le_errmsg; 2382830Sdjl } 2392830Sdjl return (le->le_errno); 2402830Sdjl } 2412830Sdjl 2422830Sdjl /* Callback function for setting per thread errno */ 2432830Sdjl static void 2442830Sdjl set_errno(int err) 2452830Sdjl { 2462830Sdjl errno = err; 2472830Sdjl } 2482830Sdjl 2492830Sdjl /* Callback function for getting per thread errno */ 2502830Sdjl static int 2512830Sdjl get_errno(void) 2522830Sdjl { 2532830Sdjl return (errno); 2542830Sdjl } 2552830Sdjl 2562830Sdjl /* 2572830Sdjl * set up to allow multiple threads to use the same ldap connection 2582830Sdjl */ 2592830Sdjl static int 2602830Sdjl setup_mt_conn(LDAP *ld) 2612830Sdjl { 2622830Sdjl 2632830Sdjl struct ldap_thread_fns tfns; 2642830Sdjl struct ldap_extra_thread_fns extrafns; 2652830Sdjl int rc; 2662830Sdjl 2672830Sdjl /* 2682830Sdjl * Set the function pointers for dealing with mutexes 2692830Sdjl * and error information 2702830Sdjl */ 2712830Sdjl (void) memset(&tfns, '\0', sizeof (struct ldap_thread_fns)); 2722830Sdjl tfns.ltf_mutex_alloc = (void *(*)(void)) ns_mutex_alloc; 2732830Sdjl tfns.ltf_mutex_free = (void (*)(void *)) ns_mutex_free; 2742830Sdjl tfns.ltf_mutex_lock = (int (*)(void *)) mutex_lock; 2752830Sdjl tfns.ltf_mutex_unlock = (int (*)(void *)) mutex_unlock; 2762830Sdjl tfns.ltf_get_errno = get_errno; 2772830Sdjl tfns.ltf_set_errno = set_errno; 2782830Sdjl tfns.ltf_get_lderrno = get_ld_error; 2792830Sdjl tfns.ltf_set_lderrno = set_ld_error; 2802830Sdjl tfns.ltf_lderrno_arg = NULL; 2812830Sdjl 2822830Sdjl /* 2832830Sdjl * Set up this session to use those function pointers 2842830Sdjl */ 2852830Sdjl rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS, 2864522Schinlong (void *) &tfns); 2872830Sdjl if (rc < 0) { 2882830Sdjl syslog(LOG_WARNING, "libsldap: ldap_set_option " 2892830Sdjl "(LDAP_OPT_THREAD_FN_PTRS)"); 2902830Sdjl return (-1); 2912830Sdjl } 2922830Sdjl 2932830Sdjl /* 2942830Sdjl * Set the function pointers for working with semaphores 2952830Sdjl */ 2962830Sdjl (void) memset(&extrafns, '\0', 2974522Schinlong sizeof (struct ldap_extra_thread_fns)); 2982830Sdjl extrafns.ltf_threadid_fn = (void * (*)(void))thr_self; 2992830Sdjl extrafns.ltf_mutex_trylock = NULL; 3002830Sdjl extrafns.ltf_sema_alloc = NULL; 3012830Sdjl extrafns.ltf_sema_free = NULL; 3022830Sdjl extrafns.ltf_sema_wait = NULL; 3032830Sdjl extrafns.ltf_sema_post = NULL; 3042830Sdjl 3052830Sdjl /* Set up this session to use those function pointers */ 3062830Sdjl rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS, 3074522Schinlong (void *) &extrafns); 3082830Sdjl if (rc < 0) { 3092830Sdjl syslog(LOG_WARNING, "libsldap: ldap_set_option " 3102830Sdjl "(LDAP_OPT_EXTRA_THREAD_FN_PTRS)"); 3112830Sdjl return (-1); 3122830Sdjl } 3132830Sdjl 3142830Sdjl return (0); 3152830Sdjl } 3162830Sdjl 3172830Sdjl static void 3182830Sdjl ns_setup_mt_conn_and_tsd(LDAP *ld) { 3192830Sdjl thread_t t = thr_self(); 3202830Sdjl void *tsd; 3212830Sdjl /* set up to share this connection among threads */ 3222830Sdjl if (MTperConn == 1) { 3232830Sdjl if (tsd_setup() == -1) { 3242830Sdjl syslog(LOG_ERR, "tid= %d: unable " 3252830Sdjl "to set up TSD\n", t); 3262830Sdjl } else { 3272830Sdjl if (setup_mt_conn(ld) == -1) { 3282830Sdjl /* multiple threads per connection not supported */ 3292830Sdjl syslog(LOG_ERR, "tid= %d: multiple " 3302830Sdjl "threads per connection not " 3312830Sdjl "supported\n", t); 3322830Sdjl (void) thr_getspecific(ns_mtckey, &tsd); 3332830Sdjl ns_tsd_cleanup(tsd); 3342830Sdjl (void) thr_setspecific(ns_mtckey, NULL); 3352830Sdjl MTperConn = 0; 3362830Sdjl } 3372830Sdjl } 3382830Sdjl } 3392830Sdjl } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * Check /proc/PID/psinfo to see if this process is nscd 3430Sstevel@tonic-gate * If it is, treat connection as NS_LDAP_KEEP_CONN, to reduce 3440Sstevel@tonic-gate * constant reconnects for many operations. 3450Sstevel@tonic-gate * A more complete solution is to develop true connection pooling. 3460Sstevel@tonic-gate * However, this is much better than a new connection for every request. 3470Sstevel@tonic-gate */ 3485399Schinlong int 3495399Schinlong __s_api_nscd_proc(void) 3500Sstevel@tonic-gate { 3510Sstevel@tonic-gate pid_t my_pid; 3520Sstevel@tonic-gate psinfo_t pinfo; 3530Sstevel@tonic-gate char fname[BUFSIZ]; 3540Sstevel@tonic-gate int ret; 3550Sstevel@tonic-gate int fd; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /* Don't bother checking if this process isn't root. */ 3580Sstevel@tonic-gate /* It can't be nscd */ 3590Sstevel@tonic-gate if (getuid() != 0) 3600Sstevel@tonic-gate return (0); 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate my_pid = getpid(); 3630Sstevel@tonic-gate if (nscdChecked && (my_pid == checkedPid)) { 3640Sstevel@tonic-gate return (isNscd); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate (void) mutex_lock(&nscdLock); 3670Sstevel@tonic-gate if (nscdChecked && (my_pid == checkedPid)) { 3680Sstevel@tonic-gate (void) mutex_unlock(&nscdLock); 3690Sstevel@tonic-gate return (isNscd); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate nscdChecked = 1; 3720Sstevel@tonic-gate checkedPid = my_pid; 3730Sstevel@tonic-gate isNscd = 0; 3740Sstevel@tonic-gate if (snprintf(fname, BUFSIZ, "/proc/%d/psinfo", my_pid) != 0) { 3750Sstevel@tonic-gate if ((fd = open(fname, O_RDONLY)) > 0) { 3760Sstevel@tonic-gate ret = read(fd, &pinfo, sizeof (psinfo_t)); 3770Sstevel@tonic-gate (void) close(fd); 3780Sstevel@tonic-gate if (ret == sizeof (psinfo_t) && 3790Sstevel@tonic-gate (strcmp(pinfo.pr_fname, "nscd") == 0)) { 3800Sstevel@tonic-gate /* process runs as root and is named nscd */ 3810Sstevel@tonic-gate /* that's good enough for now */ 3820Sstevel@tonic-gate isNscd = 1; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate (void) mutex_unlock(&nscdLock); 3870Sstevel@tonic-gate return (isNscd); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate /* 3910Sstevel@tonic-gate * This function requests a server from the cache manager through 3920Sstevel@tonic-gate * the door functionality 3930Sstevel@tonic-gate */ 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate static int 3960Sstevel@tonic-gate __s_api_requestServer(const char *request, const char *server, 3972830Sdjl ns_server_info_t *ret, ns_ldap_error_t **error, const char *addrType) 3980Sstevel@tonic-gate { 3990Sstevel@tonic-gate union { 4000Sstevel@tonic-gate ldap_data_t s_d; 4010Sstevel@tonic-gate char s_b[DOORBUFFERSIZE]; 4020Sstevel@tonic-gate } space; 4030Sstevel@tonic-gate ldap_data_t *sptr; 4040Sstevel@tonic-gate int ndata; 4050Sstevel@tonic-gate int adata; 4060Sstevel@tonic-gate char errstr[MAXERROR]; 4070Sstevel@tonic-gate const char *ireq; 4080Sstevel@tonic-gate char *rbuf, *ptr, *rest; 4090Sstevel@tonic-gate char *dptr; 4100Sstevel@tonic-gate char **mptr, **mptr1, **cptr, **cptr1; 4110Sstevel@tonic-gate int mcnt, ccnt; 4120Sstevel@tonic-gate char **servers; 4132830Sdjl int rc, len; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate if (ret == NULL || error == NULL) { 4160Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate (void) memset(ret, 0, sizeof (ns_server_info_t)); 4190Sstevel@tonic-gate *error = NULL; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate (void) memset(space.s_b, 0, DOORBUFFERSIZE); 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate if (request == NULL) 4240Sstevel@tonic-gate ireq = NS_CACHE_NEW; 4250Sstevel@tonic-gate else 4260Sstevel@tonic-gate ireq = request; 4270Sstevel@tonic-gate 4282830Sdjl adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1); 4290Sstevel@tonic-gate if (server != NULL) { 4300Sstevel@tonic-gate adata += strlen(DOORLINESEP) + 1; 4310Sstevel@tonic-gate adata += strlen(server) + 1; 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate ndata = sizeof (space); 4342830Sdjl len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber); 4350Sstevel@tonic-gate space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER; 4362830Sdjl if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len) 4372830Sdjl return (NS_LDAP_MEMORY); 4382830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >= 4394522Schinlong len) 4402830Sdjl return (NS_LDAP_MEMORY); 4410Sstevel@tonic-gate if (server != NULL) { 4422830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, 4434522Schinlong DOORLINESEP, len) >= len) 4442830Sdjl return (NS_LDAP_MEMORY); 4452830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, 4464522Schinlong len) >= len) 4472830Sdjl return (NS_LDAP_MEMORY); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate sptr = &space.s_d; 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) { 4520Sstevel@tonic-gate case SUCCESS: 4530Sstevel@tonic-gate break; 4540Sstevel@tonic-gate /* this case is for when the $mgr is not running, but ldapclient */ 4550Sstevel@tonic-gate /* is trying to initialize things */ 4560Sstevel@tonic-gate case NOSERVER: 4570Sstevel@tonic-gate /* get first server from config list unavailable otherwise */ 4580Sstevel@tonic-gate servers = NULL; 4590Sstevel@tonic-gate rc = __s_api_getServers(&servers, error); 4600Sstevel@tonic-gate if (rc != NS_LDAP_SUCCESS) { 4610Sstevel@tonic-gate if (servers != NULL) { 4620Sstevel@tonic-gate __s_api_free2dArray(servers); 4630Sstevel@tonic-gate servers = NULL; 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate return (rc); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate if (servers == NULL || servers[0] == NULL) { 4680Sstevel@tonic-gate __s_api_free2dArray(servers); 4690Sstevel@tonic-gate servers = NULL; 4700Sstevel@tonic-gate (void) sprintf(errstr, 4714522Schinlong gettext("No server found in configuration")); 4720Sstevel@tonic-gate MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT, 4734522Schinlong strdup(errstr), NULL); 4740Sstevel@tonic-gate return (NS_LDAP_CONFIG); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate ret->server = strdup(servers[0]); 4770Sstevel@tonic-gate if (ret->server == NULL) { 4780Sstevel@tonic-gate __s_api_free2dArray(servers); 4790Sstevel@tonic-gate return (NS_LDAP_MEMORY); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate ret->saslMechanisms = NULL; 4820Sstevel@tonic-gate ret->controls = NULL; 4830Sstevel@tonic-gate __s_api_free2dArray(servers); 4840Sstevel@tonic-gate servers = NULL; 4850Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 4860Sstevel@tonic-gate case NOTFOUND: 4870Sstevel@tonic-gate default: 4880Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* copy info from door call return structure here */ 4920Sstevel@tonic-gate rbuf = space.s_d.ldap_ret.ldap_u.config; 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate /* Get the host */ 4950Sstevel@tonic-gate ptr = strtok_r(rbuf, DOORLINESEP, &rest); 4960Sstevel@tonic-gate if (ptr == NULL) { 4970Sstevel@tonic-gate (void) sprintf(errstr, gettext("No server returned from " 4984522Schinlong "ldap_cachemgr")); 4990Sstevel@tonic-gate MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR, 5004522Schinlong strdup(errstr), NULL); 5010Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate ret->server = strdup(ptr); 5040Sstevel@tonic-gate if (ret->server == NULL) { 5050Sstevel@tonic-gate return (NS_LDAP_MEMORY); 5060Sstevel@tonic-gate } 5074522Schinlong /* Get the host FQDN format */ 5084522Schinlong if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) { 5094522Schinlong ptr = strtok_r(NULL, DOORLINESEP, &rest); 5104522Schinlong if (ptr == NULL) { 5114522Schinlong (void) sprintf(errstr, gettext("No server FQDN format " 5124522Schinlong "returned from ldap_cachemgr")); 5134522Schinlong MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR, 5144522Schinlong strdup(errstr), NULL); 5154522Schinlong free(ret->server); 5164522Schinlong ret->server = NULL; 5174522Schinlong return (NS_LDAP_OP_FAILED); 5184522Schinlong } 5194522Schinlong ret->serverFQDN = strdup(ptr); 5204522Schinlong if (ret->serverFQDN == NULL) { 5214522Schinlong free(ret->server); 5224522Schinlong ret->server = NULL; 5234522Schinlong return (NS_LDAP_MEMORY); 5244522Schinlong } 5254522Schinlong } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate /* get the Supported Controls/SASL mechs */ 5280Sstevel@tonic-gate mptr = NULL; 5290Sstevel@tonic-gate mcnt = 0; 5300Sstevel@tonic-gate cptr = NULL; 5310Sstevel@tonic-gate ccnt = 0; 5320Sstevel@tonic-gate for (; ; ) { 5330Sstevel@tonic-gate ptr = strtok_r(NULL, DOORLINESEP, &rest); 5340Sstevel@tonic-gate if (ptr == NULL) 5350Sstevel@tonic-gate break; 5360Sstevel@tonic-gate if (strncasecmp(ptr, _SASLMECHANISM, 5374522Schinlong _SASLMECHANISM_LEN) == 0) { 5380Sstevel@tonic-gate dptr = strchr(ptr, '='); 5390Sstevel@tonic-gate if (dptr == NULL) 5400Sstevel@tonic-gate continue; 5410Sstevel@tonic-gate dptr++; 5420Sstevel@tonic-gate mptr1 = (char **)realloc((void *)mptr, 5434522Schinlong sizeof (char *) * (mcnt+2)); 5440Sstevel@tonic-gate if (mptr1 == NULL) { 5450Sstevel@tonic-gate __s_api_free2dArray(mptr); 5460Sstevel@tonic-gate if (sptr != &space.s_d) { 5474522Schinlong (void) munmap((char *)sptr, ndata); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate __s_api_free2dArray(cptr); 5504522Schinlong __s_api_free_server_info(ret); 5510Sstevel@tonic-gate return (NS_LDAP_MEMORY); 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate mptr = mptr1; 5540Sstevel@tonic-gate mptr[mcnt] = strdup(dptr); 5550Sstevel@tonic-gate if (mptr[mcnt] == NULL) { 5560Sstevel@tonic-gate if (sptr != &space.s_d) { 5574522Schinlong (void) munmap((char *)sptr, ndata); 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate __s_api_free2dArray(cptr); 5600Sstevel@tonic-gate cptr = NULL; 5610Sstevel@tonic-gate __s_api_free2dArray(mptr); 5620Sstevel@tonic-gate mptr = NULL; 5634522Schinlong __s_api_free_server_info(ret); 5640Sstevel@tonic-gate return (NS_LDAP_MEMORY); 5650Sstevel@tonic-gate } 5660Sstevel@tonic-gate mcnt++; 5670Sstevel@tonic-gate mptr[mcnt] = NULL; 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate if (strncasecmp(ptr, _SUPPORTEDCONTROL, 5704522Schinlong _SUPPORTEDCONTROL_LEN) == 0) { 5710Sstevel@tonic-gate dptr = strchr(ptr, '='); 5720Sstevel@tonic-gate if (dptr == NULL) 5730Sstevel@tonic-gate continue; 5740Sstevel@tonic-gate dptr++; 5750Sstevel@tonic-gate cptr1 = (char **)realloc((void *)cptr, 5764522Schinlong sizeof (char *) * (ccnt+2)); 5770Sstevel@tonic-gate if (cptr1 == NULL) { 5780Sstevel@tonic-gate if (sptr != &space.s_d) { 5794522Schinlong (void) munmap((char *)sptr, ndata); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate __s_api_free2dArray(cptr); 5820Sstevel@tonic-gate __s_api_free2dArray(mptr); 5830Sstevel@tonic-gate mptr = NULL; 5844522Schinlong __s_api_free_server_info(ret); 5850Sstevel@tonic-gate return (NS_LDAP_MEMORY); 5860Sstevel@tonic-gate } 5870Sstevel@tonic-gate cptr = cptr1; 5880Sstevel@tonic-gate cptr[ccnt] = strdup(dptr); 5890Sstevel@tonic-gate if (cptr[ccnt] == NULL) { 5900Sstevel@tonic-gate if (sptr != &space.s_d) { 5914522Schinlong (void) munmap((char *)sptr, ndata); 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate __s_api_free2dArray(cptr); 5940Sstevel@tonic-gate cptr = NULL; 5950Sstevel@tonic-gate __s_api_free2dArray(mptr); 5960Sstevel@tonic-gate mptr = NULL; 5974522Schinlong __s_api_free_server_info(ret); 5980Sstevel@tonic-gate return (NS_LDAP_MEMORY); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate ccnt++; 6010Sstevel@tonic-gate cptr[ccnt] = NULL; 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate if (mptr != NULL) { 6050Sstevel@tonic-gate ret->saslMechanisms = mptr; 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate if (cptr != NULL) { 6080Sstevel@tonic-gate ret->controls = cptr; 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate /* clean up door call */ 6130Sstevel@tonic-gate if (sptr != &space.s_d) { 6140Sstevel@tonic-gate (void) munmap((char *)sptr, ndata); 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate *error = NULL; 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate /* 6230Sstevel@tonic-gate * printCred(): prints the credential structure 6240Sstevel@tonic-gate */ 6250Sstevel@tonic-gate static void 6262830Sdjl printCred(int pri, const ns_cred_t *cred) 6270Sstevel@tonic-gate { 6282830Sdjl thread_t t = thr_self(); 6292830Sdjl 6300Sstevel@tonic-gate if (cred == NULL) { 6312830Sdjl syslog(LOG_ERR, "tid= %d: printCred: cred is NULL\n", t); 6320Sstevel@tonic-gate return; 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6352830Sdjl syslog(pri, "tid= %d: AuthType=%d", t, cred->auth.type); 6362830Sdjl syslog(pri, "tid= %d: TlsType=%d", t, cred->auth.tlstype); 6372830Sdjl syslog(pri, "tid= %d: SaslMech=%d", t, cred->auth.saslmech); 6382830Sdjl syslog(pri, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt); 6390Sstevel@tonic-gate if (cred->hostcertpath) 6402830Sdjl syslog(pri, "tid= %d: hostCertPath=%s\n", 6414522Schinlong t, cred->hostcertpath); 6420Sstevel@tonic-gate if (cred->cred.unix_cred.userID) 6432830Sdjl syslog(pri, "tid= %d: userID=%s\n", 6444522Schinlong t, cred->cred.unix_cred.userID); 6453387Schinlong #ifdef DEBUG 6460Sstevel@tonic-gate if (cred->cred.unix_cred.passwd) 6472830Sdjl syslog(pri, "tid= %d: passwd=%s\n", 6484522Schinlong t, cred->cred.unix_cred.passwd); 6493387Schinlong #endif 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate /* 6530Sstevel@tonic-gate * printConnection(): prints the connection structure 6540Sstevel@tonic-gate */ 6550Sstevel@tonic-gate static void 6562830Sdjl printConnection(int pri, Connection *con) 6570Sstevel@tonic-gate { 6582830Sdjl thread_t t = thr_self(); 6592830Sdjl 6602830Sdjl if (con == NULL) 6610Sstevel@tonic-gate return; 6620Sstevel@tonic-gate 6632830Sdjl syslog(pri, "tid= %d: connectionID=%d\n", t, con->connectionId); 6642830Sdjl syslog(pri, "tid= %d: shared=%d\n", t, con->shared); 6652830Sdjl syslog(pri, "tid= %d: usedBit=%d\n", t, con->usedBit); 6662830Sdjl syslog(pri, "tid= %d: threadID=%d\n", t, con->threadID); 6670Sstevel@tonic-gate if (con->serverAddr) { 6682830Sdjl syslog(pri, "tid= %d: serverAddr=%s\n", 6694522Schinlong t, con->serverAddr); 6700Sstevel@tonic-gate } 6712830Sdjl printCred(pri, con->auth); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate /* 6772830Sdjl * addConnection(): set up a connection so that it can be shared 6782830Sdjl * among multiple threads and then insert the connection in the 6792830Sdjl * connection list. 6800Sstevel@tonic-gate * Returns: -1 = failure, new Connection ID = success 6812830Sdjl * 6822830Sdjl * This function could exit with sessionLock locked. It will be 6832830Sdjl * be unlocked in __s_api_getConnection() when it exits without getting a 6842830Sdjl * connection. 6850Sstevel@tonic-gate */ 6860Sstevel@tonic-gate static int 6870Sstevel@tonic-gate addConnection(Connection *con) 6880Sstevel@tonic-gate { 6892830Sdjl int i, noMTperC = 0; 6902830Sdjl thread_t t = thr_self(); 6912830Sdjl struct ldap_thread_fns tfns; 6922830Sdjl void *tsd; 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate if (!con) 6950Sstevel@tonic-gate return (-1); 6962830Sdjl 6972830Sdjl syslog(LOG_DEBUG, "tid= %d: Adding connection (serverAddr=%s)", 6984522Schinlong t, con->serverAddr); 6992830Sdjl 7002830Sdjl if (MTperConn == 1) { 7012830Sdjl /* 7022830Sdjl * Make sure ld has proper thread functions and tsd 7032830Sdjl * is set up. 7042830Sdjl */ 7052830Sdjl (void) memset(&tfns, 0, sizeof (struct ldap_thread_fns)); 7062830Sdjl /* 7072830Sdjl * ldap_init sets ltf_get_lderrno and ltf_set_lderrno to NULLs. 7082830Sdjl * It's supposed to be overwritten by ns_setup_mt_conn_and_tsd. 7092830Sdjl */ 7102830Sdjl if (ldap_get_option(con->ld, LDAP_OPT_THREAD_FN_PTRS, 7114522Schinlong (void *)&tfns) != 0 || 7124522Schinlong tfns.ltf_get_lderrno != get_ld_error || 7134522Schinlong tfns.ltf_set_lderrno != set_ld_error) { 7142830Sdjl MTperConn = 0; 7152830Sdjl noMTperC = 1; 7162830Sdjl } else { 7172830Sdjl if (thr_getspecific(ns_mtckey, &tsd) != 0 || 7184522Schinlong tsd == NULL) 7192830Sdjl noMTperC = 1; 7202830Sdjl } 7212830Sdjl 7222830Sdjl } else { 7232830Sdjl noMTperC = 1; 7242830Sdjl } 7252830Sdjl 7262830Sdjl (void) rw_wrlock(&sessionPoolLock); 7270Sstevel@tonic-gate if (sessionPool == NULL) { 7280Sstevel@tonic-gate sessionPoolSize = SESSION_CACHE_INC; 7290Sstevel@tonic-gate sessionPool = calloc(sessionPoolSize, 7304522Schinlong sizeof (struct connection **)); 7310Sstevel@tonic-gate if (!sessionPool) { 7322830Sdjl (void) rw_unlock(&sessionPoolLock); 7330Sstevel@tonic-gate return (-1); 7340Sstevel@tonic-gate } 7352830Sdjl 7362830Sdjl syslog(LOG_DEBUG, "tid= %d: Initialized sessionPool", t); 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i) 7390Sstevel@tonic-gate ; 7400Sstevel@tonic-gate if (i == sessionPoolSize) { 7410Sstevel@tonic-gate /* run out of array, need to increase sessionPool */ 7420Sstevel@tonic-gate Connection **cl; 7430Sstevel@tonic-gate cl = (Connection **) realloc(sessionPool, 7444522Schinlong (sessionPoolSize + SESSION_CACHE_INC) * 7454522Schinlong sizeof (Connection *)); 7460Sstevel@tonic-gate if (!cl) { 7472830Sdjl (void) rw_unlock(&sessionPoolLock); 7480Sstevel@tonic-gate return (-1); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate (void) memset(cl + sessionPoolSize, 0, 7514522Schinlong SESSION_CACHE_INC * sizeof (struct connection *)); 7520Sstevel@tonic-gate sessionPool = cl; 7530Sstevel@tonic-gate sessionPoolSize += SESSION_CACHE_INC; 7542830Sdjl syslog(LOG_DEBUG, "tid: %d: Increased " 7554522Schinlong "sessionPoolSize to: %d\n", 7564522Schinlong t, sessionPoolSize); 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate sessionPool[i] = con; 7593387Schinlong if (noMTperC == 0) { 7602830Sdjl con->shared++; 7613387Schinlong con->pid = getpid(); 7623387Schinlong (void) mutex_lock(&sharedConnNumberLock); 7633387Schinlong sharedConnNumber++; 7643387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 7653387Schinlong } else 7662830Sdjl con->usedBit = B_TRUE; 7672830Sdjl 7682830Sdjl (void) rw_unlock(&sessionPoolLock); 7692830Sdjl 7700Sstevel@tonic-gate con->connectionId = i + CONID_OFFSET; 7712830Sdjl 7722830Sdjl syslog(LOG_DEBUG, "tid= %d: Connection added [%d]\n", 7734522Schinlong t, i); 7742830Sdjl printConnection(LOG_DEBUG, con); 7752830Sdjl 7762830Sdjl /* 7772830Sdjl * A connection can be shared now, unlock 7782830Sdjl * the session mutex and let other 7792830Sdjl * threads try to use this connection or 7802830Sdjl * get their own. 7812830Sdjl */ 7822830Sdjl if (wait4session != 0 && sessionTid == thr_self()) { 7832830Sdjl wait4session = 0; 7842830Sdjl sessionTid = 0; 7852830Sdjl syslog(LOG_DEBUG, "tid= %d: unlocking sessionLock\n", t); 7862830Sdjl (void) mutex_unlock(&sessionLock); 7872830Sdjl } 7882830Sdjl 7890Sstevel@tonic-gate return (i + CONID_OFFSET); 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /* 7930Sstevel@tonic-gate * See if the specified session matches a currently available 7940Sstevel@tonic-gate */ 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate static int 7970Sstevel@tonic-gate findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, 7980Sstevel@tonic-gate Connection **conp) 7990Sstevel@tonic-gate { 8000Sstevel@tonic-gate Connection *cp; 8010Sstevel@tonic-gate int id; 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate if ((conp == NULL) || (auth == NULL) || cID < CONID_OFFSET) 8040Sstevel@tonic-gate return (-1); 8052830Sdjl 8065532Smj162486 /* 8075532Smj162486 * If a new connection is requested, no need to continue. 8085532Smj162486 * If the process is not nscd and is not requesting keep connections 8095532Smj162486 * alive, no need to continue. 8105532Smj162486 */ 8115532Smj162486 if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() && 8125532Smj162486 !(flags & NS_LDAP_KEEP_CONN))) 8132830Sdjl return (-1); 8142830Sdjl 8150Sstevel@tonic-gate *conp = NULL; 8160Sstevel@tonic-gate if (sessionPool == NULL) 8170Sstevel@tonic-gate return (-1); 8180Sstevel@tonic-gate id = cID - CONID_OFFSET; 8190Sstevel@tonic-gate if (id < 0 || id >= sessionPoolSize) 8200Sstevel@tonic-gate return (-1); 8210Sstevel@tonic-gate 8222830Sdjl (void) rw_rdlock(&sessionPoolLock); 8230Sstevel@tonic-gate if (sessionPool[id] == NULL) { 8242830Sdjl (void) rw_unlock(&sessionPoolLock); 8250Sstevel@tonic-gate return (-1); 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate cp = sessionPool[id]; 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate /* 8300Sstevel@tonic-gate * Make sure the connection has the same type of authentication method 8310Sstevel@tonic-gate */ 8320Sstevel@tonic-gate if ((cp->usedBit) || 8332830Sdjl (cp->notAvail) || 8340Sstevel@tonic-gate (cp->auth->auth.type != auth->auth.type) || 8350Sstevel@tonic-gate (cp->auth->auth.tlstype != auth->auth.tlstype) || 8360Sstevel@tonic-gate (cp->auth->auth.saslmech != auth->auth.saslmech) || 8370Sstevel@tonic-gate (cp->auth->auth.saslopt != auth->auth.saslopt)) { 8382830Sdjl (void) rw_unlock(&sessionPoolLock); 8390Sstevel@tonic-gate return (-1); 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && 8424522Schinlong ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) || 8434522Schinlong (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) || 8444522Schinlong (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) && 8454522Schinlong ((cp->auth->cred.unix_cred.userID == NULL) || 8464522Schinlong (strcasecmp(cp->auth->cred.unix_cred.userID, 8474522Schinlong auth->cred.unix_cred.userID) != 0))) { 8482830Sdjl (void) rw_unlock(&sessionPoolLock); 8490Sstevel@tonic-gate return (-1); 8500Sstevel@tonic-gate } 8512830Sdjl 8520Sstevel@tonic-gate /* An existing connection is found but it needs to be reset */ 8530Sstevel@tonic-gate if (flags & NS_LDAP_NEW_CONN) { 8542830Sdjl (void) rw_unlock(&sessionPoolLock); 8550Sstevel@tonic-gate DropConnection(cID, 0); 8560Sstevel@tonic-gate return (-1); 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate /* found an available connection */ 8590Sstevel@tonic-gate cp->usedBit = B_TRUE; 8602830Sdjl (void) rw_unlock(&sessionPoolLock); 8610Sstevel@tonic-gate cp->threadID = thr_self(); 8620Sstevel@tonic-gate *conp = cp; 8630Sstevel@tonic-gate return (cID); 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * findConnection(): find an available connection from the list 8680Sstevel@tonic-gate * that matches the criteria specified in Connection structure. 8690Sstevel@tonic-gate * If serverAddr is NULL, then find a connection to any server 8700Sstevel@tonic-gate * as long as it matches the rest of the parameters. 8710Sstevel@tonic-gate * Returns: -1 = failure, the Connection ID found = success. 8722830Sdjl * 8732830Sdjl * This function could exit with sessionLock locked. It will be 8742830Sdjl * be unlocked in addConnection() when this thread adds the connection 8752830Sdjl * to the pool or in __s_api_getConnection() when it exits without getting a 8762830Sdjl * connection. 8770Sstevel@tonic-gate */ 8782830Sdjl #define TRY_TIMES 10 8790Sstevel@tonic-gate static int 8802830Sdjl findConnection(int flags, const char *serverAddr, 8812830Sdjl const ns_cred_t *auth, Connection **conp) 8820Sstevel@tonic-gate { 8830Sstevel@tonic-gate Connection *cp; 8844048Schinlong int i, j, conn_server_index, up_server_index, drop_conn; 8852830Sdjl int rc; 8862830Sdjl int try; 8874048Schinlong ns_server_info_t sinfo; 8884048Schinlong ns_ldap_error_t *errorp = NULL; 8894522Schinlong char **servers; 8904048Schinlong void **paramVal = NULL; 8912830Sdjl #ifdef DEBUG 8922830Sdjl thread_t t = thr_self(); 8932830Sdjl #endif /* DEBUG */ 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate if (auth == NULL || conp == NULL) 8960Sstevel@tonic-gate return (-1); 8970Sstevel@tonic-gate *conp = NULL; 8980Sstevel@tonic-gate 899*5840Smj162486 /* 900*5840Smj162486 * If a new connection is requested, no need to continue. 901*5840Smj162486 * If the process is not nscd and is not requesting keep connections 902*5840Smj162486 * alive, no need to continue. 903*5840Smj162486 */ 904*5840Smj162486 if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() && 905*5840Smj162486 !(flags & NS_LDAP_KEEP_CONN))) 9062830Sdjl return (-1); 9072830Sdjl 9080Sstevel@tonic-gate #ifdef DEBUG 9092830Sdjl (void) fprintf(stderr, "tid= %d: Find connection\n", t); 9102830Sdjl (void) fprintf(stderr, "tid= %d: Looking for ....\n", t); 9110Sstevel@tonic-gate if (serverAddr && *serverAddr) 9122830Sdjl (void) fprintf(stderr, "tid= %d: serverAddr=%s\n", 9134522Schinlong t, serverAddr); 9140Sstevel@tonic-gate else 9152830Sdjl (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t); 9164048Schinlong printCred(LOG_DEBUG, auth); 9170Sstevel@tonic-gate fflush(stderr); 9180Sstevel@tonic-gate #endif /* DEBUG */ 9192830Sdjl 9202830Sdjl /* 9212830Sdjl * If multiple threads per connection not supported, 9222830Sdjl * no sessionPool means no connection 9232830Sdjl */ 9242830Sdjl (void) rw_rdlock(&sessionPoolLock); 9252830Sdjl if (MTperConn == 0 && sessionPool == NULL) { 9262830Sdjl (void) rw_unlock(&sessionPoolLock); 9270Sstevel@tonic-gate return (-1); 9282830Sdjl } 9292830Sdjl 9302830Sdjl /* 9313387Schinlong * If no sharable connections in cache, then serialize the opening 9322830Sdjl * of connections. Make sure only one is being opened 9332830Sdjl * at a time. Otherwise, we may end up with more 9342830Sdjl * connections than we want (if multiple threads get 9352830Sdjl * here at the same time) 9362830Sdjl */ 9373387Schinlong (void) mutex_lock(&sharedConnNumberLock); 9383387Schinlong if (sessionPool == NULL || (sharedConnNumber == 0 && MTperConn == 1)) { 9393387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 9402830Sdjl (void) rw_unlock(&sessionPoolLock); 9412830Sdjl (void) mutex_lock(&sessionLock); 9423387Schinlong (void) mutex_lock(&sharedConnNumberLock); 9433387Schinlong if (sessionPool == NULL || (sharedConnNumber == 0 && 9444522Schinlong MTperConn == 1)) { 9453387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 9462830Sdjl wait4session = 1; 9472830Sdjl sessionTid = thr_self(); 9482830Sdjl #ifdef DEBUG 9492830Sdjl (void) fprintf(stderr, "tid= %d: get " 9504522Schinlong "connection ... \n", t); 9512830Sdjl fflush(stderr); 9522830Sdjl #endif /* DEBUG */ 9532830Sdjl /* 9542830Sdjl * Exit with sessionLock locked. It will be 9552830Sdjl * be unlocked in addConnection() when this 9562830Sdjl * thread adds the connection to the pool or 9572830Sdjl * in __s_api_getConnection() when it exits 9582830Sdjl * without getting a connection. 9592830Sdjl */ 9602830Sdjl return (-1); 9612830Sdjl } 9622830Sdjl 9632830Sdjl #ifdef DEBUG 9643387Schinlong (void) fprintf(stderr, "tid= %d: shareable connections " 9654522Schinlong "exist\n", t); 9662830Sdjl fflush(stderr); 9672830Sdjl #endif /* DEBUG */ 9683387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 9692830Sdjl /* 9703387Schinlong * There are sharable connections, check to see if 9712830Sdjl * one can be shared. 9722830Sdjl */ 9732830Sdjl (void) mutex_unlock(&sessionLock); 9742830Sdjl (void) rw_rdlock(&sessionPoolLock); 9753387Schinlong } else 9763387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 9773387Schinlong 9782830Sdjl try = 0; 9792830Sdjl check_again: 9802830Sdjl 9810Sstevel@tonic-gate for (i = 0; i < sessionPoolSize; ++i) { 9820Sstevel@tonic-gate if (sessionPool[i] == NULL) 9830Sstevel@tonic-gate continue; 9840Sstevel@tonic-gate cp = sessionPool[i]; 9850Sstevel@tonic-gate #ifdef DEBUG 9862830Sdjl (void) fprintf(stderr, "tid= %d: checking connection " 9874522Schinlong "[%d] ....\n", t, i); 9884048Schinlong printConnection(LOG_DEBUG, cp); 9890Sstevel@tonic-gate #endif /* DEBUG */ 9902830Sdjl if ((cp->usedBit) || (cp->notAvail) || 9910Sstevel@tonic-gate (cp->auth->auth.type != auth->auth.type) || 9920Sstevel@tonic-gate (cp->auth->auth.tlstype != auth->auth.tlstype) || 9930Sstevel@tonic-gate (cp->auth->auth.saslmech != auth->auth.saslmech) || 9940Sstevel@tonic-gate (cp->auth->auth.saslopt != auth->auth.saslopt) || 9950Sstevel@tonic-gate (serverAddr && *serverAddr && 9960Sstevel@tonic-gate (strcasecmp(serverAddr, cp->serverAddr) != 0))) 9970Sstevel@tonic-gate continue; 9980Sstevel@tonic-gate if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && 9990Sstevel@tonic-gate ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) || 10000Sstevel@tonic-gate (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) || 10010Sstevel@tonic-gate (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) && 10020Sstevel@tonic-gate ((cp->auth->cred.unix_cred.userID == NULL) || 10030Sstevel@tonic-gate (cp->auth->cred.unix_cred.passwd == NULL) || 10040Sstevel@tonic-gate ((strcasecmp(cp->auth->cred.unix_cred.userID, 10054522Schinlong auth->cred.unix_cred.userID) != 0)) || 10060Sstevel@tonic-gate ((strcmp(cp->auth->cred.unix_cred.passwd, 10074522Schinlong auth->cred.unix_cred.passwd) != 0)))) 10080Sstevel@tonic-gate continue; 10094048Schinlong if (!(serverAddr && *serverAddr)) { 10104048Schinlong /* 10114048Schinlong * Get preferred server list. 10124048Schinlong * When preferred servers are merged with default 10134048Schinlong * servers (S_LDAP_SERVER_P) by __s_api_getServer, 10144048Schinlong * preferred servers are copied sequencially. 10154048Schinlong * The order should be the same as the order retrieved 10164048Schinlong * by __ns_ldap_getParam. 10174048Schinlong */ 10184048Schinlong if ((rc = __ns_ldap_getParam(NS_LDAP_SERVER_PREF_P, 10194522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 10204048Schinlong (void) __ns_ldap_freeError(&errorp); 10214048Schinlong (void) __ns_ldap_freeParam(¶mVal); 10224048Schinlong (void) rw_unlock(&sessionPoolLock); 10234048Schinlong return (-1); 10244048Schinlong } 10254048Schinlong servers = (char **)paramVal; 10264048Schinlong /* 10274048Schinlong * Do fallback only if preferred servers are defined. 10284048Schinlong */ 10294048Schinlong if (servers != NULL) { 10304048Schinlong /* 10314048Schinlong * Find the 1st available server 10324048Schinlong */ 10334048Schinlong rc = __s_api_requestServer(NS_CACHE_NEW, NULL, 10344522Schinlong &sinfo, &errorp, NS_CACHE_ADDR_IP); 10354048Schinlong if (rc != NS_LDAP_SUCCESS) { 10364048Schinlong /* 10374048Schinlong * Drop the connection. 10384048Schinlong * Pass 1 to fini so it won't be locked 10394048Schinlong * inside _DropConnection 10404048Schinlong */ 10414048Schinlong _DropConnection( 10424522Schinlong cp->connectionId, 10434522Schinlong NS_LDAP_NEW_CONN, 1); 10444048Schinlong (void) rw_unlock( 10454048Schinlong &sessionPoolLock); 10464522Schinlong (void) __ns_ldap_freeError(&errorp); 10474048Schinlong (void) __ns_ldap_freeParam( 10484522Schinlong (void ***)&servers); 10494048Schinlong return (-1); 10504048Schinlong } 10514048Schinlong 10524048Schinlong if (sinfo.server) { 10534048Schinlong /* 10544048Schinlong * Test if cp->serverAddr is a 10554048Schinlong * preferred server. 10564048Schinlong */ 10574048Schinlong conn_server_index = -1; 10584048Schinlong for (j = 0; servers[j] != NULL; j++) { 10594048Schinlong if (strcasecmp(servers[j], 10604522Schinlong cp->serverAddr) == 0) { 10614048Schinlong conn_server_index = j; 10624048Schinlong break; 10634048Schinlong } 10644048Schinlong } 10654048Schinlong /* 10664048Schinlong * Test if sinfo.server is a preferred 10674048Schinlong * server. 10684048Schinlong */ 10694048Schinlong up_server_index = -1; 10704048Schinlong for (j = 0; servers[j] != NULL; j++) { 10714048Schinlong if (strcasecmp(sinfo.server, 10724522Schinlong servers[j]) == 0) { 10734048Schinlong up_server_index = j; 10744048Schinlong break; 10754048Schinlong } 10764048Schinlong } 10774048Schinlong 10784048Schinlong /* 10794048Schinlong * The following code is to fall back 10804048Schinlong * to preferred servers if servers 10814048Schinlong * are previously down but are up now. 10824048Schinlong * If cp->serverAddr is a preferred 10834048Schinlong * server, it falls back to the servers 10844048Schinlong * ahead of it. If cp->serverAddr is 10854048Schinlong * not a preferred server, it falls 10864048Schinlong * back to any of preferred servers 10874048Schinlong * returned by ldap_cachemgr. 10884048Schinlong */ 10894048Schinlong if (conn_server_index >= 0 && 10904522Schinlong up_server_index >= 0) { 10914048Schinlong /* 10924048Schinlong * cp->serverAddr and 10934048Schinlong * sinfo.server are preferred 10944048Schinlong * servers. 10954048Schinlong */ 10964048Schinlong if (up_server_index == 10974522Schinlong conn_server_index) 10984048Schinlong /* 10994048Schinlong * sinfo.server is the 11004048Schinlong * same as 11014048Schinlong * cp->serverAddr. 11024048Schinlong * Keep the connection. 11034048Schinlong */ 11044048Schinlong drop_conn = 0; 11054048Schinlong else 11064048Schinlong /* 11074048Schinlong * 1. 11084048Schinlong * up_server_index < 11094048Schinlong * conn_server_index 11104048Schinlong * 11114048Schinlong * sinfo is ahead of 11124048Schinlong * cp->serverAddr in 11134048Schinlong * Need to fall back. 11144048Schinlong * 2. 11154048Schinlong * up_server_index > 11164048Schinlong * conn_server_index 11174048Schinlong * cp->serverAddr is 11184048Schinlong * down. Drop it. 11194048Schinlong */ 11204048Schinlong drop_conn = 1; 11214048Schinlong } else if (conn_server_index >= 0 && 11224522Schinlong up_server_index == -1) { 11234048Schinlong /* 11244048Schinlong * cp->serverAddr is a preferred 11254048Schinlong * server but sinfo.server is 11264048Schinlong * not. Preferred servers are 11274048Schinlong * ahead of default servers. 11284048Schinlong * This means cp->serverAddr is 11294048Schinlong * down. Drop it. 11304048Schinlong */ 11314048Schinlong drop_conn = 1; 11324048Schinlong } else if (conn_server_index == -1 && 11334522Schinlong up_server_index >= 0) { 11344048Schinlong /* 11354048Schinlong * cp->serverAddr is not a 11364048Schinlong * preferred server but 11374048Schinlong * sinfo.server is. 11384048Schinlong * Fall back. 11394048Schinlong */ 11404048Schinlong drop_conn = 1; 11414048Schinlong } else { 11424048Schinlong /* 11434048Schinlong * Both index are -1 11444048Schinlong * cp->serverAddr and 11454048Schinlong * sinfo.server are not 11464048Schinlong * preferred servers. 11474048Schinlong * No fallback. 11484048Schinlong */ 11494048Schinlong drop_conn = 0; 11504048Schinlong } 11514048Schinlong if (drop_conn) { 11524048Schinlong /* 11534048Schinlong * Drop the connection so the 11544048Schinlong * new conection can fall back 11554048Schinlong * to a new server later. 11564048Schinlong * Pass 1 to fini so it won't 11574048Schinlong * be locked inside 11584048Schinlong * _DropConnection 11594048Schinlong */ 11604048Schinlong _DropConnection( 11614522Schinlong cp->connectionId, 11624522Schinlong NS_LDAP_NEW_CONN, 1); 11634048Schinlong (void) rw_unlock( 11644048Schinlong &sessionPoolLock); 11654048Schinlong (void) __ns_ldap_freeParam( 11664522Schinlong (void ***)&servers); 11674522Schinlong __s_api_free_server_info( 11684522Schinlong &sinfo); 11694048Schinlong return (-1); 11704048Schinlong } else { 11714048Schinlong /* 11724048Schinlong * Keep the connection 11734048Schinlong */ 11744048Schinlong (void) __ns_ldap_freeParam( 11754522Schinlong (void ***)&servers); 11764522Schinlong __s_api_free_server_info( 11774522Schinlong &sinfo); 11784048Schinlong } 11794048Schinlong } else { 11804048Schinlong (void) rw_unlock(&sessionPoolLock); 11814048Schinlong syslog(LOG_WARNING, "libsldap: Null " 11824522Schinlong "sinfo.server from " 11834522Schinlong "__s_api_requestServer"); 11844048Schinlong (void) __ns_ldap_freeParam( 11854522Schinlong (void ***)&servers); 11864048Schinlong return (-1); 11874048Schinlong } 11884048Schinlong } 11894048Schinlong } 11904048Schinlong 11910Sstevel@tonic-gate /* found an available connection */ 11922830Sdjl if (MTperConn == 0) 11932830Sdjl cp->usedBit = B_TRUE; 11942830Sdjl else { 11953387Schinlong /* 11963387Schinlong * if connection was established in a different 11973387Schinlong * process, drop it and get a new one 11983387Schinlong */ 11993387Schinlong if (cp->pid != getpid()) { 12003387Schinlong (void) rw_unlock(&sessionPoolLock); 12013387Schinlong DropConnection(cp->connectionId, 12024522Schinlong NS_LDAP_NEW_CONN); 12033387Schinlong 12043387Schinlong goto get_conn; 12053387Schinlong } 12062830Sdjl /* allocate TSD for per thread ldap error */ 12072830Sdjl rc = tsd_setup(); 12082830Sdjl 12092830Sdjl /* if we got TSD, this connection is shared */ 12102830Sdjl if (rc != -1) 12112830Sdjl cp->shared++; 12122830Sdjl else if (cp->shared == 0) { 12132830Sdjl cp->usedBit = B_TRUE; 12142830Sdjl cp->threadID = thr_self(); 12152830Sdjl (void) rw_unlock(&sessionPoolLock); 12162830Sdjl return (-1); 12172830Sdjl } 12182830Sdjl } 12192830Sdjl (void) rw_unlock(&sessionPoolLock); 12202830Sdjl 12210Sstevel@tonic-gate *conp = cp; 12220Sstevel@tonic-gate #ifdef DEBUG 12232830Sdjl (void) fprintf(stderr, "tid= %d: Connection found " 12244522Schinlong "cID=%d, shared =%d\n", t, i, cp->shared); 12250Sstevel@tonic-gate fflush(stderr); 12260Sstevel@tonic-gate #endif /* DEBUG */ 12270Sstevel@tonic-gate return (i + CONID_OFFSET); 12280Sstevel@tonic-gate } 12293387Schinlong 12303387Schinlong get_conn: 12313387Schinlong 12322830Sdjl (void) rw_unlock(&sessionPoolLock); 12332830Sdjl 12342830Sdjl /* 12352830Sdjl * If multiple threads per connection not supported, 12362830Sdjl * we are done, just return -1 to tell the caller to 12372830Sdjl * proceed with opening a connection 12382830Sdjl */ 12392830Sdjl if (MTperConn == 0) 12402830Sdjl return (-1); 12412830Sdjl 12422830Sdjl /* 12432830Sdjl * No connection can be shared, test to see if 12442830Sdjl * one is being opened. If trylock returns 12452830Sdjl * EBUSY then it is, so wait until the opening 12462830Sdjl * is done and try to see if the new connection 12472830Sdjl * can be shared. 12482830Sdjl */ 12492830Sdjl rc = mutex_trylock(&sessionLock); 12502830Sdjl if (rc == EBUSY) { 12512830Sdjl (void) mutex_lock(&sessionLock); 12522830Sdjl (void) mutex_unlock(&sessionLock); 12532830Sdjl (void) rw_rdlock(&sessionPoolLock); 12542830Sdjl #ifdef DEBUG 12552830Sdjl (void) fprintf(stderr, "tid= %d: check session " 12564522Schinlong "pool again\n", t); 12572830Sdjl fflush(stderr); 12582830Sdjl #endif /* DEBUG */ 12592830Sdjl if (try < TRY_TIMES) { 12602830Sdjl try++; 12612830Sdjl goto check_again; 12622830Sdjl } else { 12632830Sdjl syslog(LOG_WARNING, "libsldap: mutex_trylock " 12644522Schinlong "%d times. Stop.", TRY_TIMES); 12653387Schinlong (void) rw_unlock(&sessionPoolLock); 12662830Sdjl return (-1); 12672830Sdjl } 12682830Sdjl } else if (rc == 0) { 12692830Sdjl /* 12702830Sdjl * No connection can be shared, none being opened, 12712830Sdjl * exit with sessionLock locked to open one. The 12722830Sdjl * mutex will be unlocked in addConnection() when 12732830Sdjl * this thread adds the new connection to the pool 12742830Sdjl * or in __s_api_getConnection() when it exits 12752830Sdjl * without getting a connection. 12762830Sdjl */ 12772830Sdjl wait4session = 1; 12782830Sdjl sessionTid = thr_self(); 12792830Sdjl #ifdef DEBUG 12802830Sdjl (void) fprintf(stderr, "tid= %d: no connection found, " 12814522Schinlong "none being opened, get connection ...\n", t); 12822830Sdjl fflush(stderr); 12832830Sdjl #endif /* DEBUG */ 12842830Sdjl return (-1); 12852830Sdjl } else { 12862830Sdjl syslog(LOG_WARNING, "libsldap: mutex_trylock unexpected " 12874522Schinlong "error %d", rc); 12882830Sdjl return (-1); 12892830Sdjl } 12900Sstevel@tonic-gate } 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate /* 12930Sstevel@tonic-gate * Free a Connection structure 12940Sstevel@tonic-gate */ 12950Sstevel@tonic-gate static void 12960Sstevel@tonic-gate freeConnection(Connection *con) 12970Sstevel@tonic-gate { 12980Sstevel@tonic-gate if (con == NULL) 12990Sstevel@tonic-gate return; 13000Sstevel@tonic-gate if (con->serverAddr) 13010Sstevel@tonic-gate free(con->serverAddr); 13020Sstevel@tonic-gate if (con->auth) 13030Sstevel@tonic-gate (void) __ns_ldap_freeCred(&(con->auth)); 13040Sstevel@tonic-gate if (con->saslMechanisms) { 13050Sstevel@tonic-gate __s_api_free2dArray(con->saslMechanisms); 13060Sstevel@tonic-gate } 13070Sstevel@tonic-gate if (con->controls) { 13080Sstevel@tonic-gate __s_api_free2dArray(con->controls); 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate free(con); 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate /* 13140Sstevel@tonic-gate * Find a connection matching the passed in criteria. If an open 13150Sstevel@tonic-gate * connection with that criteria exists use it, otherwise open a 13160Sstevel@tonic-gate * new connection. 13170Sstevel@tonic-gate * Success: returns the pointer to the Connection structure 13180Sstevel@tonic-gate * Failure: returns NULL, error code and message should be in errorp 13190Sstevel@tonic-gate */ 13201687Sjanga 13210Sstevel@tonic-gate static int 13220Sstevel@tonic-gate makeConnection(Connection **conp, const char *serverAddr, 13230Sstevel@tonic-gate const ns_cred_t *auth, ConnectionID *cID, int timeoutSec, 13241179Svv149972 ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd, 13252830Sdjl int nopasswd_acct_mgmt, int flags, char ***badsrvrs) 13260Sstevel@tonic-gate { 13270Sstevel@tonic-gate Connection *con = NULL; 13280Sstevel@tonic-gate ConnectionID id; 13290Sstevel@tonic-gate char errmsg[MAXERROR]; 13300Sstevel@tonic-gate int rc, exit_rc = NS_LDAP_SUCCESS; 13310Sstevel@tonic-gate ns_server_info_t sinfo; 13320Sstevel@tonic-gate char *hReq, *host = NULL; 13330Sstevel@tonic-gate LDAP *ld = NULL; 13340Sstevel@tonic-gate int passwd_mgmt = 0; 13351687Sjanga int totalbad = 0; /* Number of servers contacted unsuccessfully */ 13362830Sdjl short memerr = 0; /* Variable for tracking memory allocation */ 13374522Schinlong char *serverAddrType = NULL, **bindHost = NULL; 13382830Sdjl 13390Sstevel@tonic-gate 13400Sstevel@tonic-gate if (conp == NULL || errorp == NULL || auth == NULL) 13410Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 13420Sstevel@tonic-gate *errorp = NULL; 13430Sstevel@tonic-gate *conp = NULL; 13444522Schinlong (void) memset(&sinfo, 0, sizeof (sinfo)); 13450Sstevel@tonic-gate 13464048Schinlong if ((wait4session == 0 || sessionTid != thr_self()) && 13474522Schinlong (id = findConnection(flags, serverAddr, auth, &con)) != -1) { 13480Sstevel@tonic-gate /* connection found in cache */ 13490Sstevel@tonic-gate #ifdef DEBUG 13502830Sdjl (void) fprintf(stderr, "tid= %d: connection found in " 13514522Schinlong "cache %d\n", thr_self(), id); 13520Sstevel@tonic-gate fflush(stderr); 13530Sstevel@tonic-gate #endif /* DEBUG */ 13540Sstevel@tonic-gate *cID = id; 13550Sstevel@tonic-gate *conp = con; 13560Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 13570Sstevel@tonic-gate } 13580Sstevel@tonic-gate 13594522Schinlong if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 13602830Sdjl serverAddrType = NS_CACHE_ADDR_HOSTNAME; 13614522Schinlong bindHost = &sinfo.serverFQDN; 13624522Schinlong } else { 13632830Sdjl serverAddrType = NS_CACHE_ADDR_IP; 13644522Schinlong bindHost = &sinfo.server; 13654522Schinlong } 13662830Sdjl 13670Sstevel@tonic-gate if (serverAddr) { 13685559Ssdussud /* 13695559Ssdussud * We're given the server address, just use it. 13705559Ssdussud * In case of sasl/GSSAPI, serverAddr would need to be a FQDN. 13715559Ssdussud * We assume this is the case for now. 13725559Ssdussud * 13735559Ssdussud * Only the server address fields of sinfo structure are filled 13745559Ssdussud * in since these are the only relevant data that we have. Other 13755559Ssdussud * fields of this structure (controls, saslMechanisms) are 13765559Ssdussud * kept to NULL. 13775559Ssdussud */ 13785559Ssdussud sinfo.server = strdup(serverAddr); 13795559Ssdussud if (sinfo.server == NULL) { 13805559Ssdussud return (NS_LDAP_MEMORY); 13815559Ssdussud } 13825559Ssdussud if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 13835559Ssdussud sinfo.serverFQDN = strdup(serverAddr); 13845559Ssdussud if (sinfo.serverFQDN == NULL) { 13855559Ssdussud free(sinfo.server); 13865559Ssdussud return (NS_LDAP_MEMORY); 13875559Ssdussud } 13882830Sdjl } 13894522Schinlong rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp, 13904522Schinlong fail_if_new_pwd_reqd, passwd_mgmt); 13910Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || rc == 13924522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 13930Sstevel@tonic-gate exit_rc = rc; 13940Sstevel@tonic-gate goto create_con; 13950Sstevel@tonic-gate } else { 13965559Ssdussud if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 13975559Ssdussud (void) snprintf(errmsg, sizeof (errmsg), 13985559Ssdussud "%s %s", gettext("makeConnection: " 13995559Ssdussud "failed to open connection using " 14005559Ssdussud "sasl/GSSAPI to"), *bindHost); 14015559Ssdussud } else { 14025559Ssdussud (void) snprintf(errmsg, sizeof (errmsg), 14035559Ssdussud "%s %s", gettext("makeConnection: " 14045559Ssdussud "failed to open connection to"), 14055559Ssdussud *bindHost); 14065559Ssdussud } 14075559Ssdussud syslog(LOG_ERR, "libsldap: %s", errmsg); 14085559Ssdussud __s_api_free_server_info(&sinfo); 14090Sstevel@tonic-gate return (rc); 14100Sstevel@tonic-gate } 14110Sstevel@tonic-gate } 14120Sstevel@tonic-gate 14130Sstevel@tonic-gate /* No cached connection, create one */ 14140Sstevel@tonic-gate for (; ; ) { 14150Sstevel@tonic-gate if (host == NULL) 14160Sstevel@tonic-gate hReq = NS_CACHE_NEW; 14170Sstevel@tonic-gate else 14180Sstevel@tonic-gate hReq = NS_CACHE_NEXT; 14192830Sdjl rc = __s_api_requestServer(hReq, host, &sinfo, errorp, 14204522Schinlong serverAddrType); 14210Sstevel@tonic-gate if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) || 14224522Schinlong (host && (strcasecmp(host, sinfo.server) == 0))) { 14230Sstevel@tonic-gate /* Log the error */ 14240Sstevel@tonic-gate if (*errorp) { 14250Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 14260Sstevel@tonic-gate "%s: (%s)", gettext("makeConnection: " 14270Sstevel@tonic-gate "unable to make LDAP connection, " 14280Sstevel@tonic-gate "request for a server failed"), 14290Sstevel@tonic-gate (*errorp)->message); 14300Sstevel@tonic-gate syslog(LOG_ERR, "libsldap: %s", errmsg); 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate 14334522Schinlong __s_api_free_server_info(&sinfo); 14340Sstevel@tonic-gate if (host) 14350Sstevel@tonic-gate free(host); 14360Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 14370Sstevel@tonic-gate } 14380Sstevel@tonic-gate if (host) 14390Sstevel@tonic-gate free(host); 14400Sstevel@tonic-gate host = strdup(sinfo.server); 14410Sstevel@tonic-gate if (host == NULL) { 14424522Schinlong __s_api_free_server_info(&sinfo); 14430Sstevel@tonic-gate return (NS_LDAP_MEMORY); 14440Sstevel@tonic-gate } 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate /* check if server supports password management */ 14470Sstevel@tonic-gate passwd_mgmt = __s_api_contain_passwd_control_oid( 14484522Schinlong sinfo.controls); 14491179Svv149972 /* check if server supports password less account mgmt */ 14501179Svv149972 if (nopasswd_acct_mgmt && 14514522Schinlong !__s_api_contain_account_usable_control_oid( 14524522Schinlong sinfo.controls)) { 14531179Svv149972 syslog(LOG_WARNING, "libsldap: server %s does not " 14544522Schinlong "provide account information without password", 14554522Schinlong host); 14561179Svv149972 free(host); 14574522Schinlong __s_api_free_server_info(&sinfo); 14581179Svv149972 return (NS_LDAP_OP_FAILED); 14591179Svv149972 } 14600Sstevel@tonic-gate /* make the connection */ 14614522Schinlong rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp, 14624522Schinlong fail_if_new_pwd_reqd, passwd_mgmt); 14630Sstevel@tonic-gate /* if success, go to create connection structure */ 14640Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 14654522Schinlong rc == NS_LDAP_SUCCESS_WITH_INFO) { 14660Sstevel@tonic-gate exit_rc = rc; 14670Sstevel@tonic-gate break; 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate /* 14710Sstevel@tonic-gate * If not able to reach the server, inform the ldap 14720Sstevel@tonic-gate * cache manager that the server should be removed 14730Sstevel@tonic-gate * from its server list. Thus, the manager will not 14740Sstevel@tonic-gate * return this server on the next get-server request 14750Sstevel@tonic-gate * and will also reduce the server list refresh TTL, 14760Sstevel@tonic-gate * so that it will find out sooner when the server 14770Sstevel@tonic-gate * is up again. 14780Sstevel@tonic-gate */ 14790Sstevel@tonic-gate if (rc == NS_LDAP_INTERNAL && *errorp != NULL) { 14800Sstevel@tonic-gate if ((*errorp)->status == LDAP_CONNECT_ERROR || 14814522Schinlong (*errorp)->status == LDAP_SERVER_DOWN) { 14821687Sjanga /* Reset memory allocation error */ 14831687Sjanga memerr = 0; 14841687Sjanga /* 14851687Sjanga * We contacted a server that we could 14861687Sjanga * not either authenticate to or contact. 14871687Sjanga * If it is due to authentication, then 14881687Sjanga * we need to try the server again. So, 14891687Sjanga * do not remove the server yet, but 14901687Sjanga * add it to the bad server list. 14911687Sjanga * The caller routine will remove 14921687Sjanga * the servers if: 14931687Sjanga * a). A good server is found or 14941687Sjanga * b). All the possible methods 14951687Sjanga * are tried without finding 14961687Sjanga * a good server 14971687Sjanga */ 14981687Sjanga if (*badsrvrs == NULL) { 14994522Schinlong if (!(*badsrvrs = (char **)malloc 15004522Schinlong (sizeof (char *) * NUMTOMALLOC))) { 15014522Schinlong memerr = 1; 15024522Schinlong } 15031687Sjanga /* Allocate memory in chunks of NUMTOMALLOC */ 15041687Sjanga } else if ((totalbad % NUMTOMALLOC) == 15054522Schinlong NUMTOMALLOC - 1) { 15064522Schinlong char **tmpptr; 15074522Schinlong if (!(tmpptr = (char **)realloc( 15084522Schinlong *badsrvrs, 15091687Sjanga (sizeof (char *) * NUMTOMALLOC * 15101687Sjanga ((totalbad/NUMTOMALLOC) + 2))))) { 15114522Schinlong memerr = 1; 15124522Schinlong } else { 15134522Schinlong *badsrvrs = tmpptr; 15144522Schinlong } 1515493Ssdussud } 15161687Sjanga /* 15171687Sjanga * Store host only if there were no unsuccessful 15181687Sjanga * memory allocations above 15191687Sjanga */ 15201687Sjanga if (!memerr && 15211687Sjanga !((*badsrvrs)[totalbad++] = strdup(host))) { 15221687Sjanga memerr = 1; 15231687Sjanga totalbad--; 15241687Sjanga } 15251687Sjanga (*badsrvrs)[totalbad] = NULL; 1526493Ssdussud } 15270Sstevel@tonic-gate } 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate /* else, cleanup and go for the next server */ 15304522Schinlong __s_api_free_server_info(&sinfo); 15314522Schinlong 15321687Sjanga /* Return if we had memory allocation errors */ 15331687Sjanga if (memerr) 15341687Sjanga return (NS_LDAP_MEMORY); 15350Sstevel@tonic-gate if (*errorp) { 15360Sstevel@tonic-gate /* 15370Sstevel@tonic-gate * If openConnection() failed due to 15380Sstevel@tonic-gate * password policy, or invalid credential, 15390Sstevel@tonic-gate * keep *errorp and exit 15400Sstevel@tonic-gate */ 15410Sstevel@tonic-gate if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD || 15420Sstevel@tonic-gate (*errorp)->status == LDAP_INVALID_CREDENTIALS) { 15430Sstevel@tonic-gate free(host); 15440Sstevel@tonic-gate return (rc); 15450Sstevel@tonic-gate } else { 15460Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 15470Sstevel@tonic-gate *errorp = NULL; 15480Sstevel@tonic-gate } 15490Sstevel@tonic-gate } 15500Sstevel@tonic-gate } 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate create_con: 15530Sstevel@tonic-gate /* we have created ld, setup con structure */ 15540Sstevel@tonic-gate if (host) 15550Sstevel@tonic-gate free(host); 15560Sstevel@tonic-gate if ((con = calloc(1, sizeof (Connection))) == NULL) { 15574522Schinlong __s_api_free_server_info(&sinfo); 15580Sstevel@tonic-gate /* 15590Sstevel@tonic-gate * If password control attached in **errorp, 15600Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 15610Sstevel@tonic-gate * free the error structure 15620Sstevel@tonic-gate */ 15630Sstevel@tonic-gate if (*errorp) { 15640Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 15650Sstevel@tonic-gate *errorp = NULL; 15660Sstevel@tonic-gate } 15675559Ssdussud (void) ldap_unbind(ld); 15680Sstevel@tonic-gate return (NS_LDAP_MEMORY); 15690Sstevel@tonic-gate } 15700Sstevel@tonic-gate 15714522Schinlong con->serverAddr = sinfo.server; /* Store original format */ 15724522Schinlong if (sinfo.serverFQDN != NULL) { 15734522Schinlong free(sinfo.serverFQDN); 15744522Schinlong sinfo.serverFQDN = NULL; 15754522Schinlong } 15760Sstevel@tonic-gate con->saslMechanisms = sinfo.saslMechanisms; 15770Sstevel@tonic-gate con->controls = sinfo.controls; 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate con->auth = __ns_ldap_dupAuth(auth); 15800Sstevel@tonic-gate if (con->auth == NULL) { 15815559Ssdussud (void) ldap_unbind(ld); 15825559Ssdussud freeConnection(con); 15830Sstevel@tonic-gate /* 15840Sstevel@tonic-gate * If password control attached in **errorp, 15850Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 15860Sstevel@tonic-gate * free the error structure 15870Sstevel@tonic-gate */ 15880Sstevel@tonic-gate if (*errorp) { 15890Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 15900Sstevel@tonic-gate *errorp = NULL; 15910Sstevel@tonic-gate } 15920Sstevel@tonic-gate return (NS_LDAP_MEMORY); 15930Sstevel@tonic-gate } 15940Sstevel@tonic-gate 15950Sstevel@tonic-gate con->threadID = thr_self(); 15963387Schinlong con->pid = getpid(); 15972830Sdjl 15980Sstevel@tonic-gate con->ld = ld; 15990Sstevel@tonic-gate if ((id = addConnection(con)) == -1) { 16005559Ssdussud (void) ldap_unbind(ld); 16010Sstevel@tonic-gate freeConnection(con); 16020Sstevel@tonic-gate /* 16030Sstevel@tonic-gate * If password control attached in **errorp, 16040Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 16050Sstevel@tonic-gate * free the error structure 16060Sstevel@tonic-gate */ 16070Sstevel@tonic-gate if (*errorp) { 16080Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 16090Sstevel@tonic-gate *errorp = NULL; 16100Sstevel@tonic-gate } 16110Sstevel@tonic-gate return (NS_LDAP_MEMORY); 16120Sstevel@tonic-gate } 16130Sstevel@tonic-gate #ifdef DEBUG 16142830Sdjl (void) fprintf(stderr, "tid= %d: connection added into " 16154522Schinlong "cache %d\n", thr_self(), id); 16160Sstevel@tonic-gate fflush(stderr); 16170Sstevel@tonic-gate #endif /* DEBUG */ 16180Sstevel@tonic-gate *cID = id; 16190Sstevel@tonic-gate *conp = con; 16200Sstevel@tonic-gate return (exit_rc); 16210Sstevel@tonic-gate } 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate /* 16240Sstevel@tonic-gate * Return the specified connection to the pool. If necessary 16250Sstevel@tonic-gate * delete the connection. 16260Sstevel@tonic-gate */ 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate static void 16290Sstevel@tonic-gate _DropConnection(ConnectionID cID, int flag, int fini) 16300Sstevel@tonic-gate { 16310Sstevel@tonic-gate Connection *cp; 16320Sstevel@tonic-gate int id; 16332830Sdjl int use_lock = !fini; 16342830Sdjl #ifdef DEBUG 16352830Sdjl thread_t t = thr_self(); 16362830Sdjl #endif /* DEBUG */ 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate id = cID - CONID_OFFSET; 16390Sstevel@tonic-gate if (id < 0 || id >= sessionPoolSize) 16400Sstevel@tonic-gate return; 16410Sstevel@tonic-gate #ifdef DEBUG 16422830Sdjl (void) fprintf(stderr, "tid= %d: " 16434522Schinlong "Dropping connection cID=%d flag=0x%x, fini = %d\n", 16444522Schinlong t, cID, flag, fini); 16450Sstevel@tonic-gate fflush(stderr); 16460Sstevel@tonic-gate #endif /* DEBUG */ 16472830Sdjl if (use_lock) 16482830Sdjl (void) rw_wrlock(&sessionPoolLock); 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate cp = sessionPool[id]; 16510Sstevel@tonic-gate /* sanity check before removing */ 16524048Schinlong if (!cp || (!fini && !cp->shared && !cp->usedBit)) { 16532830Sdjl #ifdef DEBUG 16542830Sdjl if (cp == NULL) 16552830Sdjl (void) fprintf(stderr, "tid= %d: no " 16564522Schinlong "need to remove (fini = %d, cp = %p)\n", t, 16574522Schinlong fini, cp); 16582830Sdjl else 16592830Sdjl (void) fprintf(stderr, "tid= %d: no " 16604522Schinlong "need to remove (fini = %d, cp = %p, shared = %d)" 16614522Schinlong "\n", t, fini, cp, cp->shared); 16622830Sdjl fflush(stderr); 16632830Sdjl #endif /* DEBUG */ 16642830Sdjl if (use_lock) 16652830Sdjl (void) rw_unlock(&sessionPoolLock); 16660Sstevel@tonic-gate return; 16670Sstevel@tonic-gate } 16680Sstevel@tonic-gate 16690Sstevel@tonic-gate if (!fini && 16704522Schinlong ((flag & NS_LDAP_NEW_CONN) == 0) && !cp->notAvail && 16715532Smj162486 ((flag & NS_LDAP_KEEP_CONN) || __s_api_nscd_proc())) { 16722830Sdjl #ifdef DEBUG 16732830Sdjl (void) fprintf(stderr, "tid= %d: keep alive (fini = %d " 16744522Schinlong "shared = %d)\n", t, fini, cp->shared); 16752830Sdjl #endif /* DEBUG */ 16760Sstevel@tonic-gate /* release Connection (keep alive) */ 16772830Sdjl if (cp->shared) 16782830Sdjl cp->shared--; 16790Sstevel@tonic-gate cp->usedBit = B_FALSE; 16800Sstevel@tonic-gate cp->threadID = 0; /* unmark the threadID */ 16812830Sdjl if (use_lock) 16822830Sdjl (void) rw_unlock(&sessionPoolLock); 16830Sstevel@tonic-gate } else { 16840Sstevel@tonic-gate /* delete Connection (disconnect) */ 16852830Sdjl if (cp->shared > 0) { 16862830Sdjl #ifdef DEBUG 16872830Sdjl (void) fprintf(stderr, "tid= %d: Connection no " 16884522Schinlong "longer available (fini = %d, shared = %d)\n", 16894522Schinlong t, fini, cp->shared); 16902830Sdjl fflush(stderr); 16912830Sdjl #endif /* DEBUG */ 16922830Sdjl cp->shared--; 16933387Schinlong /* 16943387Schinlong * Mark this connection not available and decrement 16953387Schinlong * sharedConnNumber. There could be multiple threads 16963387Schinlong * sharing this connection so decrement 16973387Schinlong * sharedConnNumber only once per connection. 16983387Schinlong */ 16993387Schinlong if (cp->notAvail == 0) { 17003387Schinlong cp->notAvail = 1; 17013387Schinlong (void) mutex_lock(&sharedConnNumberLock); 17023387Schinlong sharedConnNumber--; 17033387Schinlong (void) mutex_unlock(&sharedConnNumberLock); 17043387Schinlong } 17052830Sdjl } 17062830Sdjl 17072830Sdjl if (cp->shared <= 0) { 17082830Sdjl #ifdef DEBUG 17092830Sdjl (void) fprintf(stderr, "tid= %d: unbind " 17104522Schinlong "(fini = %d, shared = %d)\n", 17114522Schinlong t, fini, cp->shared); 17122830Sdjl fflush(stderr); 17132830Sdjl #endif /* DEBUG */ 17142830Sdjl sessionPool[id] = NULL; 17152830Sdjl (void) ldap_unbind(cp->ld); 17162830Sdjl freeConnection(cp); 17172830Sdjl } 17182830Sdjl 17192830Sdjl if (use_lock) 17202830Sdjl (void) rw_unlock(&sessionPoolLock); 17210Sstevel@tonic-gate } 17220Sstevel@tonic-gate } 17230Sstevel@tonic-gate 17240Sstevel@tonic-gate void 17250Sstevel@tonic-gate DropConnection(ConnectionID cID, int flag) 17260Sstevel@tonic-gate { 17270Sstevel@tonic-gate _DropConnection(cID, flag, 0); 17280Sstevel@tonic-gate } 17290Sstevel@tonic-gate 17300Sstevel@tonic-gate /* 17310Sstevel@tonic-gate * This routine is called after a bind operation is 17320Sstevel@tonic-gate * done in openConnection() to process the password 17330Sstevel@tonic-gate * management information, if any. 17340Sstevel@tonic-gate * 17350Sstevel@tonic-gate * Input: 17360Sstevel@tonic-gate * bind_type: "simple" or "sasl/DIGEST-MD5" 17370Sstevel@tonic-gate * ldaprc : ldap rc from the ldap bind operation 17380Sstevel@tonic-gate * controls : controls returned by the server 17390Sstevel@tonic-gate * errmsg : error message from the server 17400Sstevel@tonic-gate * fail_if_new_pwd_reqd: 17410Sstevel@tonic-gate * flag indicating if connection should be open 17420Sstevel@tonic-gate * when password needs to change immediately 17430Sstevel@tonic-gate * passwd_mgmt: 17440Sstevel@tonic-gate * flag indicating if server supports password 17450Sstevel@tonic-gate * policy/management 17460Sstevel@tonic-gate * 17470Sstevel@tonic-gate * Output : ns_ldap_error structure, which may contain 17480Sstevel@tonic-gate * password status and number of seconds until 17490Sstevel@tonic-gate * expired 17500Sstevel@tonic-gate * 17510Sstevel@tonic-gate * return rc: 17520Sstevel@tonic-gate * NS_LDAP_EXTERNAL: error, connection should not open 17530Sstevel@tonic-gate * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached 17540Sstevel@tonic-gate * NS_LDAP_SUCCESS: OK to open connection 17550Sstevel@tonic-gate * 17560Sstevel@tonic-gate */ 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate static int 17590Sstevel@tonic-gate process_pwd_mgmt(char *bind_type, int ldaprc, 17600Sstevel@tonic-gate LDAPControl **controls, 17610Sstevel@tonic-gate char *errmsg, ns_ldap_error_t **errorp, 17620Sstevel@tonic-gate int fail_if_new_pwd_reqd, 17630Sstevel@tonic-gate int passwd_mgmt) 17640Sstevel@tonic-gate { 17650Sstevel@tonic-gate char errstr[MAXERROR]; 17660Sstevel@tonic-gate LDAPControl **ctrl = NULL; 17670Sstevel@tonic-gate int exit_rc; 17680Sstevel@tonic-gate ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD; 17690Sstevel@tonic-gate int sec_until_exp = 0; 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate /* 17720Sstevel@tonic-gate * errmsg may be an empty string, 17730Sstevel@tonic-gate * even if ldaprc is LDAP_SUCCESS, 17740Sstevel@tonic-gate * free the empty string if that's the case 17750Sstevel@tonic-gate */ 17760Sstevel@tonic-gate if (errmsg && 17774522Schinlong (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) { 17780Sstevel@tonic-gate ldap_memfree(errmsg); 17790Sstevel@tonic-gate errmsg = NULL; 17800Sstevel@tonic-gate } 17810Sstevel@tonic-gate 17820Sstevel@tonic-gate if (ldaprc != LDAP_SUCCESS) { 17830Sstevel@tonic-gate /* 17840Sstevel@tonic-gate * try to map ldap rc and error message to 17850Sstevel@tonic-gate * a password status 17860Sstevel@tonic-gate */ 17870Sstevel@tonic-gate if (errmsg) { 17880Sstevel@tonic-gate if (passwd_mgmt) 17890Sstevel@tonic-gate pwd_status = 17904522Schinlong __s_api_set_passwd_status( 17914522Schinlong ldaprc, errmsg); 17920Sstevel@tonic-gate ldap_memfree(errmsg); 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 17964522Schinlong gettext("openConnection: " 17974522Schinlong "%s bind failed " 17984522Schinlong "- %s"), bind_type, ldap_err2string(ldaprc)); 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate if (pwd_status != NS_PASSWD_GOOD) { 18010Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 18024522Schinlong ldaprc, strdup(errstr), 18034522Schinlong pwd_status, 0, NULL); 18040Sstevel@tonic-gate } else { 18050Sstevel@tonic-gate MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr), 18064522Schinlong NULL); 18070Sstevel@tonic-gate } 18080Sstevel@tonic-gate if (controls) 18090Sstevel@tonic-gate ldap_controls_free(controls); 18100Sstevel@tonic-gate 18110Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 18120Sstevel@tonic-gate } 18130Sstevel@tonic-gate 18140Sstevel@tonic-gate /* 18150Sstevel@tonic-gate * ldaprc is LDAP_SUCCESS, 18160Sstevel@tonic-gate * process the password management controls, if any 18170Sstevel@tonic-gate */ 18180Sstevel@tonic-gate exit_rc = NS_LDAP_SUCCESS; 18190Sstevel@tonic-gate if (controls && passwd_mgmt) { 18200Sstevel@tonic-gate /* 18210Sstevel@tonic-gate * The control with the OID 18220Sstevel@tonic-gate * 2.16.840.1.113730.3.4.4 (or 18230Sstevel@tonic-gate * LDAP_CONTROL_PWEXPIRED, as defined 18240Sstevel@tonic-gate * in the ldap.h header file) is the 18250Sstevel@tonic-gate * expired password control. 18260Sstevel@tonic-gate * 18270Sstevel@tonic-gate * This control is used if the server 18280Sstevel@tonic-gate * is configured to require users to 18290Sstevel@tonic-gate * change their passwords when first 18300Sstevel@tonic-gate * logging in and whenever the 18310Sstevel@tonic-gate * passwords are reset. 18320Sstevel@tonic-gate * 18330Sstevel@tonic-gate * If the user is logging in for the 18340Sstevel@tonic-gate * first time or if the user's 18350Sstevel@tonic-gate * password has been reset, the 18360Sstevel@tonic-gate * server sends this control to 18370Sstevel@tonic-gate * indicate that the client needs to 18380Sstevel@tonic-gate * change the password immediately. 18390Sstevel@tonic-gate * 18400Sstevel@tonic-gate * At this point, the only operation 18410Sstevel@tonic-gate * that the client can perform is to 18420Sstevel@tonic-gate * change the user's password. If the 18430Sstevel@tonic-gate * client requests any other LDAP 18440Sstevel@tonic-gate * operation, the server sends back 18450Sstevel@tonic-gate * an LDAP_UNWILLING_TO_PERFORM 18460Sstevel@tonic-gate * result code with an expired 18470Sstevel@tonic-gate * password control. 18480Sstevel@tonic-gate * 18490Sstevel@tonic-gate * The control with the OID 18500Sstevel@tonic-gate * 2.16.840.1.113730.3.4.5 (or 18510Sstevel@tonic-gate * LDAP_CONTROL_PWEXPIRING, as 18520Sstevel@tonic-gate * defined in the ldap.h header file) 18530Sstevel@tonic-gate * is the password expiration warning 18540Sstevel@tonic-gate * control. 18550Sstevel@tonic-gate * 18560Sstevel@tonic-gate * This control is used if the server 18570Sstevel@tonic-gate * is configured to expire user 18580Sstevel@tonic-gate * passwords after a certain amount 18590Sstevel@tonic-gate * of time. 18600Sstevel@tonic-gate * 18610Sstevel@tonic-gate * The server sends this control back 18620Sstevel@tonic-gate * to the client if the client binds 18630Sstevel@tonic-gate * using a password that will soon 18640Sstevel@tonic-gate * expire. The ldctl_value field of 18650Sstevel@tonic-gate * the LDAPControl structure 18660Sstevel@tonic-gate * specifies the number of seconds 18670Sstevel@tonic-gate * before the password will expire. 18680Sstevel@tonic-gate */ 18690Sstevel@tonic-gate for (ctrl = controls; *ctrl; ctrl++) { 18700Sstevel@tonic-gate 18710Sstevel@tonic-gate if (strcmp((*ctrl)->ldctl_oid, 18724522Schinlong LDAP_CONTROL_PWEXPIRED) == 0) { 18730Sstevel@tonic-gate /* 18740Sstevel@tonic-gate * if the caller wants this bind 18750Sstevel@tonic-gate * to fail, set up the error info. 18760Sstevel@tonic-gate * If call to this function is 18770Sstevel@tonic-gate * for searching the LDAP directory, 18780Sstevel@tonic-gate * e.g., __ns_ldap_list(), 18790Sstevel@tonic-gate * there's really no sense to 18800Sstevel@tonic-gate * let a connection open and 18810Sstevel@tonic-gate * then fail immediately afterward 18820Sstevel@tonic-gate * on the LDAP search operation with 18830Sstevel@tonic-gate * the LDAP_UNWILLING_TO_PERFORM rc 18840Sstevel@tonic-gate */ 18850Sstevel@tonic-gate pwd_status = 18864522Schinlong NS_PASSWD_CHANGE_NEEDED; 18870Sstevel@tonic-gate if (fail_if_new_pwd_reqd) { 18880Sstevel@tonic-gate (void) snprintf(errstr, 18894522Schinlong sizeof (errstr), 18904522Schinlong gettext( 18914522Schinlong "openConnection: " 18924522Schinlong "%s bind " 18934522Schinlong "failed " 18944522Schinlong "- password " 18954522Schinlong "expired. It " 18964522Schinlong " needs to change " 18974522Schinlong "immediately!"), 18984522Schinlong bind_type); 18990Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 19004522Schinlong LDAP_SUCCESS, 19014522Schinlong strdup(errstr), 19024522Schinlong pwd_status, 19034522Schinlong 0, 19044522Schinlong NULL); 19050Sstevel@tonic-gate exit_rc = NS_LDAP_INTERNAL; 19060Sstevel@tonic-gate } else { 19070Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 19084522Schinlong LDAP_SUCCESS, 19094522Schinlong NULL, 19104522Schinlong pwd_status, 19114522Schinlong 0, 19124522Schinlong NULL); 19130Sstevel@tonic-gate exit_rc = 19144522Schinlong NS_LDAP_SUCCESS_WITH_INFO; 19150Sstevel@tonic-gate } 19160Sstevel@tonic-gate break; 19170Sstevel@tonic-gate } else if (strcmp((*ctrl)->ldctl_oid, 19184522Schinlong LDAP_CONTROL_PWEXPIRING) == 0) { 19190Sstevel@tonic-gate pwd_status = 19204522Schinlong NS_PASSWD_ABOUT_TO_EXPIRE; 19210Sstevel@tonic-gate if ((*ctrl)-> 19224522Schinlong ldctl_value.bv_len > 0 && 19234522Schinlong (*ctrl)-> 19244522Schinlong ldctl_value.bv_val) 19250Sstevel@tonic-gate sec_until_exp = 19264522Schinlong atoi((*ctrl)-> 19274522Schinlong ldctl_value.bv_val); 19280Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 19294522Schinlong LDAP_SUCCESS, 19304522Schinlong NULL, 19314522Schinlong pwd_status, 19324522Schinlong sec_until_exp, 19334522Schinlong NULL); 19340Sstevel@tonic-gate exit_rc = 19354522Schinlong NS_LDAP_SUCCESS_WITH_INFO; 19360Sstevel@tonic-gate break; 19370Sstevel@tonic-gate } 19380Sstevel@tonic-gate } 19390Sstevel@tonic-gate } 19400Sstevel@tonic-gate 19410Sstevel@tonic-gate if (controls) 19420Sstevel@tonic-gate ldap_controls_free(controls); 19430Sstevel@tonic-gate 19440Sstevel@tonic-gate return (exit_rc); 19450Sstevel@tonic-gate } 19460Sstevel@tonic-gate 19470Sstevel@tonic-gate static int 19480Sstevel@tonic-gate ldap_in_hosts_switch() 19490Sstevel@tonic-gate { 19500Sstevel@tonic-gate enum __nsw_parse_err pserr; 19510Sstevel@tonic-gate struct __nsw_switchconfig *conf; 19520Sstevel@tonic-gate struct __nsw_lookup *lkp; 19530Sstevel@tonic-gate const char *name; 19540Sstevel@tonic-gate int found = 0; 19550Sstevel@tonic-gate 19560Sstevel@tonic-gate conf = __nsw_getconfig("hosts", &pserr); 19570Sstevel@tonic-gate if (conf == NULL) { 19580Sstevel@tonic-gate return (-1); 19590Sstevel@tonic-gate } 19600Sstevel@tonic-gate 19610Sstevel@tonic-gate /* check for skip and count other backends */ 19620Sstevel@tonic-gate for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 19630Sstevel@tonic-gate name = lkp->service_name; 19640Sstevel@tonic-gate if (strcmp(name, "ldap") == 0) { 19650Sstevel@tonic-gate found = 1; 19660Sstevel@tonic-gate break; 19670Sstevel@tonic-gate } 19680Sstevel@tonic-gate } 19690Sstevel@tonic-gate __nsw_freeconfig(conf); 19700Sstevel@tonic-gate return (found); 19710Sstevel@tonic-gate } 19720Sstevel@tonic-gate 19730Sstevel@tonic-gate static int 19740Sstevel@tonic-gate openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, 19750Sstevel@tonic-gate int timeoutSec, ns_ldap_error_t **errorp, 19760Sstevel@tonic-gate int fail_if_new_pwd_reqd, int passwd_mgmt) 19770Sstevel@tonic-gate { 19780Sstevel@tonic-gate LDAP *ld = NULL; 19790Sstevel@tonic-gate char *binddn, *passwd; 19800Sstevel@tonic-gate char *digest_md5_name; 19810Sstevel@tonic-gate const char *s; 19820Sstevel@tonic-gate int ldapVersion = LDAP_VERSION3; 19830Sstevel@tonic-gate int derefOption = LDAP_DEREF_ALWAYS; 19840Sstevel@tonic-gate int zero = 0; 19850Sstevel@tonic-gate int rc; 19860Sstevel@tonic-gate char errstr[MAXERROR]; 19870Sstevel@tonic-gate int errnum = 0; 19880Sstevel@tonic-gate LDAPMessage *resultMsg; 19890Sstevel@tonic-gate int msgId; 19902830Sdjl int useSSL = 0, port = 0; 19910Sstevel@tonic-gate struct timeval tv; 19920Sstevel@tonic-gate AuthType_t bindType; 19930Sstevel@tonic-gate int timeoutMilliSec = timeoutSec * 1000; 19940Sstevel@tonic-gate struct berval cred; 19950Sstevel@tonic-gate char *sslServerAddr; 19960Sstevel@tonic-gate char *s1; 19972830Sdjl char *errmsg, *end = NULL; 19980Sstevel@tonic-gate LDAPControl **controls; 19992830Sdjl int pwd_rc, min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF; 20002830Sdjl ns_sasl_cb_param_t sasl_param; 20010Sstevel@tonic-gate 20020Sstevel@tonic-gate *errorp = NULL; 20030Sstevel@tonic-gate *ldp = NULL; 20040Sstevel@tonic-gate 20050Sstevel@tonic-gate switch (auth->auth.type) { 20060Sstevel@tonic-gate case NS_LDAP_AUTH_NONE: 20070Sstevel@tonic-gate case NS_LDAP_AUTH_SIMPLE: 20080Sstevel@tonic-gate case NS_LDAP_AUTH_SASL: 20090Sstevel@tonic-gate bindType = auth->auth.type; 20100Sstevel@tonic-gate break; 20110Sstevel@tonic-gate case NS_LDAP_AUTH_TLS: 20120Sstevel@tonic-gate useSSL = 1; 20130Sstevel@tonic-gate switch (auth->auth.tlstype) { 20140Sstevel@tonic-gate case NS_LDAP_TLS_NONE: 20150Sstevel@tonic-gate bindType = NS_LDAP_AUTH_NONE; 20160Sstevel@tonic-gate break; 20170Sstevel@tonic-gate case NS_LDAP_TLS_SIMPLE: 20180Sstevel@tonic-gate bindType = NS_LDAP_AUTH_SIMPLE; 20190Sstevel@tonic-gate break; 20200Sstevel@tonic-gate case NS_LDAP_TLS_SASL: 20210Sstevel@tonic-gate bindType = NS_LDAP_AUTH_SASL; 20220Sstevel@tonic-gate break; 20230Sstevel@tonic-gate default: 20240Sstevel@tonic-gate (void) sprintf(errstr, 20250Sstevel@tonic-gate gettext("openConnection: unsupported " 20264522Schinlong "TLS authentication method " 20274522Schinlong "(%d)"), auth->auth.tlstype); 20280Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, 20294522Schinlong LDAP_AUTH_METHOD_NOT_SUPPORTED, 20304522Schinlong strdup(errstr), NULL); 20310Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 20320Sstevel@tonic-gate } 20330Sstevel@tonic-gate break; 20340Sstevel@tonic-gate default: 20350Sstevel@tonic-gate (void) sprintf(errstr, 20364522Schinlong gettext("openConnection: unsupported " 20374522Schinlong "authentication method (%d)"), auth->auth.type); 20380Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, 20394522Schinlong LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 20404522Schinlong NULL); 20410Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 20420Sstevel@tonic-gate } 20430Sstevel@tonic-gate 20440Sstevel@tonic-gate if (useSSL) { 20450Sstevel@tonic-gate const char *hostcertpath; 20460Sstevel@tonic-gate char *alloc_hcp = NULL; 20470Sstevel@tonic-gate #ifdef DEBUG 20482830Sdjl (void) fprintf(stderr, "tid= %d: +++TLS transport\n", 20494522Schinlong thr_self()); 20500Sstevel@tonic-gate #endif /* DEBUG */ 20512333Sjanga 20522333Sjanga if (prldap_set_session_option(NULL, NULL, 20532333Sjanga PRLDAP_OPT_IO_MAX_TIMEOUT, 20542333Sjanga timeoutMilliSec) != LDAP_SUCCESS) { 20552333Sjanga (void) snprintf(errstr, sizeof (errstr), 20564522Schinlong gettext("openConnection: failed to initialize " 20574522Schinlong "TLS security")); 20582333Sjanga MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 20594522Schinlong strdup(errstr), NULL); 20602333Sjanga return (NS_LDAP_INTERNAL); 20612333Sjanga } 20622333Sjanga 20630Sstevel@tonic-gate hostcertpath = auth->hostcertpath; 20640Sstevel@tonic-gate if (hostcertpath == NULL) { 20650Sstevel@tonic-gate alloc_hcp = __s_get_hostcertpath(); 20660Sstevel@tonic-gate hostcertpath = alloc_hcp; 20670Sstevel@tonic-gate } 20680Sstevel@tonic-gate 20690Sstevel@tonic-gate if (hostcertpath == NULL) 20700Sstevel@tonic-gate return (NS_LDAP_MEMORY); 20710Sstevel@tonic-gate 20720Sstevel@tonic-gate if ((rc = ldapssl_client_init(hostcertpath, NULL)) < 0) { 20730Sstevel@tonic-gate if (alloc_hcp) 20740Sstevel@tonic-gate free(alloc_hcp); 20750Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 20764522Schinlong gettext("openConnection: failed to initialize " 20774522Schinlong "TLS security (%s)"), 20784522Schinlong ldapssl_err2string(rc)); 20790Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 20804522Schinlong strdup(errstr), NULL); 20810Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 20820Sstevel@tonic-gate } 20830Sstevel@tonic-gate if (alloc_hcp) 20840Sstevel@tonic-gate free(alloc_hcp); 20850Sstevel@tonic-gate 20860Sstevel@tonic-gate /* determine if the host name contains a port number */ 20870Sstevel@tonic-gate s = strchr(serverAddr, ']'); /* skip over ipv6 addr */ 20880Sstevel@tonic-gate if (s == NULL) 20890Sstevel@tonic-gate s = serverAddr; 20900Sstevel@tonic-gate s = strchr(s, ':'); 20910Sstevel@tonic-gate if (s != NULL) { 20920Sstevel@tonic-gate /* 20930Sstevel@tonic-gate * If we do get a port number, we will try stripping 20940Sstevel@tonic-gate * it. At present, referrals will always have a 20950Sstevel@tonic-gate * port number. 20960Sstevel@tonic-gate */ 20970Sstevel@tonic-gate sslServerAddr = strdup(serverAddr); 20980Sstevel@tonic-gate if (sslServerAddr == NULL) 20990Sstevel@tonic-gate return (NS_LDAP_MEMORY); 21000Sstevel@tonic-gate s1 = strrchr(sslServerAddr, ':'); 21010Sstevel@tonic-gate if (s1 != NULL) 21020Sstevel@tonic-gate *s1 = '\0'; 21030Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 21040Sstevel@tonic-gate gettext("openConnection: cannot use tls with %s. " 21054522Schinlong "Trying %s"), 21064522Schinlong serverAddr, sslServerAddr); 21070Sstevel@tonic-gate syslog(LOG_ERR, "libsldap: %s", errstr); 21080Sstevel@tonic-gate } else 21090Sstevel@tonic-gate sslServerAddr = (char *)serverAddr; 21100Sstevel@tonic-gate 21110Sstevel@tonic-gate ld = ldapssl_init(sslServerAddr, LDAPS_PORT, 1); 21120Sstevel@tonic-gate 21130Sstevel@tonic-gate if (sslServerAddr != serverAddr) 21140Sstevel@tonic-gate free(sslServerAddr); 21150Sstevel@tonic-gate 21160Sstevel@tonic-gate if (ld == NULL || 21170Sstevel@tonic-gate ldapssl_install_gethostbyaddr(ld, "ldap") != 0) { 21180Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 21194522Schinlong gettext("openConnection: failed to connect " 21204522Schinlong "using TLS (%s)"), strerror(errno)); 21210Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 21224522Schinlong strdup(errstr), NULL); 21230Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 21240Sstevel@tonic-gate } 21250Sstevel@tonic-gate } else { 21260Sstevel@tonic-gate #ifdef DEBUG 21272830Sdjl (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n", 21284522Schinlong thr_self()); 21290Sstevel@tonic-gate #endif /* DEBUG */ 21302830Sdjl port = LDAP_PORT; 21312830Sdjl if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI && 21324522Schinlong (end = strchr(serverAddr, ':')) != NULL) { 21332830Sdjl /* 21342830Sdjl * The IP is converted to hostname so it's a 21352830Sdjl * hostname:port up to this point. 21362830Sdjl * 21372830Sdjl * libldap passes hostname:port to the sasl layer. 21382830Sdjl * The ldap service principal is constructed as 21392830Sdjl * ldap/hostname:port@REALM. Kerberos authentication 21402830Sdjl * will fail. So it needs to be parsed to construct 21412830Sdjl * a valid principal ldap/hostname@REALM. 21422830Sdjl * 21432830Sdjl * For useSSL case above, it already parses port so 21442830Sdjl * no need to parse serverAddr 21452830Sdjl */ 21462830Sdjl *end = '\0'; 21472830Sdjl port = atoi(end + 1); 21482830Sdjl } 21492830Sdjl 21502830Sdjl /* Warning message IF cannot connect to host(s) */ 21512830Sdjl if ((ld = ldap_init((char *)serverAddr, port)) == NULL) { 21520Sstevel@tonic-gate char *p = strerror(errno); 21530Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 21544522Schinlong strdup(p), NULL); 21552830Sdjl if (end) 21562830Sdjl *end = ':'; 21570Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 21580Sstevel@tonic-gate } else { 21592830Sdjl if (end) 21602830Sdjl *end = ':'; 21610Sstevel@tonic-gate /* check and avoid gethostname recursion */ 21620Sstevel@tonic-gate if (ldap_in_hosts_switch() > 0 && 21634522Schinlong ! __s_api_isipv4((char *)serverAddr) && 21644522Schinlong ! __s_api_isipv6((char *)serverAddr)) { 21650Sstevel@tonic-gate /* host: ldap - found, attempt to recover */ 21660Sstevel@tonic-gate if (ldap_set_option(ld, LDAP_X_OPT_DNS_SKIPDB, 21674522Schinlong "ldap") != 0) { 21684522Schinlong (void) snprintf(errstr, sizeof (errstr), 21692830Sdjl gettext("openConnection: " 21702830Sdjl "unrecoverable gethostname " 21712830Sdjl "recursion detected " 21722830Sdjl "in /etc/nsswitch.conf")); 21734522Schinlong MKERROR(LOG_WARNING, *errorp, 21742830Sdjl LDAP_CONNECT_ERROR, 21752830Sdjl strdup(errstr), NULL); 21764522Schinlong (void) ldap_unbind(ld); 21774522Schinlong return (NS_LDAP_INTERNAL); 21780Sstevel@tonic-gate } 21790Sstevel@tonic-gate } 21800Sstevel@tonic-gate } 21810Sstevel@tonic-gate } 21820Sstevel@tonic-gate 21832830Sdjl ns_setup_mt_conn_and_tsd(ld); 21840Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); 21850Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 21860Sstevel@tonic-gate /* 21870Sstevel@tonic-gate * set LDAP_OPT_REFERRALS to OFF. 21880Sstevel@tonic-gate * This library will handle the referral itself 21890Sstevel@tonic-gate * based on API flags or configuration file 21900Sstevel@tonic-gate * specification. If this option is not set 21910Sstevel@tonic-gate * to OFF, libldap will never pass the 21920Sstevel@tonic-gate * referral info up to this library 21930Sstevel@tonic-gate */ 21940Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 21950Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 21960Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 21970Sstevel@tonic-gate /* setup TCP/IP connect timeout */ 21980Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 21994522Schinlong &timeoutMilliSec); 22000Sstevel@tonic-gate /* retry if LDAP I/O was interrupted */ 22010Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate switch (bindType) { 22040Sstevel@tonic-gate case NS_LDAP_AUTH_NONE: 22050Sstevel@tonic-gate #ifdef DEBUG 22062830Sdjl (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n", 22074522Schinlong thr_self()); 22080Sstevel@tonic-gate #endif /* DEBUG */ 22090Sstevel@tonic-gate break; 22100Sstevel@tonic-gate case NS_LDAP_AUTH_SIMPLE: 22110Sstevel@tonic-gate binddn = auth->cred.unix_cred.userID; 22120Sstevel@tonic-gate passwd = auth->cred.unix_cred.passwd; 22130Sstevel@tonic-gate if (passwd == NULL || *passwd == '\0' || 22140Sstevel@tonic-gate binddn == NULL || *binddn == '\0') { 22150Sstevel@tonic-gate (void) sprintf(errstr, gettext("openConnection: " 22164522Schinlong "missing credentials for Simple bind")); 22170Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, 22184522Schinlong strdup(errstr), NULL); 22190Sstevel@tonic-gate (void) ldap_unbind(ld); 22200Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 22210Sstevel@tonic-gate } 22220Sstevel@tonic-gate 22230Sstevel@tonic-gate #ifdef DEBUG 22242830Sdjl (void) fprintf(stderr, "tid= %d: +++Simple bind\n", 22254522Schinlong thr_self()); 22260Sstevel@tonic-gate #endif /* DEBUG */ 22270Sstevel@tonic-gate msgId = ldap_simple_bind(ld, binddn, passwd); 22280Sstevel@tonic-gate 22290Sstevel@tonic-gate if (msgId == -1) { 22300Sstevel@tonic-gate (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 22314522Schinlong (void *)&errnum); 22320Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 22334522Schinlong gettext("openConnection: simple bind failed " 22344522Schinlong "- %s"), ldap_err2string(errnum)); 22350Sstevel@tonic-gate (void) ldap_unbind(ld); 22360Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 22374522Schinlong NULL); 22380Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 22390Sstevel@tonic-gate } 22400Sstevel@tonic-gate 22410Sstevel@tonic-gate tv.tv_sec = timeoutSec; 22420Sstevel@tonic-gate tv.tv_usec = 0; 22430Sstevel@tonic-gate rc = ldap_result(ld, msgId, 0, &tv, &resultMsg); 22440Sstevel@tonic-gate 22450Sstevel@tonic-gate if ((rc == -1) || (rc == 0)) { 22460Sstevel@tonic-gate (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 22474522Schinlong (void *)&errnum); 22480Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 22494522Schinlong gettext("openConnection: simple bind failed " 22504522Schinlong "- %s"), ldap_err2string(errnum)); 22510Sstevel@tonic-gate (void) ldap_msgfree(resultMsg); 22520Sstevel@tonic-gate (void) ldap_unbind(ld); 22530Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 22544522Schinlong NULL); 22550Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 22560Sstevel@tonic-gate } 22570Sstevel@tonic-gate 22580Sstevel@tonic-gate /* 22590Sstevel@tonic-gate * get ldaprc, controls, and error msg 22600Sstevel@tonic-gate */ 22610Sstevel@tonic-gate rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 22624522Schinlong &errmsg, NULL, &controls, 1); 22630Sstevel@tonic-gate 22640Sstevel@tonic-gate if (rc != LDAP_SUCCESS) { 22650Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 22664522Schinlong gettext("openConnection: simple bind failed " 22674522Schinlong "- unable to parse result")); 22680Sstevel@tonic-gate (void) ldap_unbind(ld); 22690Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 22704522Schinlong strdup(errstr), NULL); 22710Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 22720Sstevel@tonic-gate } 22730Sstevel@tonic-gate 22740Sstevel@tonic-gate /* process the password management info, if any */ 22750Sstevel@tonic-gate pwd_rc = process_pwd_mgmt("simple", 22764522Schinlong errnum, controls, errmsg, 22774522Schinlong errorp, 22784522Schinlong fail_if_new_pwd_reqd, 22794522Schinlong passwd_mgmt); 22800Sstevel@tonic-gate 22810Sstevel@tonic-gate if (pwd_rc == NS_LDAP_INTERNAL) { 22820Sstevel@tonic-gate (void) ldap_unbind(ld); 22830Sstevel@tonic-gate return (pwd_rc); 22840Sstevel@tonic-gate } 22850Sstevel@tonic-gate 22860Sstevel@tonic-gate if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) { 22870Sstevel@tonic-gate *ldp = ld; 22880Sstevel@tonic-gate return (pwd_rc); 22890Sstevel@tonic-gate } 22900Sstevel@tonic-gate 22910Sstevel@tonic-gate break; 22920Sstevel@tonic-gate case NS_LDAP_AUTH_SASL: 22932830Sdjl if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE && 22944522Schinlong auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 22950Sstevel@tonic-gate (void) sprintf(errstr, 22964522Schinlong gettext("openConnection: SASL options are " 22974522Schinlong "not supported (%d) for non-GSSAPI sasl bind"), 22984522Schinlong auth->auth.saslopt); 22990Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, 23004522Schinlong LDAP_AUTH_METHOD_NOT_SUPPORTED, 23014522Schinlong strdup(errstr), NULL); 23020Sstevel@tonic-gate (void) ldap_unbind(ld); 23030Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23040Sstevel@tonic-gate } 23052830Sdjl if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 23062830Sdjl binddn = auth->cred.unix_cred.userID; 23072830Sdjl passwd = auth->cred.unix_cred.passwd; 23082830Sdjl if (passwd == NULL || *passwd == '\0' || 23094522Schinlong binddn == NULL || *binddn == '\0') { 23102830Sdjl (void) sprintf(errstr, 23114522Schinlong gettext("openConnection: missing " 23124522Schinlong "credentials for SASL bind")); 23132830Sdjl MKERROR(LOG_WARNING, *errorp, 23144522Schinlong LDAP_INVALID_CREDENTIALS, 23154522Schinlong strdup(errstr), NULL); 23162830Sdjl (void) ldap_unbind(ld); 23172830Sdjl return (NS_LDAP_INTERNAL); 23182830Sdjl } 23192830Sdjl cred.bv_val = passwd; 23202830Sdjl cred.bv_len = strlen(passwd); 23210Sstevel@tonic-gate } 23220Sstevel@tonic-gate 23230Sstevel@tonic-gate switch (auth->auth.saslmech) { 23240Sstevel@tonic-gate case NS_LDAP_SASL_CRAM_MD5: 23250Sstevel@tonic-gate /* 23260Sstevel@tonic-gate * NOTE: if iDS changes to support cram_md5, 23270Sstevel@tonic-gate * please add password management code here. 23280Sstevel@tonic-gate * Since ldap_sasl_cram_md5_bind_s does not 23290Sstevel@tonic-gate * return anything that could be used to 23300Sstevel@tonic-gate * extract the ldap rc/errmsg/control to 23310Sstevel@tonic-gate * determine if bind failed due to password 23320Sstevel@tonic-gate * policy, a new cram_md5_bind API will need 23330Sstevel@tonic-gate * to be introduced. See 23340Sstevel@tonic-gate * ldap_x_sasl_digest_md5_bind() and case 23350Sstevel@tonic-gate * NS_LDAP_SASL_DIGEST_MD5 below for details. 23360Sstevel@tonic-gate */ 23370Sstevel@tonic-gate if ((rc = ldap_sasl_cram_md5_bind_s(ld, binddn, 23384522Schinlong &cred, NULL, NULL)) != LDAP_SUCCESS) { 23390Sstevel@tonic-gate (void) ldap_get_option(ld, 23404522Schinlong LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 23410Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 23424522Schinlong gettext("openConnection: " 23434522Schinlong "sasl/CRAM-MD5 bind failed - %s"), 23444522Schinlong ldap_err2string(errnum)); 23450Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, errnum, 23464522Schinlong strdup(errstr), NULL); 23470Sstevel@tonic-gate (void) ldap_unbind(ld); 23480Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23490Sstevel@tonic-gate } 23500Sstevel@tonic-gate break; 23510Sstevel@tonic-gate case NS_LDAP_SASL_DIGEST_MD5: 23520Sstevel@tonic-gate digest_md5_name = malloc(strlen(binddn) + 5); 23530Sstevel@tonic-gate /* 5 = strlen("dn: ") + 1 */ 23540Sstevel@tonic-gate if (digest_md5_name == NULL) { 23550Sstevel@tonic-gate (void) ldap_unbind(ld); 23560Sstevel@tonic-gate return (NS_LDAP_MEMORY); 23570Sstevel@tonic-gate } 23580Sstevel@tonic-gate (void) strcpy(digest_md5_name, "dn: "); 23590Sstevel@tonic-gate (void) strcat(digest_md5_name, binddn); 23600Sstevel@tonic-gate 23610Sstevel@tonic-gate tv.tv_sec = timeoutSec; 23620Sstevel@tonic-gate tv.tv_usec = 0; 23630Sstevel@tonic-gate rc = ldap_x_sasl_digest_md5_bind(ld, 23644522Schinlong digest_md5_name, &cred, NULL, NULL, 23654522Schinlong &tv, &resultMsg); 23660Sstevel@tonic-gate 23670Sstevel@tonic-gate if (resultMsg == NULL) { 23680Sstevel@tonic-gate free(digest_md5_name); 23690Sstevel@tonic-gate (void) ldap_get_option(ld, 23704522Schinlong LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 23710Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 23724522Schinlong gettext("openConnection: " 23734522Schinlong "DIGEST-MD5 bind failed - %s"), 23744522Schinlong ldap_err2string(errnum)); 23750Sstevel@tonic-gate (void) ldap_unbind(ld); 23760Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, errnum, 23774522Schinlong strdup(errstr), NULL); 23780Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23790Sstevel@tonic-gate } 23800Sstevel@tonic-gate 23810Sstevel@tonic-gate /* 23820Sstevel@tonic-gate * get ldaprc, controls, and error msg 23830Sstevel@tonic-gate */ 23840Sstevel@tonic-gate rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 23854522Schinlong &errmsg, NULL, &controls, 1); 23860Sstevel@tonic-gate 23870Sstevel@tonic-gate if (rc != LDAP_SUCCESS) { 23880Sstevel@tonic-gate free(digest_md5_name); 23890Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 23904522Schinlong gettext("openConnection: " 23914522Schinlong "DIGEST-MD5 bind failed " 23924522Schinlong "- unable to parse result")); 23930Sstevel@tonic-gate (void) ldap_unbind(ld); 23940Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 23954522Schinlong strdup(errstr), NULL); 23960Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 23970Sstevel@tonic-gate } 23980Sstevel@tonic-gate 23990Sstevel@tonic-gate /* process the password management info, if any */ 24000Sstevel@tonic-gate pwd_rc = process_pwd_mgmt("sasl/DIGEST-MD5", 24014522Schinlong errnum, controls, errmsg, 24024522Schinlong errorp, 24034522Schinlong fail_if_new_pwd_reqd, 24044522Schinlong passwd_mgmt); 24050Sstevel@tonic-gate 24060Sstevel@tonic-gate if (pwd_rc == NS_LDAP_INTERNAL) { 24070Sstevel@tonic-gate free(digest_md5_name); 24080Sstevel@tonic-gate (void) ldap_unbind(ld); 24090Sstevel@tonic-gate return (pwd_rc); 24100Sstevel@tonic-gate } 24110Sstevel@tonic-gate 24120Sstevel@tonic-gate if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) { 24130Sstevel@tonic-gate *ldp = ld; 24140Sstevel@tonic-gate return (pwd_rc); 24150Sstevel@tonic-gate } 24160Sstevel@tonic-gate 24170Sstevel@tonic-gate free(digest_md5_name); 24180Sstevel@tonic-gate break; 24192830Sdjl case NS_LDAP_SASL_GSSAPI: 24202830Sdjl if (sasl_gssapi_inited == 0) { 24212830Sdjl rc = __s_api_sasl_gssapi_init(); 24222830Sdjl if (rc != NS_LDAP_SUCCESS) { 24232830Sdjl (void) snprintf(errstr, sizeof (errstr), 24244522Schinlong gettext("openConnection: " 24254522Schinlong "GSSAPI initialization " 24264522Schinlong "failed")); 24272830Sdjl (void) ldap_unbind(ld); 24282830Sdjl MKERROR(LOG_WARNING, *errorp, rc, 24294522Schinlong strdup(errstr), NULL); 24302830Sdjl return (rc); 24312830Sdjl } 24322830Sdjl } 24332830Sdjl (void) memset(&sasl_param, 0, 24344522Schinlong sizeof (ns_sasl_cb_param_t)); 24352830Sdjl sasl_param.authid = NULL; 24362830Sdjl sasl_param.authzid = ""; 24372830Sdjl (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN, 24384522Schinlong (void *)&min_ssf); 24392830Sdjl (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX, 24404522Schinlong (void *)&max_ssf); 24412830Sdjl 24422830Sdjl rc = ldap_sasl_interactive_bind_s( 24434522Schinlong ld, NULL, "GSSAPI", 24444522Schinlong NULL, NULL, LDAP_SASL_INTERACTIVE, 24454522Schinlong __s_api_sasl_bind_callback, 24464522Schinlong &sasl_param); 24472830Sdjl 24482830Sdjl if (rc != LDAP_SUCCESS) { 24492830Sdjl (void) snprintf(errstr, sizeof (errstr), 24504522Schinlong gettext("openConnection: " 24514522Schinlong "GSSAPI bind failed " 24524522Schinlong "- %d %s"), rc, ldap_err2string(rc)); 24532830Sdjl (void) ldap_unbind(ld); 24542830Sdjl MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 24554522Schinlong strdup(errstr), NULL); 24562830Sdjl return (NS_LDAP_INTERNAL); 24572830Sdjl } 24582830Sdjl 24592830Sdjl break; 24600Sstevel@tonic-gate default: 24610Sstevel@tonic-gate (void) ldap_unbind(ld); 24620Sstevel@tonic-gate (void) sprintf(errstr, 24634522Schinlong gettext("openConnection: unsupported SASL " 24644522Schinlong "mechanism (%d)"), auth->auth.saslmech); 24650Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, 24664522Schinlong LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 24674522Schinlong NULL); 24680Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 24690Sstevel@tonic-gate } 24700Sstevel@tonic-gate } 24710Sstevel@tonic-gate 24720Sstevel@tonic-gate *ldp = ld; 24730Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 24740Sstevel@tonic-gate } 24750Sstevel@tonic-gate 24760Sstevel@tonic-gate /* 24770Sstevel@tonic-gate * FUNCTION: __s_api_getDefaultAuth 24780Sstevel@tonic-gate * 24790Sstevel@tonic-gate * Constructs a credential for authentication using the config module. 24800Sstevel@tonic-gate * 24810Sstevel@tonic-gate * RETURN VALUES: 24820Sstevel@tonic-gate * 24830Sstevel@tonic-gate * NS_LDAP_SUCCESS If successful 24840Sstevel@tonic-gate * NS_LDAP_CONFIG If there are any config errors. 24850Sstevel@tonic-gate * NS_LDAP_MEMORY Memory errors. 24860Sstevel@tonic-gate * NS_LDAP_OP_FAILED If there are no more authentication methods so can 24870Sstevel@tonic-gate * not build a new authp. 24880Sstevel@tonic-gate * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the 24890Sstevel@tonic-gate * necessary fields of a cred for a given auth method 24900Sstevel@tonic-gate * are not provided. 24910Sstevel@tonic-gate * INPUT: 24920Sstevel@tonic-gate * 24930Sstevel@tonic-gate * cLevel Currently requested credential level to be tried 24940Sstevel@tonic-gate * 24950Sstevel@tonic-gate * aMethod Currently requested authentication method to be tried 24960Sstevel@tonic-gate * 24970Sstevel@tonic-gate * OUTPUT: 24980Sstevel@tonic-gate * 24990Sstevel@tonic-gate * authp authentication method to use. 25000Sstevel@tonic-gate */ 25010Sstevel@tonic-gate static int 25020Sstevel@tonic-gate __s_api_getDefaultAuth( 25030Sstevel@tonic-gate int *cLevel, 25040Sstevel@tonic-gate ns_auth_t *aMethod, 25050Sstevel@tonic-gate ns_cred_t **authp) 25060Sstevel@tonic-gate { 25070Sstevel@tonic-gate void **paramVal = NULL; 25080Sstevel@tonic-gate char *modparamVal = NULL; 25090Sstevel@tonic-gate int getUid = 0; 25100Sstevel@tonic-gate int getPasswd = 0; 25110Sstevel@tonic-gate int getCertpath = 0; 25120Sstevel@tonic-gate int rc = 0; 25130Sstevel@tonic-gate ns_ldap_error_t *errorp = NULL; 25140Sstevel@tonic-gate 25150Sstevel@tonic-gate #ifdef DEBUG 25160Sstevel@tonic-gate (void) fprintf(stderr, "__s_api_getDefaultAuth START\n"); 25170Sstevel@tonic-gate #endif 25180Sstevel@tonic-gate 25190Sstevel@tonic-gate if (aMethod == NULL) { 25200Sstevel@tonic-gate /* Require an Auth */ 25210Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 25220Sstevel@tonic-gate 25230Sstevel@tonic-gate } 25240Sstevel@tonic-gate /* 25252830Sdjl * credential level "self" can work with auth method sasl/GSSAPI only 25260Sstevel@tonic-gate */ 25272830Sdjl if (cLevel && *cLevel == NS_LDAP_CRED_SELF && 25284522Schinlong aMethod->saslmech != NS_LDAP_SASL_GSSAPI) 25290Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 25300Sstevel@tonic-gate 25310Sstevel@tonic-gate *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); 25320Sstevel@tonic-gate if ((*authp) == NULL) 25330Sstevel@tonic-gate return (NS_LDAP_MEMORY); 25340Sstevel@tonic-gate 25350Sstevel@tonic-gate (*authp)->auth = *aMethod; 25360Sstevel@tonic-gate 25370Sstevel@tonic-gate switch (aMethod->type) { 25380Sstevel@tonic-gate case NS_LDAP_AUTH_NONE: 25390Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 25400Sstevel@tonic-gate case NS_LDAP_AUTH_SIMPLE: 25410Sstevel@tonic-gate getUid++; 25420Sstevel@tonic-gate getPasswd++; 25430Sstevel@tonic-gate break; 25440Sstevel@tonic-gate case NS_LDAP_AUTH_SASL: 25450Sstevel@tonic-gate if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 25460Sstevel@tonic-gate (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) { 25470Sstevel@tonic-gate getUid++; 25480Sstevel@tonic-gate getPasswd++; 25492830Sdjl } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) { 25500Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 25510Sstevel@tonic-gate *authp = NULL; 25520Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 25530Sstevel@tonic-gate } 25540Sstevel@tonic-gate break; 25550Sstevel@tonic-gate case NS_LDAP_AUTH_TLS: 25560Sstevel@tonic-gate if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) || 25570Sstevel@tonic-gate ((aMethod->tlstype == NS_LDAP_TLS_SASL) && 25580Sstevel@tonic-gate ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 25590Sstevel@tonic-gate (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) { 25600Sstevel@tonic-gate getUid++; 25610Sstevel@tonic-gate getPasswd++; 25620Sstevel@tonic-gate getCertpath++; 25630Sstevel@tonic-gate } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) { 25640Sstevel@tonic-gate getCertpath++; 25650Sstevel@tonic-gate } else { 25660Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 25670Sstevel@tonic-gate *authp = NULL; 25680Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 25690Sstevel@tonic-gate } 25700Sstevel@tonic-gate break; 25710Sstevel@tonic-gate } 25720Sstevel@tonic-gate 25730Sstevel@tonic-gate if (getUid) { 25740Sstevel@tonic-gate paramVal = NULL; 25750Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, 25764522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 25770Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 25780Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 25790Sstevel@tonic-gate *authp = NULL; 25800Sstevel@tonic-gate return (rc); 25810Sstevel@tonic-gate } 25820Sstevel@tonic-gate 25830Sstevel@tonic-gate if (paramVal == NULL || *paramVal == NULL) { 25840Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 25850Sstevel@tonic-gate *authp = NULL; 25860Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 25870Sstevel@tonic-gate } 25880Sstevel@tonic-gate 25890Sstevel@tonic-gate (*authp)->cred.unix_cred.userID = strdup((char *)*paramVal); 25900Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 25910Sstevel@tonic-gate if ((*authp)->cred.unix_cred.userID == NULL) { 25920Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 25930Sstevel@tonic-gate *authp = NULL; 25940Sstevel@tonic-gate return (NS_LDAP_MEMORY); 25950Sstevel@tonic-gate } 25960Sstevel@tonic-gate } 25970Sstevel@tonic-gate if (getPasswd) { 25980Sstevel@tonic-gate paramVal = NULL; 25990Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, 26004522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 26010Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26020Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 26030Sstevel@tonic-gate *authp = NULL; 26040Sstevel@tonic-gate return (rc); 26050Sstevel@tonic-gate } 26060Sstevel@tonic-gate 26070Sstevel@tonic-gate if (paramVal == NULL || *paramVal == NULL) { 26080Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26090Sstevel@tonic-gate *authp = NULL; 26100Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 26110Sstevel@tonic-gate } 26120Sstevel@tonic-gate 26130Sstevel@tonic-gate modparamVal = dvalue((char *)*paramVal); 26140Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 26150Sstevel@tonic-gate if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) { 26160Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26170Sstevel@tonic-gate if (modparamVal != NULL) 26180Sstevel@tonic-gate free(modparamVal); 26190Sstevel@tonic-gate *authp = NULL; 26200Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 26210Sstevel@tonic-gate } 26220Sstevel@tonic-gate 26230Sstevel@tonic-gate (*authp)->cred.unix_cred.passwd = modparamVal; 26240Sstevel@tonic-gate } 26250Sstevel@tonic-gate if (getCertpath) { 26260Sstevel@tonic-gate paramVal = NULL; 26270Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 26284522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 26290Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26300Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 26310Sstevel@tonic-gate *authp = NULL; 26320Sstevel@tonic-gate return (rc); 26330Sstevel@tonic-gate } 26340Sstevel@tonic-gate 26350Sstevel@tonic-gate if (paramVal == NULL || *paramVal == NULL) { 26360Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26370Sstevel@tonic-gate *authp = NULL; 26380Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 26390Sstevel@tonic-gate } 26400Sstevel@tonic-gate 26410Sstevel@tonic-gate (*authp)->hostcertpath = strdup((char *)*paramVal); 26420Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 26430Sstevel@tonic-gate if ((*authp)->hostcertpath == NULL) { 26440Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 26450Sstevel@tonic-gate *authp = NULL; 26460Sstevel@tonic-gate return (NS_LDAP_MEMORY); 26470Sstevel@tonic-gate } 26480Sstevel@tonic-gate } 26490Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 26500Sstevel@tonic-gate } 26510Sstevel@tonic-gate 26520Sstevel@tonic-gate /* 26530Sstevel@tonic-gate * FUNCTION: __s_api_getConnection 26540Sstevel@tonic-gate * 26550Sstevel@tonic-gate * Bind to the specified server or one from the server 26560Sstevel@tonic-gate * list and return the pointer. 26570Sstevel@tonic-gate * 26580Sstevel@tonic-gate * This function can rebind or not (NS_LDAP_HARD), it can require a 26590Sstevel@tonic-gate * credential or bind anonymously 26600Sstevel@tonic-gate * 26610Sstevel@tonic-gate * This function follows the DUA configuration schema algorithm 26620Sstevel@tonic-gate * 26630Sstevel@tonic-gate * RETURN VALUES: 26640Sstevel@tonic-gate * 26650Sstevel@tonic-gate * NS_LDAP_SUCCESS A connection was made successfully. 26660Sstevel@tonic-gate * NS_LDAP_SUCCESS_WITH_INFO 26670Sstevel@tonic-gate * A connection was made successfully, but with 26680Sstevel@tonic-gate * password management info in *errorp 26690Sstevel@tonic-gate * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function. 26700Sstevel@tonic-gate * NS_LDAP_CONFIG If there are any config errors. 26710Sstevel@tonic-gate * NS_LDAP_MEMORY Memory errors. 26720Sstevel@tonic-gate * NS_LDAP_INTERNAL If there was a ldap error. 26730Sstevel@tonic-gate * 26740Sstevel@tonic-gate * INPUT: 26750Sstevel@tonic-gate * 26760Sstevel@tonic-gate * server Bind to this LDAP server only 26770Sstevel@tonic-gate * flags If NS_LDAP_HARD is set function will not return until it has 26780Sstevel@tonic-gate * a connection unless there is a authentication problem. 26790Sstevel@tonic-gate * If NS_LDAP_NEW_CONN is set the function must force a new 26800Sstevel@tonic-gate * connection to be created 26810Sstevel@tonic-gate * If NS_LDAP_KEEP_CONN is set the connection is to be kept open 26820Sstevel@tonic-gate * auth Credentials for bind. This could be NULL in which case 26830Sstevel@tonic-gate * a default cred built from the config module is used. 26840Sstevel@tonic-gate * sessionId cookie that points to a previous session 26850Sstevel@tonic-gate * fail_if_new_pwd_reqd 26860Sstevel@tonic-gate * a flag indicating this function should fail if the passwd 26870Sstevel@tonic-gate * in auth needs to change immediately 26881179Svv149972 * nopasswd_acct_mgmt 26891179Svv149972 * a flag indicating that makeConnection should check before 26901179Svv149972 * binding if server supports LDAP V3 password less 26911179Svv149972 * account management 26920Sstevel@tonic-gate * 26930Sstevel@tonic-gate * OUTPUT: 26940Sstevel@tonic-gate * 26950Sstevel@tonic-gate * session pointer to a session with connection information 26960Sstevel@tonic-gate * errorp Set if there are any INTERNAL, or CONFIG error. 26970Sstevel@tonic-gate */ 26980Sstevel@tonic-gate int 26990Sstevel@tonic-gate __s_api_getConnection( 27000Sstevel@tonic-gate const char *server, 27010Sstevel@tonic-gate const int flags, 27020Sstevel@tonic-gate const ns_cred_t *cred, /* credentials for bind */ 27030Sstevel@tonic-gate ConnectionID *sessionId, 27040Sstevel@tonic-gate Connection **session, 27050Sstevel@tonic-gate ns_ldap_error_t **errorp, 27061179Svv149972 int fail_if_new_pwd_reqd, 27071179Svv149972 int nopasswd_acct_mgmt) 27080Sstevel@tonic-gate { 27090Sstevel@tonic-gate char errmsg[MAXERROR]; 27100Sstevel@tonic-gate ns_auth_t **aMethod = NULL; 27110Sstevel@tonic-gate ns_auth_t **aNext = NULL; 27120Sstevel@tonic-gate int **cLevel = NULL; 27130Sstevel@tonic-gate int **cNext = NULL; 27140Sstevel@tonic-gate int timeoutSec = NS_DEFAULT_BIND_TIMEOUT; 27150Sstevel@tonic-gate int rc; 27160Sstevel@tonic-gate Connection *con = NULL; 27170Sstevel@tonic-gate int sec = 1; 27180Sstevel@tonic-gate ns_cred_t *authp = NULL; 27190Sstevel@tonic-gate ns_cred_t anon; 27202830Sdjl int version = NS_LDAP_V2, self_gssapi_only = 0; 27210Sstevel@tonic-gate void **paramVal = NULL; 27221687Sjanga char **badSrvrs = NULL; /* List of problem hostnames */ 27230Sstevel@tonic-gate 27240Sstevel@tonic-gate if ((session == NULL) || (sessionId == NULL)) { 27250Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 27260Sstevel@tonic-gate } 27270Sstevel@tonic-gate *session = NULL; 27280Sstevel@tonic-gate 27290Sstevel@tonic-gate /* if we already have a session id try to reuse connection */ 27300Sstevel@tonic-gate if (*sessionId > 0) { 27310Sstevel@tonic-gate rc = findConnectionById(flags, cred, *sessionId, &con); 27320Sstevel@tonic-gate if (rc == *sessionId && con) { 27330Sstevel@tonic-gate *session = con; 27340Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 27350Sstevel@tonic-gate } 27360Sstevel@tonic-gate *sessionId = 0; 27370Sstevel@tonic-gate } 27380Sstevel@tonic-gate 27390Sstevel@tonic-gate /* get profile version number */ 27400Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, 27414522Schinlong ¶mVal, errorp)) != NS_LDAP_SUCCESS) 27420Sstevel@tonic-gate return (rc); 27430Sstevel@tonic-gate if (paramVal == NULL) { 27440Sstevel@tonic-gate (void) sprintf(errmsg, gettext("getConnection: no file " 27454522Schinlong "version")); 27460Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg), 27474522Schinlong NS_LDAP_CONFIG); 27480Sstevel@tonic-gate return (NS_LDAP_CONFIG); 27490Sstevel@tonic-gate } 27500Sstevel@tonic-gate if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0) 27510Sstevel@tonic-gate version = NS_LDAP_V1; 27520Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)¶mVal); 27530Sstevel@tonic-gate 27540Sstevel@tonic-gate /* Get the bind timeout value */ 27550Sstevel@tonic-gate (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp); 27560Sstevel@tonic-gate if (paramVal != NULL && *paramVal != NULL) { 27570Sstevel@tonic-gate timeoutSec = **((int **)paramVal); 27580Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 27590Sstevel@tonic-gate } 27600Sstevel@tonic-gate if (*errorp) 27610Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 27620Sstevel@tonic-gate 27630Sstevel@tonic-gate if (cred == NULL) { 27640Sstevel@tonic-gate /* Get the authentication method list */ 27650Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, 27664522Schinlong (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS) 27670Sstevel@tonic-gate return (rc); 27680Sstevel@tonic-gate if (aMethod == NULL) { 27690Sstevel@tonic-gate aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *)); 27700Sstevel@tonic-gate if (aMethod == NULL) 27710Sstevel@tonic-gate return (NS_LDAP_MEMORY); 27720Sstevel@tonic-gate aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t)); 27730Sstevel@tonic-gate if (aMethod[0] == NULL) { 27740Sstevel@tonic-gate free(aMethod); 27750Sstevel@tonic-gate return (NS_LDAP_MEMORY); 27760Sstevel@tonic-gate } 27770Sstevel@tonic-gate if (version == NS_LDAP_V1) 27780Sstevel@tonic-gate (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE; 27790Sstevel@tonic-gate else { 27800Sstevel@tonic-gate (aMethod[0])->type = NS_LDAP_AUTH_SASL; 27810Sstevel@tonic-gate (aMethod[0])->saslmech = 27824522Schinlong NS_LDAP_SASL_DIGEST_MD5; 27830Sstevel@tonic-gate (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE; 27840Sstevel@tonic-gate } 27850Sstevel@tonic-gate } 27860Sstevel@tonic-gate 27870Sstevel@tonic-gate /* Get the credential level list */ 27880Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P, 27894522Schinlong (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) { 27900Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&aMethod); 27910Sstevel@tonic-gate return (rc); 27920Sstevel@tonic-gate } 27930Sstevel@tonic-gate if (cLevel == NULL) { 27940Sstevel@tonic-gate cLevel = (int **)calloc(2, sizeof (int *)); 27950Sstevel@tonic-gate if (cLevel == NULL) 27960Sstevel@tonic-gate return (NS_LDAP_MEMORY); 27970Sstevel@tonic-gate cLevel[0] = (int *)calloc(1, sizeof (int)); 27980Sstevel@tonic-gate if (cLevel[0] == NULL) 27990Sstevel@tonic-gate return (NS_LDAP_MEMORY); 28000Sstevel@tonic-gate if (version == NS_LDAP_V1) 28010Sstevel@tonic-gate *(cLevel[0]) = NS_LDAP_CRED_PROXY; 28020Sstevel@tonic-gate else 28030Sstevel@tonic-gate *(cLevel[0]) = NS_LDAP_CRED_ANON; 28040Sstevel@tonic-gate } 28050Sstevel@tonic-gate } 28060Sstevel@tonic-gate 28070Sstevel@tonic-gate /* setup the anon credential for anonymous connection */ 28080Sstevel@tonic-gate (void) memset(&anon, 0, sizeof (ns_cred_t)); 28090Sstevel@tonic-gate anon.auth.type = NS_LDAP_AUTH_NONE; 28100Sstevel@tonic-gate 28110Sstevel@tonic-gate for (; ; ) { 28120Sstevel@tonic-gate if (cred != NULL) { 28130Sstevel@tonic-gate /* using specified auth method */ 28140Sstevel@tonic-gate rc = makeConnection(&con, server, cred, 28154522Schinlong sessionId, timeoutSec, errorp, 28164522Schinlong fail_if_new_pwd_reqd, 28174522Schinlong nopasswd_acct_mgmt, flags, &badSrvrs); 28184387Smj162486 /* not using bad server if credentials were supplied */ 28194387Smj162486 if (badSrvrs && *badSrvrs) { 28204387Smj162486 __s_api_free2dArray(badSrvrs); 28214387Smj162486 badSrvrs = NULL; 28224387Smj162486 } 28230Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 28244522Schinlong rc == NS_LDAP_SUCCESS_WITH_INFO) { 28250Sstevel@tonic-gate *session = con; 28260Sstevel@tonic-gate break; 28270Sstevel@tonic-gate } 28280Sstevel@tonic-gate } else { 28292830Sdjl self_gssapi_only = __s_api_self_gssapi_only_get(); 28300Sstevel@tonic-gate /* for every cred level */ 28310Sstevel@tonic-gate for (cNext = cLevel; *cNext != NULL; cNext++) { 28322830Sdjl if (self_gssapi_only && 28334522Schinlong **cNext != NS_LDAP_CRED_SELF) 28342830Sdjl continue; 28350Sstevel@tonic-gate if (**cNext == NS_LDAP_CRED_ANON) { 28361687Sjanga /* 28371687Sjanga * make connection anonymously 28381687Sjanga * Free the down server list before 28391687Sjanga * looping through 28401687Sjanga */ 28411687Sjanga if (badSrvrs && *badSrvrs) { 28421687Sjanga __s_api_free2dArray(badSrvrs); 28431687Sjanga badSrvrs = NULL; 28441687Sjanga } 28450Sstevel@tonic-gate rc = makeConnection(&con, server, &anon, 28464522Schinlong sessionId, timeoutSec, errorp, 28474522Schinlong fail_if_new_pwd_reqd, 28484522Schinlong nopasswd_acct_mgmt, flags, 28494522Schinlong &badSrvrs); 28500Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 28514522Schinlong rc == 28524522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 28530Sstevel@tonic-gate *session = con; 28540Sstevel@tonic-gate goto done; 28550Sstevel@tonic-gate } 28560Sstevel@tonic-gate continue; 28570Sstevel@tonic-gate } 28580Sstevel@tonic-gate /* for each cred level */ 28590Sstevel@tonic-gate for (aNext = aMethod; *aNext != NULL; aNext++) { 28602830Sdjl if (self_gssapi_only && 28614522Schinlong (*aNext)->saslmech != 28624522Schinlong NS_LDAP_SASL_GSSAPI) 28632830Sdjl continue; 28642830Sdjl /* 28652830Sdjl * self coexists with sasl/GSSAPI only 28662830Sdjl * and non-self coexists with non-gssapi 28672830Sdjl * only 28682830Sdjl */ 28692830Sdjl if ((**cNext == NS_LDAP_CRED_SELF && 28704522Schinlong (*aNext)->saslmech != 28714522Schinlong NS_LDAP_SASL_GSSAPI) || 28724522Schinlong (**cNext != NS_LDAP_CRED_SELF && 28734522Schinlong (*aNext)->saslmech == 28744522Schinlong NS_LDAP_SASL_GSSAPI)) 28752830Sdjl continue; 28760Sstevel@tonic-gate /* make connection and authenticate */ 28770Sstevel@tonic-gate /* with default credentials */ 28780Sstevel@tonic-gate authp = NULL; 28790Sstevel@tonic-gate rc = __s_api_getDefaultAuth(*cNext, 28804522Schinlong *aNext, &authp); 28810Sstevel@tonic-gate if (rc != NS_LDAP_SUCCESS) { 28820Sstevel@tonic-gate continue; 28830Sstevel@tonic-gate } 28841687Sjanga /* 28851687Sjanga * Free the down server list before 28861687Sjanga * looping through 28871687Sjanga */ 28881687Sjanga if (badSrvrs && *badSrvrs) { 28891687Sjanga __s_api_free2dArray(badSrvrs); 28901687Sjanga badSrvrs = NULL; 28911687Sjanga } 28920Sstevel@tonic-gate rc = makeConnection(&con, server, authp, 28934522Schinlong sessionId, timeoutSec, errorp, 28944522Schinlong fail_if_new_pwd_reqd, 28954522Schinlong nopasswd_acct_mgmt, flags, 28964522Schinlong &badSrvrs); 28970Sstevel@tonic-gate (void) __ns_ldap_freeCred(&authp); 28980Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 28994522Schinlong rc == 29004522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 29010Sstevel@tonic-gate *session = con; 29020Sstevel@tonic-gate goto done; 29030Sstevel@tonic-gate } 29040Sstevel@tonic-gate } 29050Sstevel@tonic-gate } 29060Sstevel@tonic-gate } 29070Sstevel@tonic-gate if (flags & NS_LDAP_HARD) { 29080Sstevel@tonic-gate if (sec < LDAPMAXHARDLOOKUPTIME) 29090Sstevel@tonic-gate sec *= 2; 29100Sstevel@tonic-gate _sleep(sec); 29110Sstevel@tonic-gate } else { 29120Sstevel@tonic-gate break; 29130Sstevel@tonic-gate } 29140Sstevel@tonic-gate } 29150Sstevel@tonic-gate 29160Sstevel@tonic-gate done: 29172830Sdjl /* 29182830Sdjl * If unable to get a connection, and this is 29192830Sdjl * the thread opening the shared connection, 29202830Sdjl * unlock the session mutex and let other 29212830Sdjl * threads try to get their own connection. 29222830Sdjl */ 29232830Sdjl if (wait4session != 0 && sessionTid == thr_self()) { 29242830Sdjl wait4session = 0; 29252830Sdjl sessionTid = 0; 29262830Sdjl #ifdef DEBUG 29272830Sdjl (void) fprintf(stderr, "tid= %d: __s_api_getConnection: " 29284522Schinlong "unlocking sessionLock \n", thr_self()); 29292830Sdjl fflush(stderr); 29302830Sdjl #endif /* DEBUG */ 29312830Sdjl (void) mutex_unlock(&sessionLock); 29322830Sdjl } 29332830Sdjl if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) { 29342830Sdjl /* 29352830Sdjl * self_gssapi_only is true but no self/sasl/gssapi is 29362830Sdjl * configured 29372830Sdjl */ 29382830Sdjl rc = NS_LDAP_CONFIG; 29392830Sdjl } 29402830Sdjl 29410Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&aMethod); 29420Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&cLevel); 29431687Sjanga 29441687Sjanga if (badSrvrs && *badSrvrs) { 29451687Sjanga /* 29461687Sjanga * At this point, either we have a successful 29471687Sjanga * connection or exhausted all the possible auths. 29481687Sjanga * and creds. Mark the problem servers as down 29491687Sjanga * so that the problem servers are not contacted 29501687Sjanga * again until the refresh_ttl expires. 29511687Sjanga */ 29521687Sjanga (void) __s_api_removeBadServers(badSrvrs); 29531687Sjanga __s_api_free2dArray(badSrvrs); 29541687Sjanga } 29550Sstevel@tonic-gate return (rc); 29560Sstevel@tonic-gate } 29570Sstevel@tonic-gate 29580Sstevel@tonic-gate #pragma fini(_free_sessionPool) 29590Sstevel@tonic-gate static void 29600Sstevel@tonic-gate _free_sessionPool() 29610Sstevel@tonic-gate { 29620Sstevel@tonic-gate int id; 29630Sstevel@tonic-gate 29642830Sdjl (void) rw_wrlock(&sessionPoolLock); 29650Sstevel@tonic-gate if (sessionPool != NULL) { 29660Sstevel@tonic-gate for (id = 0; id < sessionPoolSize; id++) 29670Sstevel@tonic-gate _DropConnection(id + CONID_OFFSET, 0, 1); 29680Sstevel@tonic-gate free(sessionPool); 29690Sstevel@tonic-gate sessionPool = NULL; 29700Sstevel@tonic-gate sessionPoolSize = 0; 29710Sstevel@tonic-gate } 29722830Sdjl (void) rw_unlock(&sessionPoolLock); 29730Sstevel@tonic-gate } 2974