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 */ 21*11411SSurya.Prakki@Sun.COM 220Sstevel@tonic-gate /* 239576SJulian.Pullen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <stdlib.h> 280Sstevel@tonic-gate #include <stdio.h> 290Sstevel@tonic-gate #include <errno.h> 300Sstevel@tonic-gate #include <string.h> 310Sstevel@tonic-gate #include <synch.h> 320Sstevel@tonic-gate #include <time.h> 330Sstevel@tonic-gate #include <libintl.h> 340Sstevel@tonic-gate #include <thread.h> 350Sstevel@tonic-gate #include <syslog.h> 360Sstevel@tonic-gate #include <sys/mman.h> 370Sstevel@tonic-gate #include <nsswitch.h> 380Sstevel@tonic-gate #include <nss_dbdefs.h> 390Sstevel@tonic-gate #include "solaris-priv.h" 402830Sdjl #include "solaris-int.h" 410Sstevel@tonic-gate #include "ns_sldap.h" 420Sstevel@tonic-gate #include "ns_internal.h" 430Sstevel@tonic-gate #include "ns_cache_door.h" 446842Sth160488 #include "ns_connmgmt.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 516842Sth160488 #define USE_DEFAULT_PORT 0 526842Sth160488 536842Sth160488 static ns_ldap_return_code performBind(const ns_cred_t *, 546842Sth160488 LDAP *, 556842Sth160488 int, 566842Sth160488 ns_ldap_error_t **, 576842Sth160488 int, 586842Sth160488 int); 596842Sth160488 static ns_ldap_return_code createSession(const ns_cred_t *, 606842Sth160488 const char *, 616842Sth160488 uint16_t, 626842Sth160488 int, 636842Sth160488 LDAP **, 646842Sth160488 ns_ldap_error_t **); 656842Sth160488 660Sstevel@tonic-gate extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *, 670Sstevel@tonic-gate LDAPControl **, LDAPControl **); 680Sstevel@tonic-gate extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip); 690Sstevel@tonic-gate 709576SJulian.Pullen@Sun.COM extern int __door_getconf(char **buffer, int *buflen, 719576SJulian.Pullen@Sun.COM ns_ldap_error_t **error, int callnumber); 729576SJulian.Pullen@Sun.COM extern int __ns_ldap_freeUnixCred(UnixCred_t **credp); 739576SJulian.Pullen@Sun.COM extern int SetDoorInfoToUnixCred(char *buffer, 749576SJulian.Pullen@Sun.COM ns_ldap_error_t **errorp, 759576SJulian.Pullen@Sun.COM UnixCred_t **cred); 769576SJulian.Pullen@Sun.COM 770Sstevel@tonic-gate static int openConnection(LDAP **, const char *, const ns_cred_t *, 786842Sth160488 int, ns_ldap_error_t **, int, int, ns_conn_user_t *); 794048Schinlong static void 804048Schinlong _DropConnection(ConnectionID cID, int flag, int fini); 816842Sth160488 826842Sth160488 static mutex_t sessionPoolLock = DEFAULTMUTEX; 830Sstevel@tonic-gate 840Sstevel@tonic-gate static Connection **sessionPool = NULL; 850Sstevel@tonic-gate static int sessionPoolSize = 0; 860Sstevel@tonic-gate 872830Sdjl /* 882830Sdjl * SSF values are for SASL integrity & privacy. 892830Sdjl * JES DS5.2 does not support this feature but DS6 does. 902830Sdjl * The values between 0 and 65535 can work with both server versions. 912830Sdjl */ 922830Sdjl #define MAX_SASL_SSF 65535 932830Sdjl #define MIN_SASL_SSF 0 940Sstevel@tonic-gate 951687Sjanga /* Number of hostnames to allocate memory for */ 961687Sjanga #define NUMTOMALLOC 32 972830Sdjl 982830Sdjl /* 996842Sth160488 * This function get the servers from the lists and returns 1006842Sth160488 * the first server with the empty lists of server controls and 1016842Sth160488 * SASL mechanisms. It is invoked if it is not possible to obtain a server 1026842Sth160488 * from ldap_cachemgr or the local list. 1032830Sdjl */ 1046842Sth160488 static 1056842Sth160488 ns_ldap_return_code 1066842Sth160488 getFirstFromConfig(ns_server_info_t *ret, ns_ldap_error_t **error) 1072830Sdjl { 1086842Sth160488 char **servers = NULL; 1096842Sth160488 ns_ldap_return_code ret_code; 1106842Sth160488 char errstr[MAXERROR]; 1112830Sdjl 1126842Sth160488 /* get first server from config list unavailable otherwise */ 1136842Sth160488 ret_code = __s_api_getServers(&servers, error); 1146842Sth160488 if (ret_code != NS_LDAP_SUCCESS) { 1156842Sth160488 if (servers != NULL) { 1166842Sth160488 __s_api_free2dArray(servers); 1176842Sth160488 } 1186842Sth160488 return (ret_code); 1192830Sdjl } 1202830Sdjl 1216842Sth160488 if (servers == NULL || servers[0] == NULL) { 1226842Sth160488 __s_api_free2dArray(servers); 1236842Sth160488 (void) sprintf(errstr, 1246842Sth160488 gettext("No server found in configuration")); 1256842Sth160488 MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT, 1266842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 1276842Sth160488 return (NS_LDAP_CONFIG); 1286072Smj162486 } 1296072Smj162486 1306842Sth160488 ret->server = strdup(servers[0]); 1316842Sth160488 if (ret->server == NULL) { 1326842Sth160488 __s_api_free2dArray(servers); 1336842Sth160488 return (NS_LDAP_MEMORY); 1346072Smj162486 } 1356072Smj162486 1366842Sth160488 ret->saslMechanisms = NULL; 1376842Sth160488 ret->controls = NULL; 1386072Smj162486 1396842Sth160488 __s_api_free2dArray(servers); 1406072Smj162486 1416842Sth160488 return (NS_LDAP_SUCCESS); 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1449576SJulian.Pullen@Sun.COM /* very similar to __door_getldapconfig() in ns_config.c */ 1459576SJulian.Pullen@Sun.COM static int 1469576SJulian.Pullen@Sun.COM __door_getadmincred(char **buffer, int *buflen, ns_ldap_error_t **error) 1479576SJulian.Pullen@Sun.COM { 1489576SJulian.Pullen@Sun.COM return (__door_getconf(buffer, buflen, error, GETADMINCRED)); 1499576SJulian.Pullen@Sun.COM } 1509576SJulian.Pullen@Sun.COM 1519576SJulian.Pullen@Sun.COM /* 1529576SJulian.Pullen@Sun.COM * This function requests Admin credentials from the cache manager through 1539576SJulian.Pullen@Sun.COM * the door functionality 1549576SJulian.Pullen@Sun.COM */ 1559576SJulian.Pullen@Sun.COM 1569576SJulian.Pullen@Sun.COM static int 1579576SJulian.Pullen@Sun.COM requestAdminCred(UnixCred_t **cred, ns_ldap_error_t **error) 1589576SJulian.Pullen@Sun.COM { 1599576SJulian.Pullen@Sun.COM char *buffer = NULL; 1609576SJulian.Pullen@Sun.COM int buflen = 0; 1619576SJulian.Pullen@Sun.COM int ret; 1629576SJulian.Pullen@Sun.COM 1639576SJulian.Pullen@Sun.COM *error = NULL; 1649576SJulian.Pullen@Sun.COM ret = __door_getadmincred(&buffer, &buflen, error); 1659576SJulian.Pullen@Sun.COM 1669576SJulian.Pullen@Sun.COM if (ret != NS_LDAP_SUCCESS) { 1679576SJulian.Pullen@Sun.COM if (*error != NULL && (*error)->message != NULL) 1689576SJulian.Pullen@Sun.COM syslog(LOG_WARNING, "libsldap: %s", (*error)->message); 1699576SJulian.Pullen@Sun.COM return (ret); 1709576SJulian.Pullen@Sun.COM } 1719576SJulian.Pullen@Sun.COM 1729576SJulian.Pullen@Sun.COM /* now convert from door format */ 1739576SJulian.Pullen@Sun.COM ret = SetDoorInfoToUnixCred(buffer, error, cred); 1749576SJulian.Pullen@Sun.COM free(buffer); 1759576SJulian.Pullen@Sun.COM 1769576SJulian.Pullen@Sun.COM return (ret); 1779576SJulian.Pullen@Sun.COM } 1789576SJulian.Pullen@Sun.COM 1790Sstevel@tonic-gate /* 1800Sstevel@tonic-gate * This function requests a server from the cache manager through 1810Sstevel@tonic-gate * the door functionality 1820Sstevel@tonic-gate */ 1830Sstevel@tonic-gate 1846842Sth160488 int 1850Sstevel@tonic-gate __s_api_requestServer(const char *request, const char *server, 1862830Sdjl ns_server_info_t *ret, ns_ldap_error_t **error, const char *addrType) 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate union { 1890Sstevel@tonic-gate ldap_data_t s_d; 1900Sstevel@tonic-gate char s_b[DOORBUFFERSIZE]; 1910Sstevel@tonic-gate } space; 1926842Sth160488 ldap_data_t *sptr; 1936842Sth160488 int ndata; 1946842Sth160488 int adata; 1956842Sth160488 char errstr[MAXERROR]; 1966842Sth160488 const char *ireq; 1976842Sth160488 char *rbuf, *ptr, *rest; 1986842Sth160488 char *dptr; 1996842Sth160488 char **mptr, **mptr1, **cptr, **cptr1; 2006842Sth160488 int mcnt, ccnt; 2016842Sth160488 int len; 2026842Sth160488 ns_ldap_return_code ret_code; 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if (ret == NULL || error == NULL) { 2050Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate (void) memset(ret, 0, sizeof (ns_server_info_t)); 2080Sstevel@tonic-gate *error = NULL; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate if (request == NULL) 2110Sstevel@tonic-gate ireq = NS_CACHE_NEW; 2120Sstevel@tonic-gate else 2130Sstevel@tonic-gate ireq = request; 2140Sstevel@tonic-gate 2156842Sth160488 /* 2166842Sth160488 * In the 'Standalone' mode a server will be obtained 2176842Sth160488 * from the local libsldap's list 2186842Sth160488 */ 2196842Sth160488 if (__s_api_isStandalone()) { 2207281Smichen if ((ret_code = __s_api_findRootDSE(ireq, 2216842Sth160488 server, 2226842Sth160488 addrType, 2236842Sth160488 ret, 2247281Smichen error)) != NS_LDAP_SUCCESS) { 2257281Smichen /* 2267281Smichen * get first server from local list only once 2277281Smichen * to prevent looping 2287281Smichen */ 2297281Smichen if (strcmp(ireq, NS_CACHE_NEW) != 0) 2307281Smichen return (ret_code); 2317281Smichen 2326842Sth160488 syslog(LOG_WARNING, 2336842Sth160488 "libsldap (\"standalone\" mode): " 2346842Sth160488 "can not find any available server. " 2356842Sth160488 "Return the first one from the lists"); 2366842Sth160488 if (*error != NULL) { 2376842Sth160488 (void) __ns_ldap_freeError(error); 2386842Sth160488 } 2396842Sth160488 2406842Sth160488 ret_code = getFirstFromConfig(ret, error); 2416842Sth160488 if (ret_code != NS_LDAP_SUCCESS) { 2426842Sth160488 return (ret_code); 2436842Sth160488 } 2446842Sth160488 2456842Sth160488 if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) { 2466842Sth160488 ret_code = __s_api_ip2hostname(ret->server, 2476842Sth160488 &ret->serverFQDN); 2486842Sth160488 if (ret_code != NS_LDAP_SUCCESS) { 2496842Sth160488 (void) snprintf(errstr, 2506842Sth160488 sizeof (errstr), 2516842Sth160488 gettext("The %s address " 2526842Sth160488 "can not be resolved into " 2536842Sth160488 "a host name. Returning " 2546842Sth160488 "the address as it is."), 2556842Sth160488 ret->server); 2566842Sth160488 MKERROR(LOG_ERR, 2576842Sth160488 *error, 2586842Sth160488 NS_CONFIG_NOTLOADED, 2596842Sth160488 strdup(errstr), 2606842Sth160488 NS_LDAP_MEMORY); 2616842Sth160488 free(ret->server); 2626842Sth160488 ret->server = NULL; 2636842Sth160488 return (NS_LDAP_INTERNAL); 2646842Sth160488 } 2656842Sth160488 } 2666842Sth160488 } 2676842Sth160488 2686842Sth160488 return (NS_LDAP_SUCCESS); 2696842Sth160488 } 2706842Sth160488 2716842Sth160488 (void) memset(space.s_b, 0, DOORBUFFERSIZE); 2726842Sth160488 2732830Sdjl adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1); 2740Sstevel@tonic-gate if (server != NULL) { 2750Sstevel@tonic-gate adata += strlen(DOORLINESEP) + 1; 2760Sstevel@tonic-gate adata += strlen(server) + 1; 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate ndata = sizeof (space); 2792830Sdjl len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber); 2800Sstevel@tonic-gate space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER; 2812830Sdjl if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len) 2822830Sdjl return (NS_LDAP_MEMORY); 2832830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >= 2844522Schinlong len) 2852830Sdjl return (NS_LDAP_MEMORY); 2860Sstevel@tonic-gate if (server != NULL) { 2872830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, 2884522Schinlong DOORLINESEP, len) >= len) 2892830Sdjl return (NS_LDAP_MEMORY); 2902830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, 2914522Schinlong len) >= len) 2922830Sdjl return (NS_LDAP_MEMORY); 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate sptr = &space.s_d; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) { 2976842Sth160488 case NS_CACHE_SUCCESS: 2980Sstevel@tonic-gate break; 2990Sstevel@tonic-gate /* this case is for when the $mgr is not running, but ldapclient */ 3000Sstevel@tonic-gate /* is trying to initialize things */ 3016842Sth160488 case NS_CACHE_NOSERVER: 3026842Sth160488 ret_code = getFirstFromConfig(ret, error); 3036842Sth160488 if (ret_code != NS_LDAP_SUCCESS) { 3046842Sth160488 return (ret_code); 3050Sstevel@tonic-gate } 3066842Sth160488 3076842Sth160488 if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) { 3086842Sth160488 ret_code = __s_api_ip2hostname(ret->server, 3096842Sth160488 &ret->serverFQDN); 3106842Sth160488 if (ret_code != NS_LDAP_SUCCESS) { 3116842Sth160488 (void) snprintf(errstr, 3126842Sth160488 sizeof (errstr), 3136842Sth160488 gettext("The %s address " 3146842Sth160488 "can not be resolved into " 3156842Sth160488 "a host name. Returning " 3166842Sth160488 "the address as it is."), 3176842Sth160488 ret->server); 3186842Sth160488 MKERROR(LOG_ERR, 3196842Sth160488 *error, 3206842Sth160488 NS_CONFIG_NOTLOADED, 3216842Sth160488 strdup(errstr), 3226842Sth160488 NS_LDAP_MEMORY); 3236842Sth160488 free(ret->server); 3246842Sth160488 ret->server = NULL; 3256842Sth160488 return (NS_LDAP_INTERNAL); 3266842Sth160488 } 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 3296842Sth160488 case NS_CACHE_NOTFOUND: 3300Sstevel@tonic-gate default: 3310Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate /* copy info from door call return structure here */ 3350Sstevel@tonic-gate rbuf = space.s_d.ldap_ret.ldap_u.config; 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate /* Get the host */ 3380Sstevel@tonic-gate ptr = strtok_r(rbuf, DOORLINESEP, &rest); 3390Sstevel@tonic-gate if (ptr == NULL) { 3400Sstevel@tonic-gate (void) sprintf(errstr, gettext("No server returned from " 3414522Schinlong "ldap_cachemgr")); 3420Sstevel@tonic-gate MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR, 3436842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 3440Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate ret->server = strdup(ptr); 3470Sstevel@tonic-gate if (ret->server == NULL) { 3480Sstevel@tonic-gate return (NS_LDAP_MEMORY); 3490Sstevel@tonic-gate } 3504522Schinlong /* Get the host FQDN format */ 3514522Schinlong if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) { 3524522Schinlong ptr = strtok_r(NULL, DOORLINESEP, &rest); 3534522Schinlong if (ptr == NULL) { 3544522Schinlong (void) sprintf(errstr, gettext("No server FQDN format " 3554522Schinlong "returned from ldap_cachemgr")); 3564522Schinlong MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR, 3574522Schinlong strdup(errstr), NULL); 3584522Schinlong free(ret->server); 3594522Schinlong ret->server = NULL; 3604522Schinlong return (NS_LDAP_OP_FAILED); 3614522Schinlong } 3624522Schinlong ret->serverFQDN = strdup(ptr); 3634522Schinlong if (ret->serverFQDN == NULL) { 3644522Schinlong free(ret->server); 3654522Schinlong ret->server = NULL; 3664522Schinlong return (NS_LDAP_MEMORY); 3674522Schinlong } 3684522Schinlong } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate /* get the Supported Controls/SASL mechs */ 3710Sstevel@tonic-gate mptr = NULL; 3720Sstevel@tonic-gate mcnt = 0; 3730Sstevel@tonic-gate cptr = NULL; 3740Sstevel@tonic-gate ccnt = 0; 3756842Sth160488 for (;;) { 3760Sstevel@tonic-gate ptr = strtok_r(NULL, DOORLINESEP, &rest); 3770Sstevel@tonic-gate if (ptr == NULL) 3780Sstevel@tonic-gate break; 3790Sstevel@tonic-gate if (strncasecmp(ptr, _SASLMECHANISM, 3804522Schinlong _SASLMECHANISM_LEN) == 0) { 3810Sstevel@tonic-gate dptr = strchr(ptr, '='); 3820Sstevel@tonic-gate if (dptr == NULL) 3830Sstevel@tonic-gate continue; 3840Sstevel@tonic-gate dptr++; 3850Sstevel@tonic-gate mptr1 = (char **)realloc((void *)mptr, 3864522Schinlong sizeof (char *) * (mcnt+2)); 3870Sstevel@tonic-gate if (mptr1 == NULL) { 3880Sstevel@tonic-gate __s_api_free2dArray(mptr); 3890Sstevel@tonic-gate if (sptr != &space.s_d) { 3904522Schinlong (void) munmap((char *)sptr, ndata); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate __s_api_free2dArray(cptr); 3934522Schinlong __s_api_free_server_info(ret); 3940Sstevel@tonic-gate return (NS_LDAP_MEMORY); 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate mptr = mptr1; 3970Sstevel@tonic-gate mptr[mcnt] = strdup(dptr); 3980Sstevel@tonic-gate if (mptr[mcnt] == NULL) { 3990Sstevel@tonic-gate if (sptr != &space.s_d) { 4004522Schinlong (void) munmap((char *)sptr, ndata); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate __s_api_free2dArray(cptr); 4030Sstevel@tonic-gate cptr = NULL; 4040Sstevel@tonic-gate __s_api_free2dArray(mptr); 4050Sstevel@tonic-gate mptr = NULL; 4064522Schinlong __s_api_free_server_info(ret); 4070Sstevel@tonic-gate return (NS_LDAP_MEMORY); 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate mcnt++; 4100Sstevel@tonic-gate mptr[mcnt] = NULL; 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate if (strncasecmp(ptr, _SUPPORTEDCONTROL, 4134522Schinlong _SUPPORTEDCONTROL_LEN) == 0) { 4140Sstevel@tonic-gate dptr = strchr(ptr, '='); 4150Sstevel@tonic-gate if (dptr == NULL) 4160Sstevel@tonic-gate continue; 4170Sstevel@tonic-gate dptr++; 4180Sstevel@tonic-gate cptr1 = (char **)realloc((void *)cptr, 4194522Schinlong sizeof (char *) * (ccnt+2)); 4200Sstevel@tonic-gate if (cptr1 == NULL) { 4210Sstevel@tonic-gate if (sptr != &space.s_d) { 4224522Schinlong (void) munmap((char *)sptr, ndata); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate __s_api_free2dArray(cptr); 4250Sstevel@tonic-gate __s_api_free2dArray(mptr); 4260Sstevel@tonic-gate mptr = NULL; 4274522Schinlong __s_api_free_server_info(ret); 4280Sstevel@tonic-gate return (NS_LDAP_MEMORY); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate cptr = cptr1; 4310Sstevel@tonic-gate cptr[ccnt] = strdup(dptr); 4320Sstevel@tonic-gate if (cptr[ccnt] == NULL) { 4330Sstevel@tonic-gate if (sptr != &space.s_d) { 4344522Schinlong (void) munmap((char *)sptr, ndata); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate __s_api_free2dArray(cptr); 4370Sstevel@tonic-gate cptr = NULL; 4380Sstevel@tonic-gate __s_api_free2dArray(mptr); 4390Sstevel@tonic-gate mptr = NULL; 4404522Schinlong __s_api_free_server_info(ret); 4410Sstevel@tonic-gate return (NS_LDAP_MEMORY); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate ccnt++; 4440Sstevel@tonic-gate cptr[ccnt] = NULL; 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate if (mptr != NULL) { 4480Sstevel@tonic-gate ret->saslMechanisms = mptr; 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate if (cptr != NULL) { 4510Sstevel@tonic-gate ret->controls = cptr; 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* clean up door call */ 4560Sstevel@tonic-gate if (sptr != &space.s_d) { 4570Sstevel@tonic-gate (void) munmap((char *)sptr, ndata); 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate *error = NULL; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate 4656842Sth160488 #ifdef DEBUG 4660Sstevel@tonic-gate /* 4670Sstevel@tonic-gate * printCred(): prints the credential structure 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate static void 4706842Sth160488 printCred(FILE *fp, const ns_cred_t *cred) 4710Sstevel@tonic-gate { 4722830Sdjl thread_t t = thr_self(); 4732830Sdjl 4740Sstevel@tonic-gate if (cred == NULL) { 4756842Sth160488 (void) fprintf(fp, "tid= %d: printCred: cred is NULL\n", t); 4760Sstevel@tonic-gate return; 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4796842Sth160488 (void) fprintf(fp, "tid= %d: AuthType=%d", t, cred->auth.type); 4806842Sth160488 (void) fprintf(fp, "tid= %d: TlsType=%d", t, cred->auth.tlstype); 4816842Sth160488 (void) fprintf(fp, "tid= %d: SaslMech=%d", t, cred->auth.saslmech); 4826842Sth160488 (void) fprintf(fp, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt); 4830Sstevel@tonic-gate if (cred->hostcertpath) 4846842Sth160488 (void) fprintf(fp, "tid= %d: hostCertPath=%s\n", 4854522Schinlong t, cred->hostcertpath); 4860Sstevel@tonic-gate if (cred->cred.unix_cred.userID) 4876842Sth160488 (void) fprintf(fp, "tid= %d: userID=%s\n", 4884522Schinlong t, cred->cred.unix_cred.userID); 4890Sstevel@tonic-gate if (cred->cred.unix_cred.passwd) 4906842Sth160488 (void) fprintf(fp, "tid= %d: passwd=%s\n", 4914522Schinlong t, cred->cred.unix_cred.passwd); 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate /* 4950Sstevel@tonic-gate * printConnection(): prints the connection structure 4960Sstevel@tonic-gate */ 4970Sstevel@tonic-gate static void 4986842Sth160488 printConnection(FILE *fp, Connection *con) 4990Sstevel@tonic-gate { 5002830Sdjl thread_t t = thr_self(); 5012830Sdjl 5022830Sdjl if (con == NULL) 5030Sstevel@tonic-gate return; 5040Sstevel@tonic-gate 5056842Sth160488 (void) fprintf(fp, "tid= %d: connectionID=%d\n", t, con->connectionId); 5066842Sth160488 (void) fprintf(fp, "tid= %d: usedBit=%d\n", t, con->usedBit); 5076842Sth160488 (void) fprintf(fp, "tid= %d: threadID=%d\n", t, con->threadID); 5080Sstevel@tonic-gate if (con->serverAddr) { 5096842Sth160488 (void) fprintf(fp, "tid= %d: serverAddr=%s\n", 5104522Schinlong t, con->serverAddr); 5110Sstevel@tonic-gate } 5126842Sth160488 printCred(fp, con->auth); 5130Sstevel@tonic-gate } 5146842Sth160488 #endif 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate /* 5176842Sth160488 * addConnection(): inserts a connection in the connection list. 5186842Sth160488 * It will also sets use bit and the thread Id for the thread 5196842Sth160488 * using the connection for the first time. 5200Sstevel@tonic-gate * Returns: -1 = failure, new Connection ID = success 5210Sstevel@tonic-gate */ 5220Sstevel@tonic-gate static int 5230Sstevel@tonic-gate addConnection(Connection *con) 5240Sstevel@tonic-gate { 5256842Sth160488 int i; 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate if (!con) 5280Sstevel@tonic-gate return (-1); 5296842Sth160488 #ifdef DEBUG 5306842Sth160488 (void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID); 5316842Sth160488 #endif /* DEBUG */ 5326842Sth160488 (void) mutex_lock(&sessionPoolLock); 5330Sstevel@tonic-gate if (sessionPool == NULL) { 5340Sstevel@tonic-gate sessionPoolSize = SESSION_CACHE_INC; 5350Sstevel@tonic-gate sessionPool = calloc(sessionPoolSize, 5366842Sth160488 sizeof (Connection *)); 5370Sstevel@tonic-gate if (!sessionPool) { 5386842Sth160488 (void) mutex_unlock(&sessionPoolLock); 5390Sstevel@tonic-gate return (-1); 5400Sstevel@tonic-gate } 5416842Sth160488 #ifdef DEBUG 5426842Sth160488 (void) fprintf(stderr, "Initialized sessionPool\n"); 5436842Sth160488 #endif /* DEBUG */ 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i) 5460Sstevel@tonic-gate ; 5470Sstevel@tonic-gate if (i == sessionPoolSize) { 5480Sstevel@tonic-gate /* run out of array, need to increase sessionPool */ 5490Sstevel@tonic-gate Connection **cl; 5500Sstevel@tonic-gate cl = (Connection **) realloc(sessionPool, 5514522Schinlong (sessionPoolSize + SESSION_CACHE_INC) * 5524522Schinlong sizeof (Connection *)); 5530Sstevel@tonic-gate if (!cl) { 5546842Sth160488 (void) mutex_unlock(&sessionPoolLock); 5550Sstevel@tonic-gate return (-1); 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate (void) memset(cl + sessionPoolSize, 0, 5586842Sth160488 SESSION_CACHE_INC * sizeof (Connection *)); 5590Sstevel@tonic-gate sessionPool = cl; 5600Sstevel@tonic-gate sessionPoolSize += SESSION_CACHE_INC; 5616842Sth160488 #ifdef DEBUG 5626842Sth160488 (void) fprintf(stderr, "Increased sessionPoolSize to: %d\n", 5636842Sth160488 sessionPoolSize); 5646842Sth160488 #endif /* DEBUG */ 5650Sstevel@tonic-gate } 5660Sstevel@tonic-gate sessionPool[i] = con; 5676842Sth160488 con->usedBit = B_TRUE; 5686842Sth160488 (void) mutex_unlock(&sessionPoolLock); 5690Sstevel@tonic-gate con->connectionId = i + CONID_OFFSET; 5706842Sth160488 #ifdef DEBUG 5716842Sth160488 (void) fprintf(stderr, "Connection added [%d]\n", i); 5726842Sth160488 printConnection(stderr, con); 5736842Sth160488 #endif /* DEBUG */ 5740Sstevel@tonic-gate return (i + CONID_OFFSET); 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * findConnection(): find an available connection from the list 5790Sstevel@tonic-gate * that matches the criteria specified in Connection structure. 5800Sstevel@tonic-gate * If serverAddr is NULL, then find a connection to any server 5810Sstevel@tonic-gate * as long as it matches the rest of the parameters. 5820Sstevel@tonic-gate * Returns: -1 = failure, the Connection ID found = success. 5830Sstevel@tonic-gate */ 5840Sstevel@tonic-gate static int 5852830Sdjl findConnection(int flags, const char *serverAddr, 5862830Sdjl const ns_cred_t *auth, Connection **conp) 5870Sstevel@tonic-gate { 5880Sstevel@tonic-gate Connection *cp; 5896842Sth160488 int i; 5902830Sdjl #ifdef DEBUG 5916842Sth160488 thread_t t; 5922830Sdjl #endif /* DEBUG */ 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate if (auth == NULL || conp == NULL) 5950Sstevel@tonic-gate return (-1); 5960Sstevel@tonic-gate *conp = NULL; 5970Sstevel@tonic-gate 5985840Smj162486 /* 5995840Smj162486 * If a new connection is requested, no need to continue. 6006842Sth160488 * If the process is not nscd and is not requesting keep 6016842Sth160488 * connections alive, no need to continue. 6025840Smj162486 */ 6035840Smj162486 if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() && 6046072Smj162486 !__s_api_peruser_proc() && !(flags & NS_LDAP_KEEP_CONN))) 6052830Sdjl return (-1); 6062830Sdjl 6070Sstevel@tonic-gate #ifdef DEBUG 6086842Sth160488 t = thr_self(); 6092830Sdjl (void) fprintf(stderr, "tid= %d: Find connection\n", t); 6102830Sdjl (void) fprintf(stderr, "tid= %d: Looking for ....\n", t); 6110Sstevel@tonic-gate if (serverAddr && *serverAddr) 6122830Sdjl (void) fprintf(stderr, "tid= %d: serverAddr=%s\n", 6134522Schinlong t, serverAddr); 6140Sstevel@tonic-gate else 6152830Sdjl (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t); 6166842Sth160488 printCred(stderr, auth); 6170Sstevel@tonic-gate fflush(stderr); 6180Sstevel@tonic-gate #endif /* DEBUG */ 6196842Sth160488 if (sessionPool == NULL) 6200Sstevel@tonic-gate return (-1); 6216842Sth160488 (void) mutex_lock(&sessionPoolLock); 6220Sstevel@tonic-gate for (i = 0; i < sessionPoolSize; ++i) { 6230Sstevel@tonic-gate if (sessionPool[i] == NULL) 6240Sstevel@tonic-gate continue; 6250Sstevel@tonic-gate cp = sessionPool[i]; 6260Sstevel@tonic-gate #ifdef DEBUG 6276842Sth160488 (void) fprintf(stderr, 6286842Sth160488 "tid: %d: checking connection [%d] ....\n", t, i); 6296842Sth160488 printConnection(stderr, cp); 6300Sstevel@tonic-gate #endif /* DEBUG */ 6316842Sth160488 if ((cp->usedBit) || (serverAddr && *serverAddr && 6320Sstevel@tonic-gate (strcasecmp(serverAddr, cp->serverAddr) != 0))) 6330Sstevel@tonic-gate continue; 6344048Schinlong 6356842Sth160488 if (__s_api_is_auth_matched(cp->auth, auth) == B_FALSE) 6366842Sth160488 continue; 6374048Schinlong 6380Sstevel@tonic-gate /* found an available connection */ 6396842Sth160488 cp->usedBit = B_TRUE; 6406842Sth160488 (void) mutex_unlock(&sessionPoolLock); 6416842Sth160488 cp->threadID = thr_self(); 6420Sstevel@tonic-gate *conp = cp; 6430Sstevel@tonic-gate #ifdef DEBUG 6446842Sth160488 (void) fprintf(stderr, 6456842Sth160488 "tid %d: Connection found cID=%d\n", t, i); 6460Sstevel@tonic-gate fflush(stderr); 6470Sstevel@tonic-gate #endif /* DEBUG */ 6480Sstevel@tonic-gate return (i + CONID_OFFSET); 6490Sstevel@tonic-gate } 6506842Sth160488 (void) mutex_unlock(&sessionPoolLock); 6516842Sth160488 return (-1); 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate /* 6550Sstevel@tonic-gate * Free a Connection structure 6560Sstevel@tonic-gate */ 6576842Sth160488 void 6586842Sth160488 __s_api_freeConnection(Connection *con) 6590Sstevel@tonic-gate { 6600Sstevel@tonic-gate if (con == NULL) 6610Sstevel@tonic-gate return; 6620Sstevel@tonic-gate if (con->serverAddr) 6630Sstevel@tonic-gate free(con->serverAddr); 6640Sstevel@tonic-gate if (con->auth) 6650Sstevel@tonic-gate (void) __ns_ldap_freeCred(&(con->auth)); 6660Sstevel@tonic-gate if (con->saslMechanisms) { 6670Sstevel@tonic-gate __s_api_free2dArray(con->saslMechanisms); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate if (con->controls) { 6700Sstevel@tonic-gate __s_api_free2dArray(con->controls); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate free(con); 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate /* 6760Sstevel@tonic-gate * Find a connection matching the passed in criteria. If an open 6770Sstevel@tonic-gate * connection with that criteria exists use it, otherwise open a 6780Sstevel@tonic-gate * new connection. 6790Sstevel@tonic-gate * Success: returns the pointer to the Connection structure 6800Sstevel@tonic-gate * Failure: returns NULL, error code and message should be in errorp 6810Sstevel@tonic-gate */ 6821687Sjanga 6830Sstevel@tonic-gate static int 6840Sstevel@tonic-gate makeConnection(Connection **conp, const char *serverAddr, 6850Sstevel@tonic-gate const ns_cred_t *auth, ConnectionID *cID, int timeoutSec, 6861179Svv149972 ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd, 6876842Sth160488 int nopasswd_acct_mgmt, int flags, char ***badsrvrs, 6886842Sth160488 ns_conn_user_t *conn_user) 6890Sstevel@tonic-gate { 6900Sstevel@tonic-gate Connection *con = NULL; 6910Sstevel@tonic-gate ConnectionID id; 6920Sstevel@tonic-gate char errmsg[MAXERROR]; 6930Sstevel@tonic-gate int rc, exit_rc = NS_LDAP_SUCCESS; 6940Sstevel@tonic-gate ns_server_info_t sinfo; 6950Sstevel@tonic-gate char *hReq, *host = NULL; 6960Sstevel@tonic-gate LDAP *ld = NULL; 6970Sstevel@tonic-gate int passwd_mgmt = 0; 6981687Sjanga int totalbad = 0; /* Number of servers contacted unsuccessfully */ 6992830Sdjl short memerr = 0; /* Variable for tracking memory allocation */ 7004522Schinlong char *serverAddrType = NULL, **bindHost = NULL; 7012830Sdjl 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate if (conp == NULL || errorp == NULL || auth == NULL) 7040Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 7050Sstevel@tonic-gate *errorp = NULL; 7060Sstevel@tonic-gate *conp = NULL; 7074522Schinlong (void) memset(&sinfo, 0, sizeof (sinfo)); 7080Sstevel@tonic-gate 7096842Sth160488 if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) { 7100Sstevel@tonic-gate /* connection found in cache */ 7110Sstevel@tonic-gate #ifdef DEBUG 7122830Sdjl (void) fprintf(stderr, "tid= %d: connection found in " 7134522Schinlong "cache %d\n", thr_self(), id); 7140Sstevel@tonic-gate fflush(stderr); 7150Sstevel@tonic-gate #endif /* DEBUG */ 7160Sstevel@tonic-gate *cID = id; 7170Sstevel@tonic-gate *conp = con; 7180Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7214522Schinlong if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 7222830Sdjl serverAddrType = NS_CACHE_ADDR_HOSTNAME; 7234522Schinlong bindHost = &sinfo.serverFQDN; 7244522Schinlong } else { 7252830Sdjl serverAddrType = NS_CACHE_ADDR_IP; 7264522Schinlong bindHost = &sinfo.server; 7274522Schinlong } 7282830Sdjl 7290Sstevel@tonic-gate if (serverAddr) { 7306842Sth160488 if (__s_api_isInitializing()) { 7316842Sth160488 /* 7326842Sth160488 * When obtaining the root DSE, connect to the server 7336842Sth160488 * passed here through the serverAddr parameter 7346842Sth160488 */ 7356842Sth160488 sinfo.server = strdup(serverAddr); 7366842Sth160488 if (sinfo.server == NULL) 7375559Ssdussud return (NS_LDAP_MEMORY); 7386842Sth160488 if (strcmp(serverAddrType, 7396842Sth160488 NS_CACHE_ADDR_HOSTNAME) == 0) { 7406842Sth160488 rc = __s_api_ip2hostname(sinfo.server, 7416842Sth160488 &sinfo.serverFQDN); 7426842Sth160488 if (rc != NS_LDAP_SUCCESS) { 7436842Sth160488 (void) snprintf(errmsg, 7446842Sth160488 sizeof (errmsg), 7456842Sth160488 gettext("The %s address " 7466842Sth160488 "can not be resolved into " 7476842Sth160488 "a host name. Returning " 7486842Sth160488 "the address as it is."), 7496842Sth160488 serverAddr); 7506842Sth160488 MKERROR(LOG_ERR, 7516842Sth160488 *errorp, 7526842Sth160488 NS_CONFIG_NOTLOADED, 7536842Sth160488 strdup(errmsg), 7546842Sth160488 NS_LDAP_MEMORY); 7556842Sth160488 __s_api_free_server_info(&sinfo); 7566842Sth160488 return (NS_LDAP_INTERNAL); 7576842Sth160488 } 7586842Sth160488 } 7596842Sth160488 } else { 7606842Sth160488 /* 7616842Sth160488 * We're given the server address, just use it. 7626842Sth160488 * In case of sasl/GSSAPI, serverAddr would need 7636842Sth160488 * to be a FQDN. We assume this is the case for now. 7646842Sth160488 * 7656842Sth160488 * Only the server address fields of sinfo structure 7666842Sth160488 * are filled in since these are the only relevant 7676842Sth160488 * data that we have. Other fields of this structure 7686842Sth160488 * (controls, saslMechanisms) are kept to NULL. 7696842Sth160488 */ 7706842Sth160488 sinfo.server = strdup(serverAddr); 7716842Sth160488 if (sinfo.server == NULL) { 7726842Sth160488 return (NS_LDAP_MEMORY); 7736842Sth160488 } 7746842Sth160488 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 7756842Sth160488 sinfo.serverFQDN = strdup(serverAddr); 7766842Sth160488 if (sinfo.serverFQDN == NULL) { 7776842Sth160488 free(sinfo.server); 7786842Sth160488 return (NS_LDAP_MEMORY); 7796842Sth160488 } 7805559Ssdussud } 7812830Sdjl } 7824522Schinlong rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp, 7836842Sth160488 fail_if_new_pwd_reqd, passwd_mgmt, conn_user); 7840Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || rc == 7854522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 7860Sstevel@tonic-gate exit_rc = rc; 7870Sstevel@tonic-gate goto create_con; 7880Sstevel@tonic-gate } else { 7895559Ssdussud if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 7905559Ssdussud (void) snprintf(errmsg, sizeof (errmsg), 7915559Ssdussud "%s %s", gettext("makeConnection: " 7925559Ssdussud "failed to open connection using " 7935559Ssdussud "sasl/GSSAPI to"), *bindHost); 7945559Ssdussud } else { 7955559Ssdussud (void) snprintf(errmsg, sizeof (errmsg), 7965559Ssdussud "%s %s", gettext("makeConnection: " 7975559Ssdussud "failed to open connection to"), 7985559Ssdussud *bindHost); 7995559Ssdussud } 8005559Ssdussud syslog(LOG_ERR, "libsldap: %s", errmsg); 8015559Ssdussud __s_api_free_server_info(&sinfo); 8020Sstevel@tonic-gate return (rc); 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate /* No cached connection, create one */ 8070Sstevel@tonic-gate for (; ; ) { 8080Sstevel@tonic-gate if (host == NULL) 8090Sstevel@tonic-gate hReq = NS_CACHE_NEW; 8100Sstevel@tonic-gate else 8110Sstevel@tonic-gate hReq = NS_CACHE_NEXT; 8122830Sdjl rc = __s_api_requestServer(hReq, host, &sinfo, errorp, 8134522Schinlong serverAddrType); 8140Sstevel@tonic-gate if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) || 8154522Schinlong (host && (strcasecmp(host, sinfo.server) == 0))) { 8160Sstevel@tonic-gate /* Log the error */ 8170Sstevel@tonic-gate if (*errorp) { 8180Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 8190Sstevel@tonic-gate "%s: (%s)", gettext("makeConnection: " 8200Sstevel@tonic-gate "unable to make LDAP connection, " 8210Sstevel@tonic-gate "request for a server failed"), 8220Sstevel@tonic-gate (*errorp)->message); 8230Sstevel@tonic-gate syslog(LOG_ERR, "libsldap: %s", errmsg); 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate 8264522Schinlong __s_api_free_server_info(&sinfo); 8270Sstevel@tonic-gate if (host) 8280Sstevel@tonic-gate free(host); 8290Sstevel@tonic-gate return (NS_LDAP_OP_FAILED); 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate if (host) 8320Sstevel@tonic-gate free(host); 8330Sstevel@tonic-gate host = strdup(sinfo.server); 8340Sstevel@tonic-gate if (host == NULL) { 8354522Schinlong __s_api_free_server_info(&sinfo); 8360Sstevel@tonic-gate return (NS_LDAP_MEMORY); 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate /* check if server supports password management */ 8400Sstevel@tonic-gate passwd_mgmt = __s_api_contain_passwd_control_oid( 8414522Schinlong sinfo.controls); 8421179Svv149972 /* check if server supports password less account mgmt */ 8431179Svv149972 if (nopasswd_acct_mgmt && 8444522Schinlong !__s_api_contain_account_usable_control_oid( 8454522Schinlong sinfo.controls)) { 8461179Svv149972 syslog(LOG_WARNING, "libsldap: server %s does not " 8474522Schinlong "provide account information without password", 8484522Schinlong host); 8491179Svv149972 free(host); 8504522Schinlong __s_api_free_server_info(&sinfo); 8511179Svv149972 return (NS_LDAP_OP_FAILED); 8521179Svv149972 } 8530Sstevel@tonic-gate /* make the connection */ 8544522Schinlong rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp, 8556842Sth160488 fail_if_new_pwd_reqd, passwd_mgmt, conn_user); 8560Sstevel@tonic-gate /* if success, go to create connection structure */ 8570Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 8584522Schinlong rc == NS_LDAP_SUCCESS_WITH_INFO) { 8590Sstevel@tonic-gate exit_rc = rc; 8600Sstevel@tonic-gate break; 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate /* 8640Sstevel@tonic-gate * If not able to reach the server, inform the ldap 8650Sstevel@tonic-gate * cache manager that the server should be removed 8660Sstevel@tonic-gate * from its server list. Thus, the manager will not 8670Sstevel@tonic-gate * return this server on the next get-server request 8680Sstevel@tonic-gate * and will also reduce the server list refresh TTL, 8690Sstevel@tonic-gate * so that it will find out sooner when the server 8700Sstevel@tonic-gate * is up again. 8710Sstevel@tonic-gate */ 8720Sstevel@tonic-gate if (rc == NS_LDAP_INTERNAL && *errorp != NULL) { 8730Sstevel@tonic-gate if ((*errorp)->status == LDAP_CONNECT_ERROR || 8744522Schinlong (*errorp)->status == LDAP_SERVER_DOWN) { 8751687Sjanga /* Reset memory allocation error */ 8761687Sjanga memerr = 0; 8771687Sjanga /* 8781687Sjanga * We contacted a server that we could 8791687Sjanga * not either authenticate to or contact. 8801687Sjanga * If it is due to authentication, then 8811687Sjanga * we need to try the server again. So, 8821687Sjanga * do not remove the server yet, but 8831687Sjanga * add it to the bad server list. 8841687Sjanga * The caller routine will remove 8851687Sjanga * the servers if: 8861687Sjanga * a). A good server is found or 8871687Sjanga * b). All the possible methods 8881687Sjanga * are tried without finding 8891687Sjanga * a good server 8901687Sjanga */ 8911687Sjanga if (*badsrvrs == NULL) { 8924522Schinlong if (!(*badsrvrs = (char **)malloc 8934522Schinlong (sizeof (char *) * NUMTOMALLOC))) { 8944522Schinlong memerr = 1; 8954522Schinlong } 8961687Sjanga /* Allocate memory in chunks of NUMTOMALLOC */ 8971687Sjanga } else if ((totalbad % NUMTOMALLOC) == 8984522Schinlong NUMTOMALLOC - 1) { 8994522Schinlong char **tmpptr; 9004522Schinlong if (!(tmpptr = (char **)realloc( 9014522Schinlong *badsrvrs, 9021687Sjanga (sizeof (char *) * NUMTOMALLOC * 9031687Sjanga ((totalbad/NUMTOMALLOC) + 2))))) { 9044522Schinlong memerr = 1; 9054522Schinlong } else { 9064522Schinlong *badsrvrs = tmpptr; 9074522Schinlong } 908493Ssdussud } 9091687Sjanga /* 9101687Sjanga * Store host only if there were no unsuccessful 9111687Sjanga * memory allocations above 9121687Sjanga */ 9131687Sjanga if (!memerr && 9141687Sjanga !((*badsrvrs)[totalbad++] = strdup(host))) { 9151687Sjanga memerr = 1; 9161687Sjanga totalbad--; 9171687Sjanga } 9181687Sjanga (*badsrvrs)[totalbad] = NULL; 919493Ssdussud } 9200Sstevel@tonic-gate } 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate /* else, cleanup and go for the next server */ 9234522Schinlong __s_api_free_server_info(&sinfo); 9244522Schinlong 9251687Sjanga /* Return if we had memory allocation errors */ 9261687Sjanga if (memerr) 9271687Sjanga return (NS_LDAP_MEMORY); 9280Sstevel@tonic-gate if (*errorp) { 9290Sstevel@tonic-gate /* 9300Sstevel@tonic-gate * If openConnection() failed due to 9310Sstevel@tonic-gate * password policy, or invalid credential, 9320Sstevel@tonic-gate * keep *errorp and exit 9330Sstevel@tonic-gate */ 9340Sstevel@tonic-gate if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD || 9350Sstevel@tonic-gate (*errorp)->status == LDAP_INVALID_CREDENTIALS) { 9360Sstevel@tonic-gate free(host); 9370Sstevel@tonic-gate return (rc); 9380Sstevel@tonic-gate } else { 9390Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 9400Sstevel@tonic-gate *errorp = NULL; 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate create_con: 9460Sstevel@tonic-gate /* we have created ld, setup con structure */ 9470Sstevel@tonic-gate if (host) 9480Sstevel@tonic-gate free(host); 9490Sstevel@tonic-gate if ((con = calloc(1, sizeof (Connection))) == NULL) { 9504522Schinlong __s_api_free_server_info(&sinfo); 9510Sstevel@tonic-gate /* 9520Sstevel@tonic-gate * If password control attached in **errorp, 9530Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 9540Sstevel@tonic-gate * free the error structure 9550Sstevel@tonic-gate */ 9560Sstevel@tonic-gate if (*errorp) { 9570Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 9580Sstevel@tonic-gate *errorp = NULL; 9590Sstevel@tonic-gate } 9605559Ssdussud (void) ldap_unbind(ld); 9610Sstevel@tonic-gate return (NS_LDAP_MEMORY); 9620Sstevel@tonic-gate } 9630Sstevel@tonic-gate 9644522Schinlong con->serverAddr = sinfo.server; /* Store original format */ 9654522Schinlong if (sinfo.serverFQDN != NULL) { 9664522Schinlong free(sinfo.serverFQDN); 9674522Schinlong sinfo.serverFQDN = NULL; 9684522Schinlong } 9690Sstevel@tonic-gate con->saslMechanisms = sinfo.saslMechanisms; 9700Sstevel@tonic-gate con->controls = sinfo.controls; 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate con->auth = __ns_ldap_dupAuth(auth); 9730Sstevel@tonic-gate if (con->auth == NULL) { 9745559Ssdussud (void) ldap_unbind(ld); 9756842Sth160488 __s_api_freeConnection(con); 9760Sstevel@tonic-gate /* 9770Sstevel@tonic-gate * If password control attached in **errorp, 9780Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 9790Sstevel@tonic-gate * free the error structure 9800Sstevel@tonic-gate */ 9810Sstevel@tonic-gate if (*errorp) { 9820Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 9830Sstevel@tonic-gate *errorp = NULL; 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate return (NS_LDAP_MEMORY); 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate con->threadID = thr_self(); 9893387Schinlong con->pid = getpid(); 9902830Sdjl 9910Sstevel@tonic-gate con->ld = ld; 9926842Sth160488 /* add MT connection to the MT connection pool */ 9936842Sth160488 if (conn_user != NULL && conn_user->conn_mt != NULL) { 9946842Sth160488 if (__s_api_conn_mt_add(con, conn_user, errorp) == 9956842Sth160488 NS_LDAP_SUCCESS) { 9966842Sth160488 *conp = con; 9976842Sth160488 return (exit_rc); 9986842Sth160488 } else { 9996842Sth160488 (void) ldap_unbind(ld); 10006842Sth160488 __s_api_freeConnection(con); 10016842Sth160488 return ((*errorp)->status); 10026842Sth160488 } 10036842Sth160488 } 10046842Sth160488 10056842Sth160488 /* MT connection not supported or not required case */ 10060Sstevel@tonic-gate if ((id = addConnection(con)) == -1) { 10075559Ssdussud (void) ldap_unbind(ld); 10086842Sth160488 __s_api_freeConnection(con); 10090Sstevel@tonic-gate /* 10100Sstevel@tonic-gate * If password control attached in **errorp, 10110Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 10120Sstevel@tonic-gate * free the error structure 10130Sstevel@tonic-gate */ 10140Sstevel@tonic-gate if (*errorp) { 10150Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 10160Sstevel@tonic-gate *errorp = NULL; 10170Sstevel@tonic-gate } 10180Sstevel@tonic-gate return (NS_LDAP_MEMORY); 10190Sstevel@tonic-gate } 10200Sstevel@tonic-gate #ifdef DEBUG 10212830Sdjl (void) fprintf(stderr, "tid= %d: connection added into " 10224522Schinlong "cache %d\n", thr_self(), id); 10230Sstevel@tonic-gate fflush(stderr); 10240Sstevel@tonic-gate #endif /* DEBUG */ 10250Sstevel@tonic-gate *cID = id; 10260Sstevel@tonic-gate *conp = con; 10270Sstevel@tonic-gate return (exit_rc); 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * Return the specified connection to the pool. If necessary 10320Sstevel@tonic-gate * delete the connection. 10330Sstevel@tonic-gate */ 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate static void 10360Sstevel@tonic-gate _DropConnection(ConnectionID cID, int flag, int fini) 10370Sstevel@tonic-gate { 10380Sstevel@tonic-gate Connection *cp; 10390Sstevel@tonic-gate int id; 10406842Sth160488 int use_mutex = !fini; 10416722Smj162486 struct timeval zerotime; 10426722Smj162486 LDAPMessage *res; 10436722Smj162486 10446722Smj162486 zerotime.tv_sec = zerotime.tv_usec = 0L; 10456722Smj162486 10460Sstevel@tonic-gate id = cID - CONID_OFFSET; 10470Sstevel@tonic-gate if (id < 0 || id >= sessionPoolSize) 10480Sstevel@tonic-gate return; 10490Sstevel@tonic-gate #ifdef DEBUG 10506842Sth160488 (void) fprintf(stderr, 10516842Sth160488 "tid %d: Dropping connection cID=%d flag=0x%x\n", 10526842Sth160488 thr_self(), cID, flag); 10530Sstevel@tonic-gate fflush(stderr); 10540Sstevel@tonic-gate #endif /* DEBUG */ 10556842Sth160488 if (use_mutex) 10566842Sth160488 (void) mutex_lock(&sessionPoolLock); 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate cp = sessionPool[id]; 10590Sstevel@tonic-gate /* sanity check before removing */ 10606842Sth160488 if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) { 10616842Sth160488 if (use_mutex) 10626842Sth160488 (void) mutex_unlock(&sessionPoolLock); 10630Sstevel@tonic-gate return; 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate if (!fini && 10676842Sth160488 ((flag & NS_LDAP_NEW_CONN) == 0) && 10686072Smj162486 ((flag & NS_LDAP_KEEP_CONN) || __s_api_nscd_proc() || 10696072Smj162486 __s_api_peruser_proc())) { 10700Sstevel@tonic-gate /* release Connection (keep alive) */ 10710Sstevel@tonic-gate cp->usedBit = B_FALSE; 10720Sstevel@tonic-gate cp->threadID = 0; /* unmark the threadID */ 10736722Smj162486 /* 10746842Sth160488 * Do sanity cleanup of remaining results. 10756722Smj162486 */ 10766842Sth160488 while (ldap_result(cp->ld, LDAP_RES_ANY, LDAP_MSG_ALL, 10776842Sth160488 &zerotime, &res) > 0) { 10786842Sth160488 if (res != NULL) 10796842Sth160488 (void) ldap_msgfree(res); 10806722Smj162486 } 10816842Sth160488 if (use_mutex) 10826842Sth160488 (void) mutex_unlock(&sessionPoolLock); 10830Sstevel@tonic-gate } else { 10840Sstevel@tonic-gate /* delete Connection (disconnect) */ 10856842Sth160488 sessionPool[id] = NULL; 10866842Sth160488 if (use_mutex) 10876842Sth160488 (void) mutex_unlock(&sessionPoolLock); 10886842Sth160488 (void) ldap_unbind(cp->ld); 10896842Sth160488 __s_api_freeConnection(cp); 10900Sstevel@tonic-gate } 10910Sstevel@tonic-gate } 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate void 10940Sstevel@tonic-gate DropConnection(ConnectionID cID, int flag) 10950Sstevel@tonic-gate { 10960Sstevel@tonic-gate _DropConnection(cID, flag, 0); 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate /* 11000Sstevel@tonic-gate * This routine is called after a bind operation is 11010Sstevel@tonic-gate * done in openConnection() to process the password 11020Sstevel@tonic-gate * management information, if any. 11030Sstevel@tonic-gate * 11040Sstevel@tonic-gate * Input: 11050Sstevel@tonic-gate * bind_type: "simple" or "sasl/DIGEST-MD5" 11060Sstevel@tonic-gate * ldaprc : ldap rc from the ldap bind operation 11070Sstevel@tonic-gate * controls : controls returned by the server 11080Sstevel@tonic-gate * errmsg : error message from the server 11090Sstevel@tonic-gate * fail_if_new_pwd_reqd: 11100Sstevel@tonic-gate * flag indicating if connection should be open 11110Sstevel@tonic-gate * when password needs to change immediately 11120Sstevel@tonic-gate * passwd_mgmt: 11130Sstevel@tonic-gate * flag indicating if server supports password 11140Sstevel@tonic-gate * policy/management 11150Sstevel@tonic-gate * 11160Sstevel@tonic-gate * Output : ns_ldap_error structure, which may contain 11170Sstevel@tonic-gate * password status and number of seconds until 11180Sstevel@tonic-gate * expired 11190Sstevel@tonic-gate * 11200Sstevel@tonic-gate * return rc: 11210Sstevel@tonic-gate * NS_LDAP_EXTERNAL: error, connection should not open 11220Sstevel@tonic-gate * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached 11230Sstevel@tonic-gate * NS_LDAP_SUCCESS: OK to open connection 11240Sstevel@tonic-gate * 11250Sstevel@tonic-gate */ 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate static int 11280Sstevel@tonic-gate process_pwd_mgmt(char *bind_type, int ldaprc, 11290Sstevel@tonic-gate LDAPControl **controls, 11300Sstevel@tonic-gate char *errmsg, ns_ldap_error_t **errorp, 11310Sstevel@tonic-gate int fail_if_new_pwd_reqd, 11320Sstevel@tonic-gate int passwd_mgmt) 11330Sstevel@tonic-gate { 11340Sstevel@tonic-gate char errstr[MAXERROR]; 11350Sstevel@tonic-gate LDAPControl **ctrl = NULL; 11360Sstevel@tonic-gate int exit_rc; 11370Sstevel@tonic-gate ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD; 11380Sstevel@tonic-gate int sec_until_exp = 0; 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate /* 11410Sstevel@tonic-gate * errmsg may be an empty string, 11420Sstevel@tonic-gate * even if ldaprc is LDAP_SUCCESS, 11430Sstevel@tonic-gate * free the empty string if that's the case 11440Sstevel@tonic-gate */ 11450Sstevel@tonic-gate if (errmsg && 11464522Schinlong (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) { 11470Sstevel@tonic-gate ldap_memfree(errmsg); 11480Sstevel@tonic-gate errmsg = NULL; 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate if (ldaprc != LDAP_SUCCESS) { 11520Sstevel@tonic-gate /* 11530Sstevel@tonic-gate * try to map ldap rc and error message to 11540Sstevel@tonic-gate * a password status 11550Sstevel@tonic-gate */ 11560Sstevel@tonic-gate if (errmsg) { 11570Sstevel@tonic-gate if (passwd_mgmt) 11580Sstevel@tonic-gate pwd_status = 11594522Schinlong __s_api_set_passwd_status( 11604522Schinlong ldaprc, errmsg); 11610Sstevel@tonic-gate ldap_memfree(errmsg); 11620Sstevel@tonic-gate } 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr), 11654522Schinlong gettext("openConnection: " 11664522Schinlong "%s bind failed " 11674522Schinlong "- %s"), bind_type, ldap_err2string(ldaprc)); 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate if (pwd_status != NS_PASSWD_GOOD) { 11700Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 11714522Schinlong ldaprc, strdup(errstr), 11724522Schinlong pwd_status, 0, NULL); 11730Sstevel@tonic-gate } else { 11740Sstevel@tonic-gate MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr), 11756842Sth160488 NS_LDAP_MEMORY); 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate if (controls) 11780Sstevel@tonic-gate ldap_controls_free(controls); 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate return (NS_LDAP_INTERNAL); 11810Sstevel@tonic-gate } 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate /* 11840Sstevel@tonic-gate * ldaprc is LDAP_SUCCESS, 11850Sstevel@tonic-gate * process the password management controls, if any 11860Sstevel@tonic-gate */ 11870Sstevel@tonic-gate exit_rc = NS_LDAP_SUCCESS; 11880Sstevel@tonic-gate if (controls && passwd_mgmt) { 11890Sstevel@tonic-gate /* 11900Sstevel@tonic-gate * The control with the OID 11910Sstevel@tonic-gate * 2.16.840.1.113730.3.4.4 (or 11920Sstevel@tonic-gate * LDAP_CONTROL_PWEXPIRED, as defined 11930Sstevel@tonic-gate * in the ldap.h header file) is the 11940Sstevel@tonic-gate * expired password control. 11950Sstevel@tonic-gate * 11960Sstevel@tonic-gate * This control is used if the server 11970Sstevel@tonic-gate * is configured to require users to 11980Sstevel@tonic-gate * change their passwords when first 11990Sstevel@tonic-gate * logging in and whenever the 12000Sstevel@tonic-gate * passwords are reset. 12010Sstevel@tonic-gate * 12020Sstevel@tonic-gate * If the user is logging in for the 12030Sstevel@tonic-gate * first time or if the user's 12040Sstevel@tonic-gate * password has been reset, the 12050Sstevel@tonic-gate * server sends this control to 12060Sstevel@tonic-gate * indicate that the client needs to 12070Sstevel@tonic-gate * change the password immediately. 12080Sstevel@tonic-gate * 12090Sstevel@tonic-gate * At this point, the only operation 12100Sstevel@tonic-gate * that the client can perform is to 12110Sstevel@tonic-gate * change the user's password. If the 12120Sstevel@tonic-gate * client requests any other LDAP 12130Sstevel@tonic-gate * operation, the server sends back 12140Sstevel@tonic-gate * an LDAP_UNWILLING_TO_PERFORM 12150Sstevel@tonic-gate * result code with an expired 12160Sstevel@tonic-gate * password control. 12170Sstevel@tonic-gate * 12180Sstevel@tonic-gate * The control with the OID 12190Sstevel@tonic-gate * 2.16.840.1.113730.3.4.5 (or 12200Sstevel@tonic-gate * LDAP_CONTROL_PWEXPIRING, as 12210Sstevel@tonic-gate * defined in the ldap.h header file) 12220Sstevel@tonic-gate * is the password expiration warning 12230Sstevel@tonic-gate * control. 12240Sstevel@tonic-gate * 12250Sstevel@tonic-gate * This control is used if the server 12260Sstevel@tonic-gate * is configured to expire user 12270Sstevel@tonic-gate * passwords after a certain amount 12280Sstevel@tonic-gate * of time. 12290Sstevel@tonic-gate * 12300Sstevel@tonic-gate * The server sends this control back 12310Sstevel@tonic-gate * to the client if the client binds 12320Sstevel@tonic-gate * using a password that will soon 12330Sstevel@tonic-gate * expire. The ldctl_value field of 12340Sstevel@tonic-gate * the LDAPControl structure 12350Sstevel@tonic-gate * specifies the number of seconds 12360Sstevel@tonic-gate * before the password will expire. 12370Sstevel@tonic-gate */ 12380Sstevel@tonic-gate for (ctrl = controls; *ctrl; ctrl++) { 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate if (strcmp((*ctrl)->ldctl_oid, 12414522Schinlong LDAP_CONTROL_PWEXPIRED) == 0) { 12420Sstevel@tonic-gate /* 12430Sstevel@tonic-gate * if the caller wants this bind 12440Sstevel@tonic-gate * to fail, set up the error info. 12450Sstevel@tonic-gate * If call to this function is 12460Sstevel@tonic-gate * for searching the LDAP directory, 12470Sstevel@tonic-gate * e.g., __ns_ldap_list(), 12480Sstevel@tonic-gate * there's really no sense to 12490Sstevel@tonic-gate * let a connection open and 12500Sstevel@tonic-gate * then fail immediately afterward 12510Sstevel@tonic-gate * on the LDAP search operation with 12520Sstevel@tonic-gate * the LDAP_UNWILLING_TO_PERFORM rc 12530Sstevel@tonic-gate */ 12540Sstevel@tonic-gate pwd_status = 12554522Schinlong NS_PASSWD_CHANGE_NEEDED; 12560Sstevel@tonic-gate if (fail_if_new_pwd_reqd) { 12570Sstevel@tonic-gate (void) snprintf(errstr, 12584522Schinlong sizeof (errstr), 12594522Schinlong gettext( 12604522Schinlong "openConnection: " 12614522Schinlong "%s bind " 12624522Schinlong "failed " 12634522Schinlong "- password " 12644522Schinlong "expired. It " 12654522Schinlong " needs to change " 12664522Schinlong "immediately!"), 12674522Schinlong bind_type); 12680Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 12694522Schinlong LDAP_SUCCESS, 12704522Schinlong strdup(errstr), 12714522Schinlong pwd_status, 12724522Schinlong 0, 12734522Schinlong NULL); 12740Sstevel@tonic-gate exit_rc = NS_LDAP_INTERNAL; 12750Sstevel@tonic-gate } else { 12760Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 12774522Schinlong LDAP_SUCCESS, 12784522Schinlong NULL, 12794522Schinlong pwd_status, 12804522Schinlong 0, 12814522Schinlong NULL); 12820Sstevel@tonic-gate exit_rc = 12834522Schinlong NS_LDAP_SUCCESS_WITH_INFO; 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate break; 12860Sstevel@tonic-gate } else if (strcmp((*ctrl)->ldctl_oid, 12874522Schinlong LDAP_CONTROL_PWEXPIRING) == 0) { 12880Sstevel@tonic-gate pwd_status = 12894522Schinlong NS_PASSWD_ABOUT_TO_EXPIRE; 12900Sstevel@tonic-gate if ((*ctrl)-> 12914522Schinlong ldctl_value.bv_len > 0 && 12924522Schinlong (*ctrl)-> 12934522Schinlong ldctl_value.bv_val) 12940Sstevel@tonic-gate sec_until_exp = 12954522Schinlong atoi((*ctrl)-> 12964522Schinlong ldctl_value.bv_val); 12970Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp, 12984522Schinlong LDAP_SUCCESS, 12994522Schinlong NULL, 13004522Schinlong pwd_status, 13014522Schinlong sec_until_exp, 13024522Schinlong NULL); 13030Sstevel@tonic-gate exit_rc = 13044522Schinlong NS_LDAP_SUCCESS_WITH_INFO; 13050Sstevel@tonic-gate break; 13060Sstevel@tonic-gate } 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate } 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate if (controls) 13110Sstevel@tonic-gate ldap_controls_free(controls); 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate return (exit_rc); 13140Sstevel@tonic-gate } 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate static int 13176842Sth160488 ldap_in_nss_switch(char *db) 13180Sstevel@tonic-gate { 13190Sstevel@tonic-gate enum __nsw_parse_err pserr; 13200Sstevel@tonic-gate struct __nsw_switchconfig *conf; 13210Sstevel@tonic-gate struct __nsw_lookup *lkp; 13220Sstevel@tonic-gate const char *name; 13230Sstevel@tonic-gate int found = 0; 13240Sstevel@tonic-gate 13256842Sth160488 conf = __nsw_getconfig(db, &pserr); 13260Sstevel@tonic-gate if (conf == NULL) { 13270Sstevel@tonic-gate return (-1); 13280Sstevel@tonic-gate } 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate /* check for skip and count other backends */ 13310Sstevel@tonic-gate for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 13320Sstevel@tonic-gate name = lkp->service_name; 13330Sstevel@tonic-gate if (strcmp(name, "ldap") == 0) { 13340Sstevel@tonic-gate found = 1; 13350Sstevel@tonic-gate break; 13360Sstevel@tonic-gate } 13370Sstevel@tonic-gate } 1338*11411SSurya.Prakki@Sun.COM (void) __nsw_freeconfig(conf); 13390Sstevel@tonic-gate return (found); 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate static int 13430Sstevel@tonic-gate openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, 13440Sstevel@tonic-gate int timeoutSec, ns_ldap_error_t **errorp, 13456842Sth160488 int fail_if_new_pwd_reqd, int passwd_mgmt, 13466842Sth160488 ns_conn_user_t *conn_user) 13470Sstevel@tonic-gate { 13486842Sth160488 LDAP *ld = NULL; 13496842Sth160488 int ldapVersion = LDAP_VERSION3; 13506842Sth160488 int derefOption = LDAP_DEREF_ALWAYS; 13516842Sth160488 int zero = 0; 13526842Sth160488 int timeoutMilliSec = timeoutSec * 1000; 13536842Sth160488 uint16_t port = USE_DEFAULT_PORT; 13546842Sth160488 char *s; 13556842Sth160488 char errstr[MAXERROR]; 13566842Sth160488 13576842Sth160488 ns_ldap_return_code ret_code = NS_LDAP_SUCCESS; 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate *errorp = NULL; 13600Sstevel@tonic-gate *ldp = NULL; 13610Sstevel@tonic-gate 13626842Sth160488 /* determine if the host name contains a port number */ 13636842Sth160488 s = strchr(serverAddr, ']'); /* skip over ipv6 addr */ 13646842Sth160488 s = strchr(s != NULL ? s : serverAddr, ':'); 13656842Sth160488 if (s != NULL) { 13666842Sth160488 if (sscanf(s + 1, "%hu", &port) != 1) { 13676842Sth160488 (void) snprintf(errstr, 13686842Sth160488 sizeof (errstr), 13696842Sth160488 gettext("openConnection: cannot " 13706842Sth160488 "convert %s into a valid " 13716842Sth160488 "port number for the " 13726842Sth160488 "%s server. A default value " 13736842Sth160488 "will be used."), 13746842Sth160488 s, 13756842Sth160488 serverAddr); 13760Sstevel@tonic-gate syslog(LOG_ERR, "libsldap: %s", errstr); 13770Sstevel@tonic-gate } else { 13786842Sth160488 *s = '\0'; 13790Sstevel@tonic-gate } 13800Sstevel@tonic-gate } 13810Sstevel@tonic-gate 13826842Sth160488 ret_code = createSession(auth, 13836842Sth160488 serverAddr, 13846842Sth160488 port, 13856842Sth160488 timeoutMilliSec, 13866842Sth160488 &ld, 13876842Sth160488 errorp); 13886842Sth160488 if (s != NULL) { 13896842Sth160488 *s = ':'; 13906842Sth160488 } 13916842Sth160488 if (ret_code != NS_LDAP_SUCCESS) { 13926842Sth160488 return (ret_code); 13936842Sth160488 } 13946842Sth160488 13956842Sth160488 /* check to see if the underlying libsldap supports MT connection */ 13966842Sth160488 if (conn_user != NULL) { 13976842Sth160488 int rc; 13986842Sth160488 13996842Sth160488 rc = __s_api_check_libldap_MT_conn_support(conn_user, ld, 14006842Sth160488 errorp); 14016842Sth160488 if (rc != NS_LDAP_SUCCESS) { 14026842Sth160488 (void) ldap_unbind(ld); 14036842Sth160488 return (rc); 14046842Sth160488 } 14056842Sth160488 } 14066842Sth160488 14070Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); 14080Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 14090Sstevel@tonic-gate /* 14100Sstevel@tonic-gate * set LDAP_OPT_REFERRALS to OFF. 14110Sstevel@tonic-gate * This library will handle the referral itself 14120Sstevel@tonic-gate * based on API flags or configuration file 14130Sstevel@tonic-gate * specification. If this option is not set 14140Sstevel@tonic-gate * to OFF, libldap will never pass the 14150Sstevel@tonic-gate * referral info up to this library 14160Sstevel@tonic-gate */ 14170Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 14180Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 14190Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 14200Sstevel@tonic-gate /* setup TCP/IP connect timeout */ 14210Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 14224522Schinlong &timeoutMilliSec); 14230Sstevel@tonic-gate /* retry if LDAP I/O was interrupted */ 14240Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 14250Sstevel@tonic-gate 14266842Sth160488 ret_code = performBind(auth, 14276842Sth160488 ld, 14286842Sth160488 timeoutSec, 14296842Sth160488 errorp, 14306842Sth160488 fail_if_new_pwd_reqd, 14316842Sth160488 passwd_mgmt); 14320Sstevel@tonic-gate 14336842Sth160488 if (ret_code == NS_LDAP_SUCCESS || 14346842Sth160488 ret_code == NS_LDAP_SUCCESS_WITH_INFO) { 14356842Sth160488 *ldp = ld; 14360Sstevel@tonic-gate } 14370Sstevel@tonic-gate 14386842Sth160488 return (ret_code); 14390Sstevel@tonic-gate } 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate /* 14420Sstevel@tonic-gate * FUNCTION: __s_api_getDefaultAuth 14430Sstevel@tonic-gate * 14440Sstevel@tonic-gate * Constructs a credential for authentication using the config module. 14450Sstevel@tonic-gate * 14460Sstevel@tonic-gate * RETURN VALUES: 14470Sstevel@tonic-gate * 14480Sstevel@tonic-gate * NS_LDAP_SUCCESS If successful 14490Sstevel@tonic-gate * NS_LDAP_CONFIG If there are any config errors. 14500Sstevel@tonic-gate * NS_LDAP_MEMORY Memory errors. 14510Sstevel@tonic-gate * NS_LDAP_OP_FAILED If there are no more authentication methods so can 14520Sstevel@tonic-gate * not build a new authp. 14530Sstevel@tonic-gate * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the 14540Sstevel@tonic-gate * necessary fields of a cred for a given auth method 14550Sstevel@tonic-gate * are not provided. 14560Sstevel@tonic-gate * INPUT: 14570Sstevel@tonic-gate * 14580Sstevel@tonic-gate * cLevel Currently requested credential level to be tried 14590Sstevel@tonic-gate * 14600Sstevel@tonic-gate * aMethod Currently requested authentication method to be tried 14610Sstevel@tonic-gate * 14629576SJulian.Pullen@Sun.COM * getAdmin If non 0, get Admin -i.e., not proxyAgent- DN and password 14639576SJulian.Pullen@Sun.COM * 14640Sstevel@tonic-gate * OUTPUT: 14650Sstevel@tonic-gate * 14660Sstevel@tonic-gate * authp authentication method to use. 14670Sstevel@tonic-gate */ 14680Sstevel@tonic-gate static int 14690Sstevel@tonic-gate __s_api_getDefaultAuth( 14700Sstevel@tonic-gate int *cLevel, 14710Sstevel@tonic-gate ns_auth_t *aMethod, 14729576SJulian.Pullen@Sun.COM ns_cred_t **authp, 14739576SJulian.Pullen@Sun.COM int getAdmin) 14740Sstevel@tonic-gate { 14750Sstevel@tonic-gate void **paramVal = NULL; 14760Sstevel@tonic-gate char *modparamVal = NULL; 14770Sstevel@tonic-gate int getUid = 0; 14780Sstevel@tonic-gate int getPasswd = 0; 14790Sstevel@tonic-gate int getCertpath = 0; 14800Sstevel@tonic-gate int rc = 0; 14810Sstevel@tonic-gate ns_ldap_error_t *errorp = NULL; 14829576SJulian.Pullen@Sun.COM UnixCred_t *AdminCred = NULL; 14830Sstevel@tonic-gate 14840Sstevel@tonic-gate #ifdef DEBUG 14850Sstevel@tonic-gate (void) fprintf(stderr, "__s_api_getDefaultAuth START\n"); 14860Sstevel@tonic-gate #endif 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate if (aMethod == NULL) { 14890Sstevel@tonic-gate /* Require an Auth */ 14900Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate } 14930Sstevel@tonic-gate /* 14942830Sdjl * credential level "self" can work with auth method sasl/GSSAPI only 14950Sstevel@tonic-gate */ 14962830Sdjl if (cLevel && *cLevel == NS_LDAP_CRED_SELF && 14974522Schinlong aMethod->saslmech != NS_LDAP_SASL_GSSAPI) 14980Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); 15010Sstevel@tonic-gate if ((*authp) == NULL) 15020Sstevel@tonic-gate return (NS_LDAP_MEMORY); 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate (*authp)->auth = *aMethod; 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate switch (aMethod->type) { 15070Sstevel@tonic-gate case NS_LDAP_AUTH_NONE: 15080Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 15090Sstevel@tonic-gate case NS_LDAP_AUTH_SIMPLE: 15100Sstevel@tonic-gate getUid++; 15110Sstevel@tonic-gate getPasswd++; 15120Sstevel@tonic-gate break; 15130Sstevel@tonic-gate case NS_LDAP_AUTH_SASL: 15140Sstevel@tonic-gate if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 15150Sstevel@tonic-gate (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) { 15160Sstevel@tonic-gate getUid++; 15170Sstevel@tonic-gate getPasswd++; 15182830Sdjl } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) { 15190Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 15200Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate break; 15230Sstevel@tonic-gate case NS_LDAP_AUTH_TLS: 15240Sstevel@tonic-gate if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) || 15250Sstevel@tonic-gate ((aMethod->tlstype == NS_LDAP_TLS_SASL) && 15260Sstevel@tonic-gate ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 15270Sstevel@tonic-gate (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) { 15280Sstevel@tonic-gate getUid++; 15290Sstevel@tonic-gate getPasswd++; 15300Sstevel@tonic-gate getCertpath++; 15310Sstevel@tonic-gate } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) { 15320Sstevel@tonic-gate getCertpath++; 15330Sstevel@tonic-gate } else { 15340Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 15350Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 15360Sstevel@tonic-gate } 15370Sstevel@tonic-gate break; 15380Sstevel@tonic-gate } 15390Sstevel@tonic-gate 15400Sstevel@tonic-gate if (getUid) { 15410Sstevel@tonic-gate paramVal = NULL; 15429576SJulian.Pullen@Sun.COM if (getAdmin) { 15439576SJulian.Pullen@Sun.COM /* 15449576SJulian.Pullen@Sun.COM * Assume AdminCred has been retrieved from 15459576SJulian.Pullen@Sun.COM * ldap_cachemgr already. It will not work 15469576SJulian.Pullen@Sun.COM * without userID or password. Flags getUid 15479576SJulian.Pullen@Sun.COM * and getPasswd should always be set 15489576SJulian.Pullen@Sun.COM * together. 15499576SJulian.Pullen@Sun.COM */ 15509576SJulian.Pullen@Sun.COM AdminCred = calloc(1, sizeof (UnixCred_t)); 15519576SJulian.Pullen@Sun.COM if (AdminCred == NULL) { 15529576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp); 15539576SJulian.Pullen@Sun.COM return (NS_LDAP_MEMORY); 15549576SJulian.Pullen@Sun.COM } 15559576SJulian.Pullen@Sun.COM 15569576SJulian.Pullen@Sun.COM rc = requestAdminCred(&AdminCred, &errorp); 15579576SJulian.Pullen@Sun.COM if (rc != NS_LDAP_SUCCESS) { 15589576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp); 15599576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 15609576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeError(&errorp); 15619576SJulian.Pullen@Sun.COM return (rc); 15629576SJulian.Pullen@Sun.COM } 15630Sstevel@tonic-gate 15649576SJulian.Pullen@Sun.COM if (AdminCred->userID == NULL) { 15659576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp); 15669576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 15679576SJulian.Pullen@Sun.COM return (NS_LDAP_INVALID_PARAM); 15689576SJulian.Pullen@Sun.COM } 15699576SJulian.Pullen@Sun.COM (*authp)->cred.unix_cred.userID = AdminCred->userID; 15709576SJulian.Pullen@Sun.COM AdminCred->userID = NULL; 15719576SJulian.Pullen@Sun.COM } else { 15729576SJulian.Pullen@Sun.COM rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, 15739576SJulian.Pullen@Sun.COM ¶mVal, &errorp); 15749576SJulian.Pullen@Sun.COM if (rc != NS_LDAP_SUCCESS) { 15759576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp); 15769576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeError(&errorp); 15779576SJulian.Pullen@Sun.COM return (rc); 15789576SJulian.Pullen@Sun.COM } 15799576SJulian.Pullen@Sun.COM 15809576SJulian.Pullen@Sun.COM if (paramVal == NULL || *paramVal == NULL) { 15819576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp); 15829576SJulian.Pullen@Sun.COM return (NS_LDAP_INVALID_PARAM); 15839576SJulian.Pullen@Sun.COM } 15849576SJulian.Pullen@Sun.COM 15859576SJulian.Pullen@Sun.COM (*authp)->cred.unix_cred.userID = 15869576SJulian.Pullen@Sun.COM strdup((char *)*paramVal); 15879576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeParam(¶mVal); 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate if ((*authp)->cred.unix_cred.userID == NULL) { 15900Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 15919576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 15920Sstevel@tonic-gate return (NS_LDAP_MEMORY); 15930Sstevel@tonic-gate } 15940Sstevel@tonic-gate } 15950Sstevel@tonic-gate if (getPasswd) { 15960Sstevel@tonic-gate paramVal = NULL; 15979576SJulian.Pullen@Sun.COM if (getAdmin) { 15989576SJulian.Pullen@Sun.COM /* 15999576SJulian.Pullen@Sun.COM * Assume AdminCred has been retrieved from 16009576SJulian.Pullen@Sun.COM * ldap_cachemgr already. It will not work 16019576SJulian.Pullen@Sun.COM * without the userID anyway because for 16029576SJulian.Pullen@Sun.COM * getting admin credential, flags getUid 16039576SJulian.Pullen@Sun.COM * and getPasswd should always be set 16049576SJulian.Pullen@Sun.COM * together. 16059576SJulian.Pullen@Sun.COM */ 16069576SJulian.Pullen@Sun.COM if (AdminCred == NULL || AdminCred->passwd == NULL) { 16079576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp); 16089576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 16099576SJulian.Pullen@Sun.COM return (NS_LDAP_INVALID_PARAM); 16109576SJulian.Pullen@Sun.COM } 16119576SJulian.Pullen@Sun.COM modparamVal = dvalue(AdminCred->passwd); 16129576SJulian.Pullen@Sun.COM } else { 16139576SJulian.Pullen@Sun.COM rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, 16149576SJulian.Pullen@Sun.COM ¶mVal, &errorp); 16159576SJulian.Pullen@Sun.COM if (rc != NS_LDAP_SUCCESS) { 16169576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp); 16179576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeError(&errorp); 16189576SJulian.Pullen@Sun.COM return (rc); 16199576SJulian.Pullen@Sun.COM } 16209576SJulian.Pullen@Sun.COM 16219576SJulian.Pullen@Sun.COM if (paramVal == NULL || *paramVal == NULL) { 16229576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp); 16239576SJulian.Pullen@Sun.COM return (NS_LDAP_INVALID_PARAM); 16249576SJulian.Pullen@Sun.COM } 16259576SJulian.Pullen@Sun.COM 16269576SJulian.Pullen@Sun.COM modparamVal = dvalue((char *)*paramVal); 16279576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeParam(¶mVal); 16280Sstevel@tonic-gate } 16290Sstevel@tonic-gate 16300Sstevel@tonic-gate if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) { 16310Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 16329576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 16330Sstevel@tonic-gate if (modparamVal != NULL) 16340Sstevel@tonic-gate free(modparamVal); 16350Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 16360Sstevel@tonic-gate } 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate (*authp)->cred.unix_cred.passwd = modparamVal; 16390Sstevel@tonic-gate } 16400Sstevel@tonic-gate if (getCertpath) { 16410Sstevel@tonic-gate paramVal = NULL; 16420Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 16434522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 16440Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 16459576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 16460Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 16470Sstevel@tonic-gate *authp = NULL; 16480Sstevel@tonic-gate return (rc); 16490Sstevel@tonic-gate } 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate if (paramVal == NULL || *paramVal == NULL) { 16520Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 16539576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 16540Sstevel@tonic-gate *authp = NULL; 16550Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 16560Sstevel@tonic-gate } 16570Sstevel@tonic-gate 16580Sstevel@tonic-gate (*authp)->hostcertpath = strdup((char *)*paramVal); 16590Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 16600Sstevel@tonic-gate if ((*authp)->hostcertpath == NULL) { 16610Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp); 16629576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 16630Sstevel@tonic-gate *authp = NULL; 16640Sstevel@tonic-gate return (NS_LDAP_MEMORY); 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate } 16679576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred); 16680Sstevel@tonic-gate return (NS_LDAP_SUCCESS); 16690Sstevel@tonic-gate } 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate /* 16726842Sth160488 * FUNCTION: getConnection 16730Sstevel@tonic-gate * 16746842Sth160488 * internal version of __s_api_getConnection() 16750Sstevel@tonic-gate */ 16766842Sth160488 static int 16776842Sth160488 getConnection( 16780Sstevel@tonic-gate const char *server, 16790Sstevel@tonic-gate const int flags, 16800Sstevel@tonic-gate const ns_cred_t *cred, /* credentials for bind */ 16810Sstevel@tonic-gate ConnectionID *sessionId, 16820Sstevel@tonic-gate Connection **session, 16830Sstevel@tonic-gate ns_ldap_error_t **errorp, 16841179Svv149972 int fail_if_new_pwd_reqd, 16856842Sth160488 int nopasswd_acct_mgmt, 16866842Sth160488 ns_conn_user_t *conn_user) 16870Sstevel@tonic-gate { 16880Sstevel@tonic-gate char errmsg[MAXERROR]; 16890Sstevel@tonic-gate ns_auth_t **aMethod = NULL; 16900Sstevel@tonic-gate ns_auth_t **aNext = NULL; 16910Sstevel@tonic-gate int **cLevel = NULL; 16920Sstevel@tonic-gate int **cNext = NULL; 16930Sstevel@tonic-gate int timeoutSec = NS_DEFAULT_BIND_TIMEOUT; 16940Sstevel@tonic-gate int rc; 16950Sstevel@tonic-gate Connection *con = NULL; 16960Sstevel@tonic-gate int sec = 1; 16970Sstevel@tonic-gate ns_cred_t *authp = NULL; 16980Sstevel@tonic-gate ns_cred_t anon; 16992830Sdjl int version = NS_LDAP_V2, self_gssapi_only = 0; 17000Sstevel@tonic-gate void **paramVal = NULL; 17011687Sjanga char **badSrvrs = NULL; /* List of problem hostnames */ 17020Sstevel@tonic-gate 17030Sstevel@tonic-gate if ((session == NULL) || (sessionId == NULL)) { 17040Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM); 17050Sstevel@tonic-gate } 17060Sstevel@tonic-gate *session = NULL; 17070Sstevel@tonic-gate 17086842Sth160488 /* reuse MT connection if needed and if available */ 17096842Sth160488 if (conn_user != NULL) { 17106842Sth160488 rc = __s_api_conn_mt_get(server, flags, cred, session, errorp, 17116842Sth160488 conn_user); 17126842Sth160488 if (rc != NS_LDAP_NOTFOUND) 17136842Sth160488 return (rc); 17140Sstevel@tonic-gate } 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate /* get profile version number */ 17170Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, 17184522Schinlong ¶mVal, errorp)) != NS_LDAP_SUCCESS) 17190Sstevel@tonic-gate return (rc); 17200Sstevel@tonic-gate if (paramVal == NULL) { 17210Sstevel@tonic-gate (void) sprintf(errmsg, gettext("getConnection: no file " 17224522Schinlong "version")); 17230Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg), 17244522Schinlong NS_LDAP_CONFIG); 17250Sstevel@tonic-gate return (NS_LDAP_CONFIG); 17260Sstevel@tonic-gate } 17270Sstevel@tonic-gate if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0) 17280Sstevel@tonic-gate version = NS_LDAP_V1; 17290Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)¶mVal); 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate /* Get the bind timeout value */ 17320Sstevel@tonic-gate (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp); 17330Sstevel@tonic-gate if (paramVal != NULL && *paramVal != NULL) { 17340Sstevel@tonic-gate timeoutSec = **((int **)paramVal); 17350Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal); 17360Sstevel@tonic-gate } 17370Sstevel@tonic-gate if (*errorp) 17380Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp); 17390Sstevel@tonic-gate 17400Sstevel@tonic-gate if (cred == NULL) { 17410Sstevel@tonic-gate /* Get the authentication method list */ 17420Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, 17434522Schinlong (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS) 17440Sstevel@tonic-gate return (rc); 17450Sstevel@tonic-gate if (aMethod == NULL) { 17460Sstevel@tonic-gate aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *)); 17470Sstevel@tonic-gate if (aMethod == NULL) 17480Sstevel@tonic-gate return (NS_LDAP_MEMORY); 17490Sstevel@tonic-gate aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t)); 17500Sstevel@tonic-gate if (aMethod[0] == NULL) { 17510Sstevel@tonic-gate free(aMethod); 17520Sstevel@tonic-gate return (NS_LDAP_MEMORY); 17530Sstevel@tonic-gate } 17540Sstevel@tonic-gate if (version == NS_LDAP_V1) 17550Sstevel@tonic-gate (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE; 17560Sstevel@tonic-gate else { 17570Sstevel@tonic-gate (aMethod[0])->type = NS_LDAP_AUTH_SASL; 17580Sstevel@tonic-gate (aMethod[0])->saslmech = 17594522Schinlong NS_LDAP_SASL_DIGEST_MD5; 17600Sstevel@tonic-gate (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE; 17610Sstevel@tonic-gate } 17620Sstevel@tonic-gate } 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate /* Get the credential level list */ 17650Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P, 17664522Schinlong (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) { 17670Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&aMethod); 17680Sstevel@tonic-gate return (rc); 17690Sstevel@tonic-gate } 17700Sstevel@tonic-gate if (cLevel == NULL) { 17710Sstevel@tonic-gate cLevel = (int **)calloc(2, sizeof (int *)); 17720Sstevel@tonic-gate if (cLevel == NULL) 17730Sstevel@tonic-gate return (NS_LDAP_MEMORY); 17740Sstevel@tonic-gate cLevel[0] = (int *)calloc(1, sizeof (int)); 17750Sstevel@tonic-gate if (cLevel[0] == NULL) 17760Sstevel@tonic-gate return (NS_LDAP_MEMORY); 17770Sstevel@tonic-gate if (version == NS_LDAP_V1) 17780Sstevel@tonic-gate *(cLevel[0]) = NS_LDAP_CRED_PROXY; 17790Sstevel@tonic-gate else 17800Sstevel@tonic-gate *(cLevel[0]) = NS_LDAP_CRED_ANON; 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate } 17830Sstevel@tonic-gate 17840Sstevel@tonic-gate /* setup the anon credential for anonymous connection */ 17850Sstevel@tonic-gate (void) memset(&anon, 0, sizeof (ns_cred_t)); 17860Sstevel@tonic-gate anon.auth.type = NS_LDAP_AUTH_NONE; 17870Sstevel@tonic-gate 17886812Sraf for (;;) { 17890Sstevel@tonic-gate if (cred != NULL) { 17900Sstevel@tonic-gate /* using specified auth method */ 17910Sstevel@tonic-gate rc = makeConnection(&con, server, cred, 17924522Schinlong sessionId, timeoutSec, errorp, 17934522Schinlong fail_if_new_pwd_reqd, 17946842Sth160488 nopasswd_acct_mgmt, flags, &badSrvrs, conn_user); 17954387Smj162486 /* not using bad server if credentials were supplied */ 17964387Smj162486 if (badSrvrs && *badSrvrs) { 17974387Smj162486 __s_api_free2dArray(badSrvrs); 17984387Smj162486 badSrvrs = NULL; 17994387Smj162486 } 18000Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 18014522Schinlong rc == NS_LDAP_SUCCESS_WITH_INFO) { 18020Sstevel@tonic-gate *session = con; 18030Sstevel@tonic-gate break; 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate } else { 18062830Sdjl self_gssapi_only = __s_api_self_gssapi_only_get(); 18070Sstevel@tonic-gate /* for every cred level */ 18080Sstevel@tonic-gate for (cNext = cLevel; *cNext != NULL; cNext++) { 18092830Sdjl if (self_gssapi_only && 18104522Schinlong **cNext != NS_LDAP_CRED_SELF) 18112830Sdjl continue; 18120Sstevel@tonic-gate if (**cNext == NS_LDAP_CRED_ANON) { 18131687Sjanga /* 18141687Sjanga * make connection anonymously 18151687Sjanga * Free the down server list before 18161687Sjanga * looping through 18171687Sjanga */ 18181687Sjanga if (badSrvrs && *badSrvrs) { 18191687Sjanga __s_api_free2dArray(badSrvrs); 18201687Sjanga badSrvrs = NULL; 18211687Sjanga } 18220Sstevel@tonic-gate rc = makeConnection(&con, server, &anon, 18234522Schinlong sessionId, timeoutSec, errorp, 18244522Schinlong fail_if_new_pwd_reqd, 18254522Schinlong nopasswd_acct_mgmt, flags, 18266842Sth160488 &badSrvrs, conn_user); 18270Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 18284522Schinlong rc == 18294522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 18300Sstevel@tonic-gate *session = con; 18310Sstevel@tonic-gate goto done; 18320Sstevel@tonic-gate } 18330Sstevel@tonic-gate continue; 18340Sstevel@tonic-gate } 18350Sstevel@tonic-gate /* for each cred level */ 18360Sstevel@tonic-gate for (aNext = aMethod; *aNext != NULL; aNext++) { 18372830Sdjl if (self_gssapi_only && 18384522Schinlong (*aNext)->saslmech != 18394522Schinlong NS_LDAP_SASL_GSSAPI) 18402830Sdjl continue; 18412830Sdjl /* 18422830Sdjl * self coexists with sasl/GSSAPI only 18432830Sdjl * and non-self coexists with non-gssapi 18442830Sdjl * only 18452830Sdjl */ 18462830Sdjl if ((**cNext == NS_LDAP_CRED_SELF && 18474522Schinlong (*aNext)->saslmech != 18484522Schinlong NS_LDAP_SASL_GSSAPI) || 18494522Schinlong (**cNext != NS_LDAP_CRED_SELF && 18504522Schinlong (*aNext)->saslmech == 18514522Schinlong NS_LDAP_SASL_GSSAPI)) 18522830Sdjl continue; 18530Sstevel@tonic-gate /* make connection and authenticate */ 18540Sstevel@tonic-gate /* with default credentials */ 18550Sstevel@tonic-gate authp = NULL; 18560Sstevel@tonic-gate rc = __s_api_getDefaultAuth(*cNext, 18579576SJulian.Pullen@Sun.COM *aNext, &authp, 18589576SJulian.Pullen@Sun.COM flags & NS_LDAP_READ_SHADOW); 18590Sstevel@tonic-gate if (rc != NS_LDAP_SUCCESS) { 18600Sstevel@tonic-gate continue; 18610Sstevel@tonic-gate } 18621687Sjanga /* 18631687Sjanga * Free the down server list before 18641687Sjanga * looping through 18651687Sjanga */ 18661687Sjanga if (badSrvrs && *badSrvrs) { 18671687Sjanga __s_api_free2dArray(badSrvrs); 18681687Sjanga badSrvrs = NULL; 18691687Sjanga } 18700Sstevel@tonic-gate rc = makeConnection(&con, server, authp, 18714522Schinlong sessionId, timeoutSec, errorp, 18724522Schinlong fail_if_new_pwd_reqd, 18734522Schinlong nopasswd_acct_mgmt, flags, 18746842Sth160488 &badSrvrs, conn_user); 18750Sstevel@tonic-gate (void) __ns_ldap_freeCred(&authp); 18760Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || 18774522Schinlong rc == 18784522Schinlong NS_LDAP_SUCCESS_WITH_INFO) { 18790Sstevel@tonic-gate *session = con; 18800Sstevel@tonic-gate goto done; 18810Sstevel@tonic-gate } 18820Sstevel@tonic-gate } 18830Sstevel@tonic-gate } 18840Sstevel@tonic-gate } 18850Sstevel@tonic-gate if (flags & NS_LDAP_HARD) { 18860Sstevel@tonic-gate if (sec < LDAPMAXHARDLOOKUPTIME) 18870Sstevel@tonic-gate sec *= 2; 18886812Sraf (void) sleep(sec); 18890Sstevel@tonic-gate } else { 18900Sstevel@tonic-gate break; 18910Sstevel@tonic-gate } 18920Sstevel@tonic-gate } 18930Sstevel@tonic-gate 18940Sstevel@tonic-gate done: 18952830Sdjl if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) { 18962830Sdjl /* 18972830Sdjl * self_gssapi_only is true but no self/sasl/gssapi is 18982830Sdjl * configured 18992830Sdjl */ 19002830Sdjl rc = NS_LDAP_CONFIG; 19012830Sdjl } 19022830Sdjl 19030Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&aMethod); 19040Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&cLevel); 19051687Sjanga 19061687Sjanga if (badSrvrs && *badSrvrs) { 19071687Sjanga /* 19081687Sjanga * At this point, either we have a successful 19091687Sjanga * connection or exhausted all the possible auths. 19101687Sjanga * and creds. Mark the problem servers as down 19111687Sjanga * so that the problem servers are not contacted 19121687Sjanga * again until the refresh_ttl expires. 19131687Sjanga */ 19141687Sjanga (void) __s_api_removeBadServers(badSrvrs); 19151687Sjanga __s_api_free2dArray(badSrvrs); 19161687Sjanga } 19170Sstevel@tonic-gate return (rc); 19180Sstevel@tonic-gate } 19190Sstevel@tonic-gate 19206842Sth160488 /* 19216842Sth160488 * FUNCTION: __s_api_getConnection 19226842Sth160488 * 19236842Sth160488 * Bind to the specified server or one from the server 19246842Sth160488 * list and return the pointer. 19256842Sth160488 * 19266842Sth160488 * This function can rebind or not (NS_LDAP_HARD), it can require a 19276842Sth160488 * credential or bind anonymously 19286842Sth160488 * 19296842Sth160488 * This function follows the DUA configuration schema algorithm 19306842Sth160488 * 19316842Sth160488 * RETURN VALUES: 19326842Sth160488 * 19336842Sth160488 * NS_LDAP_SUCCESS A connection was made successfully. 19346842Sth160488 * NS_LDAP_SUCCESS_WITH_INFO 19356842Sth160488 * A connection was made successfully, but with 19366842Sth160488 * password management info in *errorp 19376842Sth160488 * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function. 19386842Sth160488 * NS_LDAP_CONFIG If there are any config errors. 19396842Sth160488 * NS_LDAP_MEMORY Memory errors. 19406842Sth160488 * NS_LDAP_INTERNAL If there was a ldap error. 19416842Sth160488 * 19426842Sth160488 * INPUT: 19436842Sth160488 * 19446842Sth160488 * server Bind to this LDAP server only 19456842Sth160488 * flags If NS_LDAP_HARD is set function will not return until it has 19466842Sth160488 * a connection unless there is a authentication problem. 19476842Sth160488 * If NS_LDAP_NEW_CONN is set the function must force a new 19486842Sth160488 * connection to be created 19496842Sth160488 * If NS_LDAP_KEEP_CONN is set the connection is to be kept open 19506842Sth160488 * auth Credentials for bind. This could be NULL in which case 19516842Sth160488 * a default cred built from the config module is used. 19526842Sth160488 * sessionId cookie that points to a previous session 19536842Sth160488 * fail_if_new_pwd_reqd 19546842Sth160488 * a flag indicating this function should fail if the passwd 19556842Sth160488 * in auth needs to change immediately 19566842Sth160488 * nopasswd_acct_mgmt 19576842Sth160488 * a flag indicating that makeConnection should check before 19586842Sth160488 * binding if server supports LDAP V3 password less 19596842Sth160488 * account management 19606842Sth160488 * 19616842Sth160488 * OUTPUT: 19626842Sth160488 * 19636842Sth160488 * session pointer to a session with connection information 19646842Sth160488 * errorp Set if there are any INTERNAL, or CONFIG error. 19656842Sth160488 */ 19666842Sth160488 int 19676842Sth160488 __s_api_getConnection( 19686842Sth160488 const char *server, 19696842Sth160488 const int flags, 19706842Sth160488 const ns_cred_t *cred, /* credentials for bind */ 19716842Sth160488 ConnectionID *sessionId, 19726842Sth160488 Connection **session, 19736842Sth160488 ns_ldap_error_t **errorp, 19746842Sth160488 int fail_if_new_pwd_reqd, 19756842Sth160488 int nopasswd_acct_mgmt, 19766842Sth160488 ns_conn_user_t *conn_user) 19776842Sth160488 { 19786842Sth160488 int rc; 19796842Sth160488 19806842Sth160488 rc = getConnection(server, flags, cred, sessionId, session, 19816842Sth160488 errorp, fail_if_new_pwd_reqd, nopasswd_acct_mgmt, 19826842Sth160488 conn_user); 19836842Sth160488 19846842Sth160488 if (rc != NS_LDAP_SUCCESS && rc != NS_LDAP_SUCCESS_WITH_INFO) { 19856842Sth160488 if (conn_user != NULL && conn_user->conn_mt != NULL) 19866842Sth160488 __s_api_conn_mt_remove(conn_user, rc, errorp); 19876842Sth160488 } 19886842Sth160488 19896842Sth160488 return (rc); 19906842Sth160488 } 19916842Sth160488 19926842Sth160488 void 19936842Sth160488 __s_api_free_sessionPool() 19940Sstevel@tonic-gate { 19950Sstevel@tonic-gate int id; 19960Sstevel@tonic-gate 19976842Sth160488 (void) mutex_lock(&sessionPoolLock); 19986842Sth160488 19990Sstevel@tonic-gate if (sessionPool != NULL) { 20000Sstevel@tonic-gate for (id = 0; id < sessionPoolSize; id++) 20010Sstevel@tonic-gate _DropConnection(id + CONID_OFFSET, 0, 1); 20020Sstevel@tonic-gate free(sessionPool); 20030Sstevel@tonic-gate sessionPool = NULL; 20040Sstevel@tonic-gate sessionPoolSize = 0; 20050Sstevel@tonic-gate } 20066842Sth160488 (void) mutex_unlock(&sessionPoolLock); 20076842Sth160488 } 20086842Sth160488 20096842Sth160488 /* 20106842Sth160488 * This function initializes a TLS LDAP session. On success LDAP* is returned 20116842Sth160488 * (pointed by *ldp). Otherwise, the function returns an NS error code and 20126842Sth160488 * provide an additional info pointed by *errorp. 20136842Sth160488 */ 20146842Sth160488 static 20156842Sth160488 ns_ldap_return_code 20166842Sth160488 createTLSSession(const ns_cred_t *auth, const char *serverAddr, 20176842Sth160488 uint16_t port, int timeoutMilliSec, 20186842Sth160488 LDAP **ldp, ns_ldap_error_t **errorp) 20196842Sth160488 { 20206842Sth160488 const char *hostcertpath; 20216842Sth160488 char *alloc_hcp = NULL, errstr[MAXERROR]; 20226842Sth160488 int ldap_rc; 20236842Sth160488 20246842Sth160488 #ifdef DEBUG 20256842Sth160488 (void) fprintf(stderr, "tid= %d: +++TLS transport\n", 20266842Sth160488 thr_self()); 20276842Sth160488 #endif /* DEBUG */ 20286842Sth160488 20296842Sth160488 if (prldap_set_session_option(NULL, NULL, 20306842Sth160488 PRLDAP_OPT_IO_MAX_TIMEOUT, 20316842Sth160488 timeoutMilliSec) != LDAP_SUCCESS) { 20326842Sth160488 (void) snprintf(errstr, sizeof (errstr), 20336842Sth160488 gettext("createTLSSession: failed to initialize " 20346842Sth160488 "TLS security")); 20356842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 20366842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 20376842Sth160488 return (NS_LDAP_INTERNAL); 20386842Sth160488 } 20396842Sth160488 20406842Sth160488 hostcertpath = auth->hostcertpath; 20416842Sth160488 if (hostcertpath == NULL) { 20426842Sth160488 alloc_hcp = __s_get_hostcertpath(); 20436842Sth160488 hostcertpath = alloc_hcp; 20446842Sth160488 } 20456842Sth160488 20466842Sth160488 if (hostcertpath == NULL) 20476842Sth160488 return (NS_LDAP_MEMORY); 20486842Sth160488 20496842Sth160488 if ((ldap_rc = ldapssl_client_init(hostcertpath, NULL)) < 0) { 20506842Sth160488 if (alloc_hcp != NULL) { 20516842Sth160488 free(alloc_hcp); 20526842Sth160488 } 20536842Sth160488 (void) snprintf(errstr, sizeof (errstr), 20546842Sth160488 gettext("createTLSSession: failed to initialize " 20556842Sth160488 "TLS security (%s)"), 20566842Sth160488 ldapssl_err2string(ldap_rc)); 20576842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 20586842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 20596842Sth160488 return (NS_LDAP_INTERNAL); 20606842Sth160488 } 20616842Sth160488 if (alloc_hcp) 20626842Sth160488 free(alloc_hcp); 20636842Sth160488 20646842Sth160488 *ldp = ldapssl_init(serverAddr, port, 1); 20656842Sth160488 20666842Sth160488 if (*ldp == NULL || 20676842Sth160488 ldapssl_install_gethostbyaddr(*ldp, "ldap") != 0) { 20686842Sth160488 (void) snprintf(errstr, sizeof (errstr), 20696842Sth160488 gettext("createTLSSession: failed to connect " 20706842Sth160488 "using TLS (%s)"), strerror(errno)); 20716842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 20726842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 20736842Sth160488 return (NS_LDAP_INTERNAL); 20746842Sth160488 } 20756842Sth160488 20766842Sth160488 return (NS_LDAP_SUCCESS); 20776842Sth160488 } 20786842Sth160488 20796842Sth160488 /* 20806842Sth160488 * Convert (resolve) hostname to IP address. 20816842Sth160488 * 20826842Sth160488 * INPUT: 20836842Sth160488 * 20846842Sth160488 * server - \[IPv6_address\][:port] 20856842Sth160488 * - IPv4_address[:port] 20866842Sth160488 * - hostname[:port] 20876842Sth160488 * 20886842Sth160488 * newaddr - Buffer to which this function writes resulting address, 20896842Sth160488 * including the port number, if specified in server argument. 20906842Sth160488 * 20916842Sth160488 * newaddr_size - Size of the newaddr buffer. 20926842Sth160488 * 20936842Sth160488 * errstr - Buffer to which error string is written if error occurs. 20946842Sth160488 * 20956842Sth160488 * errstr_size - Size of the errstr buffer. 20966842Sth160488 * 20976842Sth160488 * OUTPUT: 20986842Sth160488 * 20996842Sth160488 * Returns 1 for success, 0 in case of error. 21006842Sth160488 * 21016842Sth160488 * newaddr - See above (INPUT section). 21026842Sth160488 * 21036842Sth160488 * errstr - See above (INPUT section). 21046842Sth160488 */ 21056842Sth160488 static int 21066842Sth160488 cvt_hostname2ip(char *server, char *newaddr, int newaddr_size, 21076842Sth160488 char *errstr, int errstr_size) 21086842Sth160488 { 21096842Sth160488 char *s; 21106842Sth160488 unsigned short port = 0; 21116842Sth160488 int err; 21126842Sth160488 char buffer[NSS_BUFLEN_HOSTS]; 21136842Sth160488 struct hostent result; 21146842Sth160488 21156842Sth160488 /* Determine if the host name contains a port number. */ 21166842Sth160488 21176842Sth160488 /* Skip over IPv6 address. */ 21186842Sth160488 s = strchr(server, ']'); 21196842Sth160488 s = strchr(s != NULL ? s : server, ':'); 21206842Sth160488 if (s != NULL) { 21216842Sth160488 if (sscanf(s + 1, "%hu", &port) != 1) { 21226842Sth160488 /* Address misformatted. No port number after : */ 21236842Sth160488 (void) snprintf(errstr, errstr_size, "%s", 21246842Sth160488 gettext("Invalid host:port format")); 21256842Sth160488 return (0); 21266842Sth160488 } else 21276842Sth160488 /* Cut off the :<port> part. */ 21286842Sth160488 *s = '\0'; 21296842Sth160488 } 21306842Sth160488 21316842Sth160488 buffer[0] = '\0'; 21326842Sth160488 /* 21336842Sth160488 * Resolve hostname and fill in hostent structure. 21346842Sth160488 */ 21356842Sth160488 if (!__s_api_hostname2ip(server, &result, buffer, NSS_BUFLEN_HOSTS, 21366842Sth160488 &err)) { 21376842Sth160488 /* 21386842Sth160488 * The only possible error here could be TRY_AGAIN if buffer was 21396842Sth160488 * not big enough. NSS_BUFLEN_HOSTS should have been enough 21406842Sth160488 * though. 21416842Sth160488 */ 21426842Sth160488 (void) snprintf(errstr, errstr_size, "%s", 21436842Sth160488 gettext("Unable to resolve address.")); 21446842Sth160488 return (0); 21456842Sth160488 } 21466842Sth160488 21476842Sth160488 21486842Sth160488 buffer[0] = '\0'; 21496842Sth160488 /* 21506842Sth160488 * Convert the address to string. 21516842Sth160488 */ 21526842Sth160488 if (!inet_ntop(result.h_addrtype, result.h_addr_list[0], buffer, 21536842Sth160488 NSS_BUFLEN_HOSTS)) { 21546842Sth160488 /* There's not much we can do. */ 21556842Sth160488 (void) snprintf(errstr, errstr_size, "%s", 21566842Sth160488 gettext("Unable to convert address to string.")); 21576842Sth160488 return (0); 21586842Sth160488 } 21596842Sth160488 21606842Sth160488 /* Put together the address and the port */ 21616842Sth160488 if (port > 0) { 21626842Sth160488 switch (result.h_addrtype) { 21636842Sth160488 case AF_INET6: 21646842Sth160488 (void) snprintf(newaddr, 21656842Sth160488 /* [IP]:<port>\0 */ 21666842Sth160488 1 + strlen(buffer) + 1 + 1 + 5 + 1, 21676842Sth160488 "[%s]:%hu", 21686842Sth160488 buffer, 21696842Sth160488 port); 21706842Sth160488 break; 21716842Sth160488 /* AF_INET */ 21726842Sth160488 default : 21736842Sth160488 (void) snprintf(newaddr, 21746842Sth160488 /* IP:<port>\0 */ 21756842Sth160488 strlen(buffer) + 1 + 5 + 1, 21766842Sth160488 "%s:%hu", 21776842Sth160488 buffer, 21786842Sth160488 port); 21796842Sth160488 break; 21806842Sth160488 } 21816842Sth160488 } else { 21826842Sth160488 (void) strncpy(newaddr, buffer, newaddr_size); 21836842Sth160488 } 21846842Sth160488 21856842Sth160488 return (1); 21866842Sth160488 } 21876842Sth160488 21886842Sth160488 21896842Sth160488 /* 21906842Sth160488 * This finction initializes a none-TLS LDAP session. On success LDAP* 21916842Sth160488 * is returned (pointed by *ldp). Otherwise, the function returns 21926842Sth160488 * an NS error code and provides an additional info pointed by *errorp. 21936842Sth160488 */ 21946842Sth160488 static 21956842Sth160488 ns_ldap_return_code 21966842Sth160488 createNonTLSSession(const char *serverAddr, 21976842Sth160488 uint16_t port, int gssapi, 21986842Sth160488 LDAP **ldp, ns_ldap_error_t **errorp) 21996842Sth160488 { 22006842Sth160488 char errstr[MAXERROR]; 22016842Sth160488 char *addr; 22026842Sth160488 int is_ip = 0; 22036842Sth160488 /* [INET6_ADDRSTRLEN]:<port>\0 */ 22046842Sth160488 char svraddr[1+INET6_ADDRSTRLEN+1+1+5+1]; 22056842Sth160488 #ifdef DEBUG 22066842Sth160488 (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n", 22076842Sth160488 thr_self()); 22086842Sth160488 #endif /* DEBUG */ 22096842Sth160488 22106842Sth160488 if (gssapi == 0) { 22116842Sth160488 is_ip = (__s_api_isipv4((char *)serverAddr) || 22126842Sth160488 __s_api_isipv6((char *)serverAddr)); 22136842Sth160488 } 22146842Sth160488 22156842Sth160488 /* 22166842Sth160488 * Let's try to resolve IP address of server. 22176842Sth160488 */ 22186842Sth160488 if (is_ip == 0 && !gssapi && (ldap_in_nss_switch((char *)"hosts") > 0 || 22196842Sth160488 ldap_in_nss_switch((char *)"ipnodes") > 0)) { 22206842Sth160488 addr = strdup(serverAddr); 22216842Sth160488 if (addr == NULL) 22226842Sth160488 return (NS_LDAP_MEMORY); 22236842Sth160488 svraddr[0] = '\0'; 22246842Sth160488 if (cvt_hostname2ip(addr, svraddr, sizeof (svraddr), 22256842Sth160488 errstr, MAXERROR) == 1) { 22266842Sth160488 serverAddr = svraddr; 22276842Sth160488 free(addr); 22286842Sth160488 } else { 22296842Sth160488 free(addr); 22306842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 22316842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 22326842Sth160488 return (NS_LDAP_INTERNAL); 22336842Sth160488 } 22346842Sth160488 } 22356842Sth160488 22366842Sth160488 /* Warning message IF cannot connect to host(s) */ 22376842Sth160488 if ((*ldp = ldap_init((char *)serverAddr, port)) == NULL) { 22386842Sth160488 char *p = strerror(errno); 22396842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 22406842Sth160488 strdup(p), NS_LDAP_MEMORY); 22416842Sth160488 return (NS_LDAP_INTERNAL); 22426842Sth160488 } 22436842Sth160488 22446842Sth160488 return (NS_LDAP_SUCCESS); 22456842Sth160488 } 22466842Sth160488 22476842Sth160488 /* 22486842Sth160488 * This finction initializes an LDAP session. 22496842Sth160488 * 22506842Sth160488 * INPUT: 22516842Sth160488 * auth - a structure specified an authenticastion method and credentials, 22526842Sth160488 * serverAddr - the address of a server to which a connection 22536842Sth160488 * will be established, 22546842Sth160488 * port - a port being listened by the server, 22556842Sth160488 * timeoutMilliSec - a timeout in milliseconds for the Bind operation. 22566842Sth160488 * 22576842Sth160488 * OUTPUT: 22586842Sth160488 * ldp - a pointer to an LDAP structure which will be used 22596842Sth160488 * for all the subsequent operations against the server. 22606921Smichen * If an error occurs, the function returns an NS error code 22616842Sth160488 * and provides an additional info pointed by *errorp. 22626842Sth160488 */ 22636842Sth160488 static 22646842Sth160488 ns_ldap_return_code 22656842Sth160488 createSession(const ns_cred_t *auth, const char *serverAddr, 22666842Sth160488 uint16_t port, int timeoutMilliSec, 22676842Sth160488 LDAP **ldp, ns_ldap_error_t **errorp) 22686842Sth160488 { 22696842Sth160488 int useSSL = 0, gssapi = 0; 22706842Sth160488 char errstr[MAXERROR]; 22716842Sth160488 22726842Sth160488 switch (auth->auth.type) { 22736842Sth160488 case NS_LDAP_AUTH_NONE: 22746842Sth160488 case NS_LDAP_AUTH_SIMPLE: 22756842Sth160488 case NS_LDAP_AUTH_SASL: 22766842Sth160488 break; 22776842Sth160488 case NS_LDAP_AUTH_TLS: 22786842Sth160488 useSSL = 1; 22796842Sth160488 break; 22806842Sth160488 default: 22816842Sth160488 (void) sprintf(errstr, 22826842Sth160488 gettext("openConnection: unsupported " 22836842Sth160488 "authentication method (%d)"), auth->auth.type); 22846842Sth160488 MKERROR(LOG_WARNING, *errorp, 22856842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 22866842Sth160488 NS_LDAP_MEMORY); 22876842Sth160488 return (NS_LDAP_INTERNAL); 22886842Sth160488 } 22896842Sth160488 22906842Sth160488 if (port == USE_DEFAULT_PORT) { 22916842Sth160488 port = useSSL ? LDAPS_PORT : LDAP_PORT; 22926842Sth160488 } 22936842Sth160488 22946842Sth160488 if (auth->auth.type == NS_LDAP_AUTH_SASL && 22956842Sth160488 auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) 22966842Sth160488 gssapi = 1; 22976842Sth160488 22986842Sth160488 if (useSSL) 22996842Sth160488 return (createTLSSession(auth, serverAddr, port, 23006842Sth160488 timeoutMilliSec, ldp, errorp)); 23016842Sth160488 else 23026842Sth160488 return (createNonTLSSession(serverAddr, port, gssapi, 23036842Sth160488 ldp, errorp)); 23040Sstevel@tonic-gate } 23056842Sth160488 23066842Sth160488 /* 23076842Sth160488 * This finction performs a non-SASL bind operation. If an error accures, 23086842Sth160488 * the function returns an NS error code and provides an additional info 23096842Sth160488 * pointed by *errorp. 23106842Sth160488 */ 23116842Sth160488 static 23126842Sth160488 ns_ldap_return_code 23136842Sth160488 doSimpleBind(const ns_cred_t *auth, 23146842Sth160488 LDAP *ld, 23156842Sth160488 int timeoutSec, 23166842Sth160488 ns_ldap_error_t **errorp, 23176842Sth160488 int fail_if_new_pwd_reqd, 23186842Sth160488 int passwd_mgmt) 23196842Sth160488 { 23206842Sth160488 char *binddn, *passwd, errstr[MAXERROR], *errmsg; 23216842Sth160488 int msgId, errnum = 0, ldap_rc; 23226842Sth160488 ns_ldap_return_code ret_code; 23236842Sth160488 LDAPMessage *resultMsg = NULL; 23246842Sth160488 LDAPControl **controls; 23256842Sth160488 struct timeval tv; 23266842Sth160488 23276842Sth160488 binddn = auth->cred.unix_cred.userID; 23286842Sth160488 passwd = auth->cred.unix_cred.passwd; 23296842Sth160488 if (passwd == NULL || *passwd == '\0' || 23306842Sth160488 binddn == NULL || *binddn == '\0') { 23316842Sth160488 (void) sprintf(errstr, gettext("openConnection: " 23326842Sth160488 "missing credentials for Simple bind")); 23336842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, 23346842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 23356842Sth160488 (void) ldap_unbind(ld); 23366842Sth160488 return (NS_LDAP_INTERNAL); 23376842Sth160488 } 23386842Sth160488 23396842Sth160488 #ifdef DEBUG 23406842Sth160488 (void) fprintf(stderr, "tid= %d: +++Simple bind\n", 23416842Sth160488 thr_self()); 23426842Sth160488 #endif /* DEBUG */ 23436842Sth160488 msgId = ldap_simple_bind(ld, binddn, passwd); 23446842Sth160488 23456842Sth160488 if (msgId == -1) { 23466842Sth160488 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 23476842Sth160488 (void *)&errnum); 23486842Sth160488 (void) snprintf(errstr, sizeof (errstr), 23496842Sth160488 gettext("openConnection: simple bind failed " 23506842Sth160488 "- %s"), ldap_err2string(errnum)); 23516842Sth160488 (void) ldap_unbind(ld); 23526842Sth160488 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 23536842Sth160488 NS_LDAP_MEMORY); 23546842Sth160488 return (NS_LDAP_INTERNAL); 23556842Sth160488 } 23566842Sth160488 23576842Sth160488 tv.tv_sec = timeoutSec; 23586842Sth160488 tv.tv_usec = 0; 23596842Sth160488 ldap_rc = ldap_result(ld, msgId, 0, &tv, &resultMsg); 23606842Sth160488 23616842Sth160488 if ((ldap_rc == -1) || (ldap_rc == 0)) { 23626842Sth160488 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 23636842Sth160488 (void *)&errnum); 23646842Sth160488 (void) snprintf(errstr, sizeof (errstr), 23656842Sth160488 gettext("openConnection: simple bind failed " 23666842Sth160488 "- %s"), ldap_err2string(errnum)); 23676842Sth160488 (void) ldap_msgfree(resultMsg); 23686842Sth160488 (void) ldap_unbind(ld); 23696842Sth160488 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 23706842Sth160488 NS_LDAP_MEMORY); 23716842Sth160488 return (NS_LDAP_INTERNAL); 23726842Sth160488 } 23736842Sth160488 23746842Sth160488 /* 23756842Sth160488 * get ldaprc, controls, and error msg 23766842Sth160488 */ 23776842Sth160488 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 23786842Sth160488 &errmsg, NULL, &controls, 1); 23796842Sth160488 23806842Sth160488 if (ldap_rc != LDAP_SUCCESS) { 23816842Sth160488 (void) snprintf(errstr, sizeof (errstr), 23826842Sth160488 gettext("openConnection: simple bind failed " 23836842Sth160488 "- unable to parse result")); 23846842Sth160488 (void) ldap_unbind(ld); 23856842Sth160488 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 23866842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 23876842Sth160488 return (NS_LDAP_INTERNAL); 23886842Sth160488 } 23896842Sth160488 23906842Sth160488 /* process the password management info, if any */ 23916842Sth160488 ret_code = process_pwd_mgmt("simple", 23926842Sth160488 errnum, controls, errmsg, 23936842Sth160488 errorp, 23946842Sth160488 fail_if_new_pwd_reqd, 23956842Sth160488 passwd_mgmt); 23966842Sth160488 23976842Sth160488 if (ret_code == NS_LDAP_INTERNAL) { 23986842Sth160488 (void) ldap_unbind(ld); 23996842Sth160488 } 24006842Sth160488 24016842Sth160488 return (ret_code); 24026842Sth160488 } 24036842Sth160488 24046842Sth160488 /* 24056842Sth160488 * This finction performs a SASL bind operation. If an error accures, 24066842Sth160488 * the function returns an NS error code and provides an additional info 24076842Sth160488 * pointed by *errorp. 24086842Sth160488 */ 24096842Sth160488 static 24106842Sth160488 ns_ldap_return_code 24116842Sth160488 doSASLBind(const ns_cred_t *auth, 24126842Sth160488 LDAP *ld, 24136842Sth160488 int timeoutSec, 24146842Sth160488 ns_ldap_error_t **errorp, 24156842Sth160488 int fail_if_new_pwd_reqd, 24166842Sth160488 int passwd_mgmt) 24176842Sth160488 { 24186842Sth160488 char *binddn, *passwd, *digest_md5_name, 24196842Sth160488 errstr[MAXERROR], *errmsg; 24206842Sth160488 struct berval cred; 24216842Sth160488 int ldap_rc, errnum = 0; 24226842Sth160488 ns_ldap_return_code ret_code; 24236842Sth160488 struct timeval tv; 24246842Sth160488 LDAPMessage *resultMsg; 24256842Sth160488 LDAPControl **controls; 24266842Sth160488 int min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF; 24276842Sth160488 ns_sasl_cb_param_t sasl_param; 24286842Sth160488 24296842Sth160488 if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE && 24306842Sth160488 auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 24316842Sth160488 (void) sprintf(errstr, 24326842Sth160488 gettext("openConnection: SASL options are " 24336842Sth160488 "not supported (%d) for non-GSSAPI sasl bind"), 24346842Sth160488 auth->auth.saslopt); 24356842Sth160488 MKERROR(LOG_WARNING, *errorp, 24366842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED, 24376842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 24386842Sth160488 (void) ldap_unbind(ld); 24396842Sth160488 return (NS_LDAP_INTERNAL); 24406842Sth160488 } 24416842Sth160488 if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 24426842Sth160488 binddn = auth->cred.unix_cred.userID; 24436842Sth160488 passwd = auth->cred.unix_cred.passwd; 24446842Sth160488 if (passwd == NULL || *passwd == '\0' || 24456842Sth160488 binddn == NULL || *binddn == '\0') { 24466842Sth160488 (void) sprintf(errstr, 24476842Sth160488 gettext("openConnection: missing credentials " 24486842Sth160488 "for SASL bind")); 24496842Sth160488 MKERROR(LOG_WARNING, *errorp, 24506842Sth160488 LDAP_INVALID_CREDENTIALS, 24516842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 24526842Sth160488 (void) ldap_unbind(ld); 24536842Sth160488 return (NS_LDAP_INTERNAL); 24546842Sth160488 } 24556842Sth160488 cred.bv_val = passwd; 24566842Sth160488 cred.bv_len = strlen(passwd); 24576842Sth160488 } 24586842Sth160488 24596842Sth160488 ret_code = NS_LDAP_SUCCESS; 24606842Sth160488 24616842Sth160488 switch (auth->auth.saslmech) { 24626842Sth160488 case NS_LDAP_SASL_CRAM_MD5: 24636842Sth160488 /* 24646842Sth160488 * NOTE: if iDS changes to support cram_md5, 24656842Sth160488 * please add password management code here. 24666842Sth160488 * Since ldap_sasl_cram_md5_bind_s does not 24676842Sth160488 * return anything that could be used to 24686842Sth160488 * extract the ldap rc/errmsg/control to 24696842Sth160488 * determine if bind failed due to password 24706842Sth160488 * policy, a new cram_md5_bind API will need 24716842Sth160488 * to be introduced. See 24726842Sth160488 * ldap_x_sasl_digest_md5_bind() and case 24736842Sth160488 * NS_LDAP_SASL_DIGEST_MD5 below for details. 24746842Sth160488 */ 24756842Sth160488 if ((ldap_rc = ldap_sasl_cram_md5_bind_s(ld, binddn, 24766842Sth160488 &cred, NULL, NULL)) != LDAP_SUCCESS) { 24776842Sth160488 (void) ldap_get_option(ld, 24786842Sth160488 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 24796842Sth160488 (void) snprintf(errstr, sizeof (errstr), 24806842Sth160488 gettext("openConnection: " 24816842Sth160488 "sasl/CRAM-MD5 bind failed - %s"), 24826842Sth160488 ldap_err2string(errnum)); 24836842Sth160488 MKERROR(LOG_WARNING, *errorp, errnum, 24846842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 24856842Sth160488 (void) ldap_unbind(ld); 24866842Sth160488 return (NS_LDAP_INTERNAL); 24876842Sth160488 } 24886842Sth160488 break; 24896842Sth160488 case NS_LDAP_SASL_DIGEST_MD5: 24906842Sth160488 digest_md5_name = malloc(strlen(binddn) + 5); 24916842Sth160488 /* 5 = strlen("dn: ") + 1 */ 24926842Sth160488 if (digest_md5_name == NULL) { 24936842Sth160488 (void) ldap_unbind(ld); 24946842Sth160488 return (NS_LDAP_MEMORY); 24956842Sth160488 } 24966842Sth160488 (void) strcpy(digest_md5_name, "dn: "); 24976842Sth160488 (void) strcat(digest_md5_name, binddn); 24986842Sth160488 24996842Sth160488 tv.tv_sec = timeoutSec; 25006842Sth160488 tv.tv_usec = 0; 25016842Sth160488 ldap_rc = ldap_x_sasl_digest_md5_bind(ld, 25026842Sth160488 digest_md5_name, &cred, NULL, NULL, 25036842Sth160488 &tv, &resultMsg); 25046842Sth160488 25056842Sth160488 if (resultMsg == NULL) { 25066842Sth160488 free(digest_md5_name); 25076842Sth160488 (void) ldap_get_option(ld, 25086842Sth160488 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 25096842Sth160488 (void) snprintf(errstr, sizeof (errstr), 25106842Sth160488 gettext("openConnection: " 25116842Sth160488 "DIGEST-MD5 bind failed - %s"), 25126842Sth160488 ldap_err2string(errnum)); 25136842Sth160488 (void) ldap_unbind(ld); 25146842Sth160488 MKERROR(LOG_WARNING, *errorp, errnum, 25156842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 25166842Sth160488 return (NS_LDAP_INTERNAL); 25176842Sth160488 } 25186842Sth160488 25196842Sth160488 /* 25206842Sth160488 * get ldaprc, controls, and error msg 25216842Sth160488 */ 25226842Sth160488 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 25236842Sth160488 &errmsg, NULL, &controls, 1); 25246842Sth160488 25256842Sth160488 if (ldap_rc != LDAP_SUCCESS) { 25266842Sth160488 free(digest_md5_name); 25276842Sth160488 (void) snprintf(errstr, sizeof (errstr), 25286842Sth160488 gettext("openConnection: " 25296842Sth160488 "DIGEST-MD5 bind failed " 25306842Sth160488 "- unable to parse result")); 25316842Sth160488 (void) ldap_unbind(ld); 25326842Sth160488 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 25336842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 25346842Sth160488 return (NS_LDAP_INTERNAL); 25356842Sth160488 } 25366842Sth160488 25376842Sth160488 /* process the password management info, if any */ 25386842Sth160488 ret_code = process_pwd_mgmt("sasl/DIGEST-MD5", 25396842Sth160488 errnum, controls, errmsg, 25406842Sth160488 errorp, 25416842Sth160488 fail_if_new_pwd_reqd, 25426842Sth160488 passwd_mgmt); 25436842Sth160488 25446842Sth160488 if (ret_code == NS_LDAP_INTERNAL) { 25456842Sth160488 (void) ldap_unbind(ld); 25466842Sth160488 } 25476842Sth160488 25486842Sth160488 free(digest_md5_name); 25496842Sth160488 break; 25506842Sth160488 case NS_LDAP_SASL_GSSAPI: 25516842Sth160488 if (sasl_gssapi_inited == 0) { 25526842Sth160488 ret_code = __s_api_sasl_gssapi_init(); 25536842Sth160488 if (ret_code != NS_LDAP_SUCCESS) { 25546842Sth160488 (void) snprintf(errstr, sizeof (errstr), 25556842Sth160488 gettext("openConnection: " 25566842Sth160488 "GSSAPI initialization " 25576842Sth160488 "failed")); 25586842Sth160488 (void) ldap_unbind(ld); 25596842Sth160488 MKERROR(LOG_WARNING, *errorp, ret_code, 25606842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 25616842Sth160488 return (ret_code); 25626842Sth160488 } 25636842Sth160488 } 25646842Sth160488 (void) memset(&sasl_param, 0, 25656842Sth160488 sizeof (ns_sasl_cb_param_t)); 25666842Sth160488 sasl_param.authid = NULL; 25676842Sth160488 sasl_param.authzid = ""; 25686842Sth160488 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN, 25696842Sth160488 (void *)&min_ssf); 25706842Sth160488 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX, 25716842Sth160488 (void *)&max_ssf); 25726842Sth160488 25736842Sth160488 ldap_rc = ldap_sasl_interactive_bind_s( 25746842Sth160488 ld, NULL, "GSSAPI", 25756842Sth160488 NULL, NULL, LDAP_SASL_INTERACTIVE, 25766842Sth160488 __s_api_sasl_bind_callback, 25776842Sth160488 &sasl_param); 25786842Sth160488 25796842Sth160488 if (ldap_rc != LDAP_SUCCESS) { 25806842Sth160488 (void) snprintf(errstr, sizeof (errstr), 25816842Sth160488 gettext("openConnection: " 25826842Sth160488 "GSSAPI bind failed " 25836842Sth160488 "- %d %s"), 25846842Sth160488 ldap_rc, 25856842Sth160488 ldap_err2string(ldap_rc)); 25866842Sth160488 (void) ldap_unbind(ld); 25876842Sth160488 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 25886842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 25896842Sth160488 return (NS_LDAP_INTERNAL); 25906842Sth160488 } 25916842Sth160488 25926842Sth160488 break; 25936842Sth160488 default: 25946842Sth160488 (void) ldap_unbind(ld); 25956842Sth160488 (void) sprintf(errstr, 25966842Sth160488 gettext("openConnection: unsupported SASL " 25976842Sth160488 "mechanism (%d)"), auth->auth.saslmech); 25986842Sth160488 MKERROR(LOG_WARNING, *errorp, 25996842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 26006842Sth160488 NS_LDAP_MEMORY); 26016842Sth160488 return (NS_LDAP_INTERNAL); 26026842Sth160488 } 26036842Sth160488 26046842Sth160488 return (ret_code); 26056842Sth160488 } 26066842Sth160488 26076842Sth160488 /* 26086842Sth160488 * This function performs an LDAP Bind operation proceeding 26096842Sth160488 * from a type of the connection specified by auth->auth.type. 26106842Sth160488 * 26116842Sth160488 * INPUT: 26126842Sth160488 * auth - a structure specified an authenticastion method and credentials, 26136842Sth160488 * ld - a pointer returned by the createSession() function, 26146842Sth160488 * timeoutSec - a timeout in seconds for the Bind operation, 26156842Sth160488 * fail_if_new_pwd_reqd - a flag indicating that the call should fail 26166842Sth160488 * if a new password is required, 26176842Sth160488 * passwd_mgmt - a flag indicating that the server supports 26186842Sth160488 * password management. 26196842Sth160488 * 26206842Sth160488 * OUTPUT: 26216842Sth160488 * If an error accures, the function returns an NS error code 26226842Sth160488 * and provides an additional info pointed by *errorp. 26236842Sth160488 */ 26246842Sth160488 static 26256842Sth160488 ns_ldap_return_code 26266842Sth160488 performBind(const ns_cred_t *auth, 26276842Sth160488 LDAP *ld, 26286842Sth160488 int timeoutSec, 26296842Sth160488 ns_ldap_error_t **errorp, 26306842Sth160488 int fail_if_new_pwd_reqd, 26316842Sth160488 int passwd_mgmt) 26326842Sth160488 { 26336842Sth160488 int bindType; 26346842Sth160488 char errstr[MAXERROR]; 26356842Sth160488 26366842Sth160488 ns_ldap_return_code (*binder)(const ns_cred_t *auth, 26376842Sth160488 LDAP *ld, 26386842Sth160488 int timeoutSec, 26396842Sth160488 ns_ldap_error_t **errorp, 26406842Sth160488 int fail_if_new_pwd_reqd, 26416842Sth160488 int passwd_mgmt) = NULL; 26426842Sth160488 26436842Sth160488 if (!ld) { 26446842Sth160488 (void) sprintf(errstr, 26456842Sth160488 "performBind: LDAP session " 26466842Sth160488 "is not initialized."); 26476842Sth160488 MKERROR(LOG_WARNING, *errorp, 26486842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED, 26496842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 26506842Sth160488 return (NS_LDAP_INTERNAL); 26516842Sth160488 } 26526842Sth160488 26536842Sth160488 bindType = auth->auth.type == NS_LDAP_AUTH_TLS ? 26546842Sth160488 auth->auth.tlstype : auth->auth.type; 26556842Sth160488 26566842Sth160488 switch (bindType) { 26576842Sth160488 case NS_LDAP_AUTH_NONE: 26586842Sth160488 #ifdef DEBUG 26596842Sth160488 (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n", 26606842Sth160488 thr_self()); 26616842Sth160488 #endif /* DEBUG */ 26626842Sth160488 break; 26636842Sth160488 case NS_LDAP_AUTH_SIMPLE: 26646842Sth160488 binder = doSimpleBind; 26656842Sth160488 break; 26666842Sth160488 case NS_LDAP_AUTH_SASL: 26676842Sth160488 binder = doSASLBind; 26686842Sth160488 break; 26696842Sth160488 default: 26706842Sth160488 (void) sprintf(errstr, 26716842Sth160488 gettext("openConnection: unsupported " 26726842Sth160488 "authentication method " 26736842Sth160488 "(%d)"), bindType); 26746842Sth160488 MKERROR(LOG_WARNING, *errorp, 26756842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED, 26766842Sth160488 strdup(errstr), NS_LDAP_MEMORY); 26776842Sth160488 (void) ldap_unbind(ld); 26786842Sth160488 return (NS_LDAP_INTERNAL); 26796842Sth160488 } 26806842Sth160488 26816842Sth160488 if (binder != NULL) { 26826842Sth160488 return (*binder)(auth, 26836842Sth160488 ld, 26846842Sth160488 timeoutSec, 26856842Sth160488 errorp, 26866842Sth160488 fail_if_new_pwd_reqd, 26876842Sth160488 passwd_mgmt); 26886842Sth160488 } 26896842Sth160488 26906842Sth160488 return (NS_LDAP_SUCCESS); 26916842Sth160488 } 2692