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 */
2111411SSurya.Prakki@Sun.COM
220Sstevel@tonic-gate /*
2312823SJulian.Pullen@Sun.COM * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include <stdio.h>
280Sstevel@tonic-gate #include <errno.h>
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <synch.h>
310Sstevel@tonic-gate #include <time.h>
320Sstevel@tonic-gate #include <libintl.h>
330Sstevel@tonic-gate #include <thread.h>
340Sstevel@tonic-gate #include <syslog.h>
350Sstevel@tonic-gate #include <sys/mman.h>
360Sstevel@tonic-gate #include <nsswitch.h>
370Sstevel@tonic-gate #include <nss_dbdefs.h>
380Sstevel@tonic-gate #include "solaris-priv.h"
392830Sdjl #include "solaris-int.h"
400Sstevel@tonic-gate #include "ns_sldap.h"
410Sstevel@tonic-gate #include "ns_internal.h"
420Sstevel@tonic-gate #include "ns_cache_door.h"
436842Sth160488 #include "ns_connmgmt.h"
442333Sjanga #include "ldappr.h"
450Sstevel@tonic-gate #include <sys/stat.h>
460Sstevel@tonic-gate #include <fcntl.h>
470Sstevel@tonic-gate #include <procfs.h>
480Sstevel@tonic-gate #include <unistd.h>
490Sstevel@tonic-gate
506842Sth160488 #define USE_DEFAULT_PORT 0
516842Sth160488
526842Sth160488 static ns_ldap_return_code performBind(const ns_cred_t *,
536842Sth160488 LDAP *,
546842Sth160488 int,
556842Sth160488 ns_ldap_error_t **,
566842Sth160488 int,
576842Sth160488 int);
586842Sth160488 static ns_ldap_return_code createSession(const ns_cred_t *,
596842Sth160488 const char *,
606842Sth160488 uint16_t,
616842Sth160488 int,
626842Sth160488 LDAP **,
636842Sth160488 ns_ldap_error_t **);
646842Sth160488
650Sstevel@tonic-gate extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *,
660Sstevel@tonic-gate LDAPControl **, LDAPControl **);
670Sstevel@tonic-gate extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip);
680Sstevel@tonic-gate
699576SJulian.Pullen@Sun.COM extern int __door_getconf(char **buffer, int *buflen,
709576SJulian.Pullen@Sun.COM ns_ldap_error_t **error, int callnumber);
719576SJulian.Pullen@Sun.COM extern int __ns_ldap_freeUnixCred(UnixCred_t **credp);
729576SJulian.Pullen@Sun.COM extern int SetDoorInfoToUnixCred(char *buffer,
739576SJulian.Pullen@Sun.COM ns_ldap_error_t **errorp,
749576SJulian.Pullen@Sun.COM UnixCred_t **cred);
759576SJulian.Pullen@Sun.COM
760Sstevel@tonic-gate static int openConnection(LDAP **, const char *, const ns_cred_t *,
77*12969SJulian.Pullen@Sun.COM int, ns_ldap_error_t **, int, int, ns_conn_user_t *, int);
784048Schinlong static void
794048Schinlong _DropConnection(ConnectionID cID, int flag, int fini);
806842Sth160488
816842Sth160488 static mutex_t sessionPoolLock = DEFAULTMUTEX;
820Sstevel@tonic-gate
830Sstevel@tonic-gate static Connection **sessionPool = NULL;
840Sstevel@tonic-gate static int sessionPoolSize = 0;
850Sstevel@tonic-gate
862830Sdjl /*
872830Sdjl * SSF values are for SASL integrity & privacy.
882830Sdjl * JES DS5.2 does not support this feature but DS6 does.
892830Sdjl * The values between 0 and 65535 can work with both server versions.
902830Sdjl */
912830Sdjl #define MAX_SASL_SSF 65535
922830Sdjl #define MIN_SASL_SSF 0
930Sstevel@tonic-gate
941687Sjanga /* Number of hostnames to allocate memory for */
951687Sjanga #define NUMTOMALLOC 32
962830Sdjl
972830Sdjl /*
986842Sth160488 * This function get the servers from the lists and returns
996842Sth160488 * the first server with the empty lists of server controls and
1006842Sth160488 * SASL mechanisms. It is invoked if it is not possible to obtain a server
1016842Sth160488 * from ldap_cachemgr or the local list.
1022830Sdjl */
1036842Sth160488 static
1046842Sth160488 ns_ldap_return_code
getFirstFromConfig(ns_server_info_t * ret,ns_ldap_error_t ** error)1056842Sth160488 getFirstFromConfig(ns_server_info_t *ret, ns_ldap_error_t **error)
1062830Sdjl {
1076842Sth160488 char **servers = NULL;
1086842Sth160488 ns_ldap_return_code ret_code;
1096842Sth160488 char errstr[MAXERROR];
1102830Sdjl
1116842Sth160488 /* get first server from config list unavailable otherwise */
1126842Sth160488 ret_code = __s_api_getServers(&servers, error);
1136842Sth160488 if (ret_code != NS_LDAP_SUCCESS) {
1146842Sth160488 if (servers != NULL) {
1156842Sth160488 __s_api_free2dArray(servers);
1166842Sth160488 }
1176842Sth160488 return (ret_code);
1182830Sdjl }
1192830Sdjl
1206842Sth160488 if (servers == NULL || servers[0] == NULL) {
1216842Sth160488 __s_api_free2dArray(servers);
1226842Sth160488 (void) sprintf(errstr,
1236842Sth160488 gettext("No server found in configuration"));
1246842Sth160488 MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT,
1256842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
1266842Sth160488 return (NS_LDAP_CONFIG);
1276072Smj162486 }
1286072Smj162486
1296842Sth160488 ret->server = strdup(servers[0]);
1306842Sth160488 if (ret->server == NULL) {
1316842Sth160488 __s_api_free2dArray(servers);
1326842Sth160488 return (NS_LDAP_MEMORY);
1336072Smj162486 }
1346072Smj162486
1356842Sth160488 ret->saslMechanisms = NULL;
1366842Sth160488 ret->controls = NULL;
1376072Smj162486
1386842Sth160488 __s_api_free2dArray(servers);
1396072Smj162486
1406842Sth160488 return (NS_LDAP_SUCCESS);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate
1439576SJulian.Pullen@Sun.COM /* very similar to __door_getldapconfig() in ns_config.c */
1449576SJulian.Pullen@Sun.COM static int
__door_getadmincred(char ** buffer,int * buflen,ns_ldap_error_t ** error)1459576SJulian.Pullen@Sun.COM __door_getadmincred(char **buffer, int *buflen, ns_ldap_error_t **error)
1469576SJulian.Pullen@Sun.COM {
1479576SJulian.Pullen@Sun.COM return (__door_getconf(buffer, buflen, error, GETADMINCRED));
1489576SJulian.Pullen@Sun.COM }
1499576SJulian.Pullen@Sun.COM
1509576SJulian.Pullen@Sun.COM /*
1519576SJulian.Pullen@Sun.COM * This function requests Admin credentials from the cache manager through
1529576SJulian.Pullen@Sun.COM * the door functionality
1539576SJulian.Pullen@Sun.COM */
1549576SJulian.Pullen@Sun.COM
1559576SJulian.Pullen@Sun.COM static int
requestAdminCred(UnixCred_t ** cred,ns_ldap_error_t ** error)1569576SJulian.Pullen@Sun.COM requestAdminCred(UnixCred_t **cred, ns_ldap_error_t **error)
1579576SJulian.Pullen@Sun.COM {
1589576SJulian.Pullen@Sun.COM char *buffer = NULL;
1599576SJulian.Pullen@Sun.COM int buflen = 0;
1609576SJulian.Pullen@Sun.COM int ret;
1619576SJulian.Pullen@Sun.COM
1629576SJulian.Pullen@Sun.COM *error = NULL;
1639576SJulian.Pullen@Sun.COM ret = __door_getadmincred(&buffer, &buflen, error);
1649576SJulian.Pullen@Sun.COM
1659576SJulian.Pullen@Sun.COM if (ret != NS_LDAP_SUCCESS) {
1669576SJulian.Pullen@Sun.COM if (*error != NULL && (*error)->message != NULL)
1679576SJulian.Pullen@Sun.COM syslog(LOG_WARNING, "libsldap: %s", (*error)->message);
1689576SJulian.Pullen@Sun.COM return (ret);
1699576SJulian.Pullen@Sun.COM }
1709576SJulian.Pullen@Sun.COM
1719576SJulian.Pullen@Sun.COM /* now convert from door format */
1729576SJulian.Pullen@Sun.COM ret = SetDoorInfoToUnixCred(buffer, error, cred);
1739576SJulian.Pullen@Sun.COM free(buffer);
1749576SJulian.Pullen@Sun.COM
1759576SJulian.Pullen@Sun.COM return (ret);
1769576SJulian.Pullen@Sun.COM }
1779576SJulian.Pullen@Sun.COM
1780Sstevel@tonic-gate /*
1790Sstevel@tonic-gate * This function requests a server from the cache manager through
1800Sstevel@tonic-gate * the door functionality
1810Sstevel@tonic-gate */
1820Sstevel@tonic-gate
1836842Sth160488 int
__s_api_requestServer(const char * request,const char * server,ns_server_info_t * ret,ns_ldap_error_t ** error,const char * addrType)1840Sstevel@tonic-gate __s_api_requestServer(const char *request, const char *server,
1852830Sdjl ns_server_info_t *ret, ns_ldap_error_t **error, const char *addrType)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate union {
1880Sstevel@tonic-gate ldap_data_t s_d;
1890Sstevel@tonic-gate char s_b[DOORBUFFERSIZE];
1900Sstevel@tonic-gate } space;
1916842Sth160488 ldap_data_t *sptr;
1926842Sth160488 int ndata;
1936842Sth160488 int adata;
1946842Sth160488 char errstr[MAXERROR];
1956842Sth160488 const char *ireq;
1966842Sth160488 char *rbuf, *ptr, *rest;
1976842Sth160488 char *dptr;
1986842Sth160488 char **mptr, **mptr1, **cptr, **cptr1;
1996842Sth160488 int mcnt, ccnt;
2006842Sth160488 int len;
2016842Sth160488 ns_ldap_return_code ret_code;
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate if (ret == NULL || error == NULL) {
2040Sstevel@tonic-gate return (NS_LDAP_OP_FAILED);
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate (void) memset(ret, 0, sizeof (ns_server_info_t));
2070Sstevel@tonic-gate *error = NULL;
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate if (request == NULL)
2100Sstevel@tonic-gate ireq = NS_CACHE_NEW;
2110Sstevel@tonic-gate else
2120Sstevel@tonic-gate ireq = request;
2130Sstevel@tonic-gate
2146842Sth160488 /*
2156842Sth160488 * In the 'Standalone' mode a server will be obtained
2166842Sth160488 * from the local libsldap's list
2176842Sth160488 */
2186842Sth160488 if (__s_api_isStandalone()) {
2197281Smichen if ((ret_code = __s_api_findRootDSE(ireq,
2206842Sth160488 server,
2216842Sth160488 addrType,
2226842Sth160488 ret,
2237281Smichen error)) != NS_LDAP_SUCCESS) {
2247281Smichen /*
2257281Smichen * get first server from local list only once
2267281Smichen * to prevent looping
2277281Smichen */
2287281Smichen if (strcmp(ireq, NS_CACHE_NEW) != 0)
2297281Smichen return (ret_code);
2307281Smichen
2316842Sth160488 syslog(LOG_WARNING,
2326842Sth160488 "libsldap (\"standalone\" mode): "
2336842Sth160488 "can not find any available server. "
2346842Sth160488 "Return the first one from the lists");
2356842Sth160488 if (*error != NULL) {
2366842Sth160488 (void) __ns_ldap_freeError(error);
2376842Sth160488 }
2386842Sth160488
2396842Sth160488 ret_code = getFirstFromConfig(ret, error);
2406842Sth160488 if (ret_code != NS_LDAP_SUCCESS) {
2416842Sth160488 return (ret_code);
2426842Sth160488 }
2436842Sth160488
2446842Sth160488 if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
2456842Sth160488 ret_code = __s_api_ip2hostname(ret->server,
2466842Sth160488 &ret->serverFQDN);
2476842Sth160488 if (ret_code != NS_LDAP_SUCCESS) {
2486842Sth160488 (void) snprintf(errstr,
2496842Sth160488 sizeof (errstr),
2506842Sth160488 gettext("The %s address "
2516842Sth160488 "can not be resolved into "
2526842Sth160488 "a host name. Returning "
2536842Sth160488 "the address as it is."),
2546842Sth160488 ret->server);
2556842Sth160488 MKERROR(LOG_ERR,
2566842Sth160488 *error,
2576842Sth160488 NS_CONFIG_NOTLOADED,
2586842Sth160488 strdup(errstr),
2596842Sth160488 NS_LDAP_MEMORY);
2606842Sth160488 free(ret->server);
2616842Sth160488 ret->server = NULL;
2626842Sth160488 return (NS_LDAP_INTERNAL);
2636842Sth160488 }
2646842Sth160488 }
2656842Sth160488 }
2666842Sth160488
2676842Sth160488 return (NS_LDAP_SUCCESS);
2686842Sth160488 }
2696842Sth160488
2706842Sth160488 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
2716842Sth160488
2722830Sdjl adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1);
2730Sstevel@tonic-gate if (server != NULL) {
2740Sstevel@tonic-gate adata += strlen(DOORLINESEP) + 1;
2750Sstevel@tonic-gate adata += strlen(server) + 1;
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate ndata = sizeof (space);
2782830Sdjl len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
2790Sstevel@tonic-gate space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
2802830Sdjl if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
2812830Sdjl return (NS_LDAP_MEMORY);
2822830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >=
2834522Schinlong len)
2842830Sdjl return (NS_LDAP_MEMORY);
2850Sstevel@tonic-gate if (server != NULL) {
2862830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
2874522Schinlong DOORLINESEP, len) >= len)
2882830Sdjl return (NS_LDAP_MEMORY);
2892830Sdjl if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server,
2904522Schinlong len) >= len)
2912830Sdjl return (NS_LDAP_MEMORY);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate sptr = &space.s_d;
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
2966842Sth160488 case NS_CACHE_SUCCESS:
2970Sstevel@tonic-gate break;
2980Sstevel@tonic-gate /* this case is for when the $mgr is not running, but ldapclient */
2990Sstevel@tonic-gate /* is trying to initialize things */
3006842Sth160488 case NS_CACHE_NOSERVER:
3016842Sth160488 ret_code = getFirstFromConfig(ret, error);
3026842Sth160488 if (ret_code != NS_LDAP_SUCCESS) {
3036842Sth160488 return (ret_code);
3040Sstevel@tonic-gate }
3056842Sth160488
3066842Sth160488 if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
3076842Sth160488 ret_code = __s_api_ip2hostname(ret->server,
3086842Sth160488 &ret->serverFQDN);
3096842Sth160488 if (ret_code != NS_LDAP_SUCCESS) {
3106842Sth160488 (void) snprintf(errstr,
3116842Sth160488 sizeof (errstr),
3126842Sth160488 gettext("The %s address "
3136842Sth160488 "can not be resolved into "
3146842Sth160488 "a host name. Returning "
3156842Sth160488 "the address as it is."),
3166842Sth160488 ret->server);
3176842Sth160488 MKERROR(LOG_ERR,
3186842Sth160488 *error,
3196842Sth160488 NS_CONFIG_NOTLOADED,
3206842Sth160488 strdup(errstr),
3216842Sth160488 NS_LDAP_MEMORY);
3226842Sth160488 free(ret->server);
3236842Sth160488 ret->server = NULL;
3246842Sth160488 return (NS_LDAP_INTERNAL);
3256842Sth160488 }
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate return (NS_LDAP_SUCCESS);
3286842Sth160488 case NS_CACHE_NOTFOUND:
3290Sstevel@tonic-gate default:
3300Sstevel@tonic-gate return (NS_LDAP_OP_FAILED);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate /* copy info from door call return structure here */
3340Sstevel@tonic-gate rbuf = space.s_d.ldap_ret.ldap_u.config;
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate /* Get the host */
3370Sstevel@tonic-gate ptr = strtok_r(rbuf, DOORLINESEP, &rest);
3380Sstevel@tonic-gate if (ptr == NULL) {
3390Sstevel@tonic-gate (void) sprintf(errstr, gettext("No server returned from "
3404522Schinlong "ldap_cachemgr"));
3410Sstevel@tonic-gate MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
3426842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
3430Sstevel@tonic-gate return (NS_LDAP_OP_FAILED);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate ret->server = strdup(ptr);
3460Sstevel@tonic-gate if (ret->server == NULL) {
3470Sstevel@tonic-gate return (NS_LDAP_MEMORY);
3480Sstevel@tonic-gate }
3494522Schinlong /* Get the host FQDN format */
3504522Schinlong if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
3514522Schinlong ptr = strtok_r(NULL, DOORLINESEP, &rest);
3524522Schinlong if (ptr == NULL) {
3534522Schinlong (void) sprintf(errstr, gettext("No server FQDN format "
3544522Schinlong "returned from ldap_cachemgr"));
3554522Schinlong MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
3564522Schinlong strdup(errstr), NULL);
3574522Schinlong free(ret->server);
3584522Schinlong ret->server = NULL;
3594522Schinlong return (NS_LDAP_OP_FAILED);
3604522Schinlong }
3614522Schinlong ret->serverFQDN = strdup(ptr);
3624522Schinlong if (ret->serverFQDN == NULL) {
3634522Schinlong free(ret->server);
3644522Schinlong ret->server = NULL;
3654522Schinlong return (NS_LDAP_MEMORY);
3664522Schinlong }
3674522Schinlong }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate /* get the Supported Controls/SASL mechs */
3700Sstevel@tonic-gate mptr = NULL;
3710Sstevel@tonic-gate mcnt = 0;
3720Sstevel@tonic-gate cptr = NULL;
3730Sstevel@tonic-gate ccnt = 0;
3746842Sth160488 for (;;) {
3750Sstevel@tonic-gate ptr = strtok_r(NULL, DOORLINESEP, &rest);
3760Sstevel@tonic-gate if (ptr == NULL)
3770Sstevel@tonic-gate break;
3780Sstevel@tonic-gate if (strncasecmp(ptr, _SASLMECHANISM,
3794522Schinlong _SASLMECHANISM_LEN) == 0) {
3800Sstevel@tonic-gate dptr = strchr(ptr, '=');
3810Sstevel@tonic-gate if (dptr == NULL)
3820Sstevel@tonic-gate continue;
3830Sstevel@tonic-gate dptr++;
3840Sstevel@tonic-gate mptr1 = (char **)realloc((void *)mptr,
3854522Schinlong sizeof (char *) * (mcnt+2));
3860Sstevel@tonic-gate if (mptr1 == NULL) {
3870Sstevel@tonic-gate __s_api_free2dArray(mptr);
3880Sstevel@tonic-gate if (sptr != &space.s_d) {
3894522Schinlong (void) munmap((char *)sptr, ndata);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate __s_api_free2dArray(cptr);
3924522Schinlong __s_api_free_server_info(ret);
3930Sstevel@tonic-gate return (NS_LDAP_MEMORY);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate mptr = mptr1;
3960Sstevel@tonic-gate mptr[mcnt] = strdup(dptr);
3970Sstevel@tonic-gate if (mptr[mcnt] == NULL) {
3980Sstevel@tonic-gate if (sptr != &space.s_d) {
3994522Schinlong (void) munmap((char *)sptr, ndata);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate __s_api_free2dArray(cptr);
4020Sstevel@tonic-gate cptr = NULL;
4030Sstevel@tonic-gate __s_api_free2dArray(mptr);
4040Sstevel@tonic-gate mptr = NULL;
4054522Schinlong __s_api_free_server_info(ret);
4060Sstevel@tonic-gate return (NS_LDAP_MEMORY);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate mcnt++;
4090Sstevel@tonic-gate mptr[mcnt] = NULL;
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate if (strncasecmp(ptr, _SUPPORTEDCONTROL,
4124522Schinlong _SUPPORTEDCONTROL_LEN) == 0) {
4130Sstevel@tonic-gate dptr = strchr(ptr, '=');
4140Sstevel@tonic-gate if (dptr == NULL)
4150Sstevel@tonic-gate continue;
4160Sstevel@tonic-gate dptr++;
4170Sstevel@tonic-gate cptr1 = (char **)realloc((void *)cptr,
4184522Schinlong sizeof (char *) * (ccnt+2));
4190Sstevel@tonic-gate if (cptr1 == NULL) {
4200Sstevel@tonic-gate if (sptr != &space.s_d) {
4214522Schinlong (void) munmap((char *)sptr, ndata);
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate __s_api_free2dArray(cptr);
4240Sstevel@tonic-gate __s_api_free2dArray(mptr);
4250Sstevel@tonic-gate mptr = NULL;
4264522Schinlong __s_api_free_server_info(ret);
4270Sstevel@tonic-gate return (NS_LDAP_MEMORY);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate cptr = cptr1;
4300Sstevel@tonic-gate cptr[ccnt] = strdup(dptr);
4310Sstevel@tonic-gate if (cptr[ccnt] == NULL) {
4320Sstevel@tonic-gate if (sptr != &space.s_d) {
4334522Schinlong (void) munmap((char *)sptr, ndata);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate __s_api_free2dArray(cptr);
4360Sstevel@tonic-gate cptr = NULL;
4370Sstevel@tonic-gate __s_api_free2dArray(mptr);
4380Sstevel@tonic-gate mptr = NULL;
4394522Schinlong __s_api_free_server_info(ret);
4400Sstevel@tonic-gate return (NS_LDAP_MEMORY);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate ccnt++;
4430Sstevel@tonic-gate cptr[ccnt] = NULL;
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate if (mptr != NULL) {
4470Sstevel@tonic-gate ret->saslMechanisms = mptr;
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate if (cptr != NULL) {
4500Sstevel@tonic-gate ret->controls = cptr;
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate /* clean up door call */
4550Sstevel@tonic-gate if (sptr != &space.s_d) {
4560Sstevel@tonic-gate (void) munmap((char *)sptr, ndata);
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate *error = NULL;
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate return (NS_LDAP_SUCCESS);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate
4646842Sth160488 #ifdef DEBUG
4650Sstevel@tonic-gate /*
4660Sstevel@tonic-gate * printCred(): prints the credential structure
4670Sstevel@tonic-gate */
4680Sstevel@tonic-gate static void
printCred(FILE * fp,const ns_cred_t * cred)4696842Sth160488 printCred(FILE *fp, const ns_cred_t *cred)
4700Sstevel@tonic-gate {
4712830Sdjl thread_t t = thr_self();
4722830Sdjl
4730Sstevel@tonic-gate if (cred == NULL) {
4746842Sth160488 (void) fprintf(fp, "tid= %d: printCred: cred is NULL\n", t);
4750Sstevel@tonic-gate return;
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate
4786842Sth160488 (void) fprintf(fp, "tid= %d: AuthType=%d", t, cred->auth.type);
4796842Sth160488 (void) fprintf(fp, "tid= %d: TlsType=%d", t, cred->auth.tlstype);
4806842Sth160488 (void) fprintf(fp, "tid= %d: SaslMech=%d", t, cred->auth.saslmech);
4816842Sth160488 (void) fprintf(fp, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt);
4820Sstevel@tonic-gate if (cred->hostcertpath)
4836842Sth160488 (void) fprintf(fp, "tid= %d: hostCertPath=%s\n",
4844522Schinlong t, cred->hostcertpath);
4850Sstevel@tonic-gate if (cred->cred.unix_cred.userID)
4866842Sth160488 (void) fprintf(fp, "tid= %d: userID=%s\n",
4874522Schinlong t, cred->cred.unix_cred.userID);
4880Sstevel@tonic-gate if (cred->cred.unix_cred.passwd)
4896842Sth160488 (void) fprintf(fp, "tid= %d: passwd=%s\n",
4904522Schinlong t, cred->cred.unix_cred.passwd);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate /*
4940Sstevel@tonic-gate * printConnection(): prints the connection structure
4950Sstevel@tonic-gate */
4960Sstevel@tonic-gate static void
printConnection(FILE * fp,Connection * con)4976842Sth160488 printConnection(FILE *fp, Connection *con)
4980Sstevel@tonic-gate {
4992830Sdjl thread_t t = thr_self();
5002830Sdjl
5012830Sdjl if (con == NULL)
5020Sstevel@tonic-gate return;
5030Sstevel@tonic-gate
5046842Sth160488 (void) fprintf(fp, "tid= %d: connectionID=%d\n", t, con->connectionId);
5056842Sth160488 (void) fprintf(fp, "tid= %d: usedBit=%d\n", t, con->usedBit);
5066842Sth160488 (void) fprintf(fp, "tid= %d: threadID=%d\n", t, con->threadID);
5070Sstevel@tonic-gate if (con->serverAddr) {
5086842Sth160488 (void) fprintf(fp, "tid= %d: serverAddr=%s\n",
5094522Schinlong t, con->serverAddr);
5100Sstevel@tonic-gate }
5116842Sth160488 printCred(fp, con->auth);
5120Sstevel@tonic-gate }
5136842Sth160488 #endif
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate /*
5166842Sth160488 * addConnection(): inserts a connection in the connection list.
5176842Sth160488 * It will also sets use bit and the thread Id for the thread
5186842Sth160488 * using the connection for the first time.
5190Sstevel@tonic-gate * Returns: -1 = failure, new Connection ID = success
5200Sstevel@tonic-gate */
5210Sstevel@tonic-gate static int
addConnection(Connection * con)5220Sstevel@tonic-gate addConnection(Connection *con)
5230Sstevel@tonic-gate {
5246842Sth160488 int i;
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate if (!con)
5270Sstevel@tonic-gate return (-1);
5286842Sth160488 #ifdef DEBUG
5296842Sth160488 (void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID);
5306842Sth160488 #endif /* DEBUG */
5316842Sth160488 (void) mutex_lock(&sessionPoolLock);
5320Sstevel@tonic-gate if (sessionPool == NULL) {
5330Sstevel@tonic-gate sessionPoolSize = SESSION_CACHE_INC;
5340Sstevel@tonic-gate sessionPool = calloc(sessionPoolSize,
5356842Sth160488 sizeof (Connection *));
5360Sstevel@tonic-gate if (!sessionPool) {
5376842Sth160488 (void) mutex_unlock(&sessionPoolLock);
5380Sstevel@tonic-gate return (-1);
5390Sstevel@tonic-gate }
5406842Sth160488 #ifdef DEBUG
5416842Sth160488 (void) fprintf(stderr, "Initialized sessionPool\n");
5426842Sth160488 #endif /* DEBUG */
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i)
5450Sstevel@tonic-gate ;
5460Sstevel@tonic-gate if (i == sessionPoolSize) {
5470Sstevel@tonic-gate /* run out of array, need to increase sessionPool */
5480Sstevel@tonic-gate Connection **cl;
5490Sstevel@tonic-gate cl = (Connection **) realloc(sessionPool,
5504522Schinlong (sessionPoolSize + SESSION_CACHE_INC) *
5514522Schinlong sizeof (Connection *));
5520Sstevel@tonic-gate if (!cl) {
5536842Sth160488 (void) mutex_unlock(&sessionPoolLock);
5540Sstevel@tonic-gate return (-1);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate (void) memset(cl + sessionPoolSize, 0,
5576842Sth160488 SESSION_CACHE_INC * sizeof (Connection *));
5580Sstevel@tonic-gate sessionPool = cl;
5590Sstevel@tonic-gate sessionPoolSize += SESSION_CACHE_INC;
5606842Sth160488 #ifdef DEBUG
5616842Sth160488 (void) fprintf(stderr, "Increased sessionPoolSize to: %d\n",
5626842Sth160488 sessionPoolSize);
5636842Sth160488 #endif /* DEBUG */
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate sessionPool[i] = con;
5666842Sth160488 con->usedBit = B_TRUE;
5676842Sth160488 (void) mutex_unlock(&sessionPoolLock);
5680Sstevel@tonic-gate con->connectionId = i + CONID_OFFSET;
5696842Sth160488 #ifdef DEBUG
5706842Sth160488 (void) fprintf(stderr, "Connection added [%d]\n", i);
5716842Sth160488 printConnection(stderr, con);
5726842Sth160488 #endif /* DEBUG */
5730Sstevel@tonic-gate return (i + CONID_OFFSET);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate /*
5770Sstevel@tonic-gate * findConnection(): find an available connection from the list
5780Sstevel@tonic-gate * that matches the criteria specified in Connection structure.
5790Sstevel@tonic-gate * If serverAddr is NULL, then find a connection to any server
5800Sstevel@tonic-gate * as long as it matches the rest of the parameters.
5810Sstevel@tonic-gate * Returns: -1 = failure, the Connection ID found = success.
5820Sstevel@tonic-gate */
5830Sstevel@tonic-gate static int
findConnection(int flags,const char * serverAddr,const ns_cred_t * auth,Connection ** conp)5842830Sdjl findConnection(int flags, const char *serverAddr,
5852830Sdjl const ns_cred_t *auth, Connection **conp)
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate Connection *cp;
5886842Sth160488 int i;
5892830Sdjl #ifdef DEBUG
5906842Sth160488 thread_t t;
5912830Sdjl #endif /* DEBUG */
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate if (auth == NULL || conp == NULL)
5940Sstevel@tonic-gate return (-1);
5950Sstevel@tonic-gate *conp = NULL;
5960Sstevel@tonic-gate
5975840Smj162486 /*
5985840Smj162486 * If a new connection is requested, no need to continue.
5996842Sth160488 * If the process is not nscd and is not requesting keep
6006842Sth160488 * connections alive, no need to continue.
6015840Smj162486 */
6025840Smj162486 if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() &&
6036072Smj162486 !__s_api_peruser_proc() && !(flags & NS_LDAP_KEEP_CONN)))
6042830Sdjl return (-1);
6052830Sdjl
6060Sstevel@tonic-gate #ifdef DEBUG
6076842Sth160488 t = thr_self();
6082830Sdjl (void) fprintf(stderr, "tid= %d: Find connection\n", t);
6092830Sdjl (void) fprintf(stderr, "tid= %d: Looking for ....\n", t);
6100Sstevel@tonic-gate if (serverAddr && *serverAddr)
6112830Sdjl (void) fprintf(stderr, "tid= %d: serverAddr=%s\n",
6124522Schinlong t, serverAddr);
6130Sstevel@tonic-gate else
6142830Sdjl (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t);
6156842Sth160488 printCred(stderr, auth);
6160Sstevel@tonic-gate fflush(stderr);
6170Sstevel@tonic-gate #endif /* DEBUG */
6186842Sth160488 if (sessionPool == NULL)
6190Sstevel@tonic-gate return (-1);
6206842Sth160488 (void) mutex_lock(&sessionPoolLock);
6210Sstevel@tonic-gate for (i = 0; i < sessionPoolSize; ++i) {
6220Sstevel@tonic-gate if (sessionPool[i] == NULL)
6230Sstevel@tonic-gate continue;
6240Sstevel@tonic-gate cp = sessionPool[i];
6250Sstevel@tonic-gate #ifdef DEBUG
6266842Sth160488 (void) fprintf(stderr,
6276842Sth160488 "tid: %d: checking connection [%d] ....\n", t, i);
6286842Sth160488 printConnection(stderr, cp);
6290Sstevel@tonic-gate #endif /* DEBUG */
6306842Sth160488 if ((cp->usedBit) || (serverAddr && *serverAddr &&
6310Sstevel@tonic-gate (strcasecmp(serverAddr, cp->serverAddr) != 0)))
6320Sstevel@tonic-gate continue;
6334048Schinlong
6346842Sth160488 if (__s_api_is_auth_matched(cp->auth, auth) == B_FALSE)
6356842Sth160488 continue;
6364048Schinlong
6370Sstevel@tonic-gate /* found an available connection */
6386842Sth160488 cp->usedBit = B_TRUE;
6396842Sth160488 (void) mutex_unlock(&sessionPoolLock);
6406842Sth160488 cp->threadID = thr_self();
6410Sstevel@tonic-gate *conp = cp;
6420Sstevel@tonic-gate #ifdef DEBUG
6436842Sth160488 (void) fprintf(stderr,
6446842Sth160488 "tid %d: Connection found cID=%d\n", t, i);
6450Sstevel@tonic-gate fflush(stderr);
6460Sstevel@tonic-gate #endif /* DEBUG */
6470Sstevel@tonic-gate return (i + CONID_OFFSET);
6480Sstevel@tonic-gate }
6496842Sth160488 (void) mutex_unlock(&sessionPoolLock);
6506842Sth160488 return (-1);
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate /*
6540Sstevel@tonic-gate * Free a Connection structure
6550Sstevel@tonic-gate */
6566842Sth160488 void
__s_api_freeConnection(Connection * con)6576842Sth160488 __s_api_freeConnection(Connection *con)
6580Sstevel@tonic-gate {
6590Sstevel@tonic-gate if (con == NULL)
6600Sstevel@tonic-gate return;
6610Sstevel@tonic-gate if (con->serverAddr)
6620Sstevel@tonic-gate free(con->serverAddr);
6630Sstevel@tonic-gate if (con->auth)
6640Sstevel@tonic-gate (void) __ns_ldap_freeCred(&(con->auth));
6650Sstevel@tonic-gate if (con->saslMechanisms) {
6660Sstevel@tonic-gate __s_api_free2dArray(con->saslMechanisms);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate if (con->controls) {
6690Sstevel@tonic-gate __s_api_free2dArray(con->controls);
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate free(con);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate * Find a connection matching the passed in criteria. If an open
6760Sstevel@tonic-gate * connection with that criteria exists use it, otherwise open a
6770Sstevel@tonic-gate * new connection.
6780Sstevel@tonic-gate * Success: returns the pointer to the Connection structure
6790Sstevel@tonic-gate * Failure: returns NULL, error code and message should be in errorp
6800Sstevel@tonic-gate */
6811687Sjanga
6820Sstevel@tonic-gate static int
makeConnection(Connection ** conp,const char * serverAddr,const ns_cred_t * auth,ConnectionID * cID,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int nopasswd_acct_mgmt,int flags,char *** badsrvrs,ns_conn_user_t * conn_user)6830Sstevel@tonic-gate makeConnection(Connection **conp, const char *serverAddr,
6840Sstevel@tonic-gate const ns_cred_t *auth, ConnectionID *cID, int timeoutSec,
6851179Svv149972 ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd,
6866842Sth160488 int nopasswd_acct_mgmt, int flags, char ***badsrvrs,
6876842Sth160488 ns_conn_user_t *conn_user)
6880Sstevel@tonic-gate {
6890Sstevel@tonic-gate Connection *con = NULL;
6900Sstevel@tonic-gate ConnectionID id;
6910Sstevel@tonic-gate char errmsg[MAXERROR];
6920Sstevel@tonic-gate int rc, exit_rc = NS_LDAP_SUCCESS;
6930Sstevel@tonic-gate ns_server_info_t sinfo;
6940Sstevel@tonic-gate char *hReq, *host = NULL;
6950Sstevel@tonic-gate LDAP *ld = NULL;
6960Sstevel@tonic-gate int passwd_mgmt = 0;
6971687Sjanga int totalbad = 0; /* Number of servers contacted unsuccessfully */
6982830Sdjl short memerr = 0; /* Variable for tracking memory allocation */
6994522Schinlong char *serverAddrType = NULL, **bindHost = NULL;
7002830Sdjl
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate if (conp == NULL || errorp == NULL || auth == NULL)
7030Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM);
7040Sstevel@tonic-gate *errorp = NULL;
7050Sstevel@tonic-gate *conp = NULL;
7064522Schinlong (void) memset(&sinfo, 0, sizeof (sinfo));
7070Sstevel@tonic-gate
7086842Sth160488 if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) {
7090Sstevel@tonic-gate /* connection found in cache */
7100Sstevel@tonic-gate #ifdef DEBUG
7112830Sdjl (void) fprintf(stderr, "tid= %d: connection found in "
7124522Schinlong "cache %d\n", thr_self(), id);
7130Sstevel@tonic-gate fflush(stderr);
7140Sstevel@tonic-gate #endif /* DEBUG */
7150Sstevel@tonic-gate *cID = id;
7160Sstevel@tonic-gate *conp = con;
7170Sstevel@tonic-gate return (NS_LDAP_SUCCESS);
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate
7204522Schinlong if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
7212830Sdjl serverAddrType = NS_CACHE_ADDR_HOSTNAME;
7224522Schinlong bindHost = &sinfo.serverFQDN;
7234522Schinlong } else {
7242830Sdjl serverAddrType = NS_CACHE_ADDR_IP;
7254522Schinlong bindHost = &sinfo.server;
7264522Schinlong }
7272830Sdjl
7280Sstevel@tonic-gate if (serverAddr) {
7296842Sth160488 if (__s_api_isInitializing()) {
7306842Sth160488 /*
7316842Sth160488 * When obtaining the root DSE, connect to the server
7326842Sth160488 * passed here through the serverAddr parameter
7336842Sth160488 */
7346842Sth160488 sinfo.server = strdup(serverAddr);
7356842Sth160488 if (sinfo.server == NULL)
7365559Ssdussud return (NS_LDAP_MEMORY);
7376842Sth160488 if (strcmp(serverAddrType,
7386842Sth160488 NS_CACHE_ADDR_HOSTNAME) == 0) {
7396842Sth160488 rc = __s_api_ip2hostname(sinfo.server,
7406842Sth160488 &sinfo.serverFQDN);
7416842Sth160488 if (rc != NS_LDAP_SUCCESS) {
7426842Sth160488 (void) snprintf(errmsg,
7436842Sth160488 sizeof (errmsg),
7446842Sth160488 gettext("The %s address "
7456842Sth160488 "can not be resolved into "
7466842Sth160488 "a host name. Returning "
7476842Sth160488 "the address as it is."),
7486842Sth160488 serverAddr);
7496842Sth160488 MKERROR(LOG_ERR,
7506842Sth160488 *errorp,
7516842Sth160488 NS_CONFIG_NOTLOADED,
7526842Sth160488 strdup(errmsg),
7536842Sth160488 NS_LDAP_MEMORY);
7546842Sth160488 __s_api_free_server_info(&sinfo);
7556842Sth160488 return (NS_LDAP_INTERNAL);
7566842Sth160488 }
7576842Sth160488 }
7586842Sth160488 } else {
7596842Sth160488 /*
7606842Sth160488 * We're given the server address, just use it.
7616842Sth160488 * In case of sasl/GSSAPI, serverAddr would need
7626842Sth160488 * to be a FQDN. We assume this is the case for now.
7636842Sth160488 *
7646842Sth160488 * Only the server address fields of sinfo structure
7656842Sth160488 * are filled in since these are the only relevant
7666842Sth160488 * data that we have. Other fields of this structure
7676842Sth160488 * (controls, saslMechanisms) are kept to NULL.
7686842Sth160488 */
7696842Sth160488 sinfo.server = strdup(serverAddr);
7706842Sth160488 if (sinfo.server == NULL) {
7716842Sth160488 return (NS_LDAP_MEMORY);
7726842Sth160488 }
7736842Sth160488 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
7746842Sth160488 sinfo.serverFQDN = strdup(serverAddr);
7756842Sth160488 if (sinfo.serverFQDN == NULL) {
7766842Sth160488 free(sinfo.server);
7776842Sth160488 return (NS_LDAP_MEMORY);
7786842Sth160488 }
7795559Ssdussud }
7802830Sdjl }
7814522Schinlong rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp,
782*12969SJulian.Pullen@Sun.COM fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags);
7830Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS || rc ==
7844522Schinlong NS_LDAP_SUCCESS_WITH_INFO) {
7850Sstevel@tonic-gate exit_rc = rc;
7860Sstevel@tonic-gate goto create_con;
7870Sstevel@tonic-gate } else {
7885559Ssdussud if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
7895559Ssdussud (void) snprintf(errmsg, sizeof (errmsg),
7905559Ssdussud "%s %s", gettext("makeConnection: "
7915559Ssdussud "failed to open connection using "
7925559Ssdussud "sasl/GSSAPI to"), *bindHost);
7935559Ssdussud } else {
7945559Ssdussud (void) snprintf(errmsg, sizeof (errmsg),
7955559Ssdussud "%s %s", gettext("makeConnection: "
7965559Ssdussud "failed to open connection to"),
7975559Ssdussud *bindHost);
7985559Ssdussud }
7995559Ssdussud syslog(LOG_ERR, "libsldap: %s", errmsg);
8005559Ssdussud __s_api_free_server_info(&sinfo);
8010Sstevel@tonic-gate return (rc);
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate /* No cached connection, create one */
8060Sstevel@tonic-gate for (; ; ) {
8070Sstevel@tonic-gate if (host == NULL)
8080Sstevel@tonic-gate hReq = NS_CACHE_NEW;
8090Sstevel@tonic-gate else
8100Sstevel@tonic-gate hReq = NS_CACHE_NEXT;
8112830Sdjl rc = __s_api_requestServer(hReq, host, &sinfo, errorp,
8124522Schinlong serverAddrType);
8130Sstevel@tonic-gate if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) ||
8144522Schinlong (host && (strcasecmp(host, sinfo.server) == 0))) {
8150Sstevel@tonic-gate /* Log the error */
8160Sstevel@tonic-gate if (*errorp) {
8170Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg),
8180Sstevel@tonic-gate "%s: (%s)", gettext("makeConnection: "
8190Sstevel@tonic-gate "unable to make LDAP connection, "
8200Sstevel@tonic-gate "request for a server failed"),
8210Sstevel@tonic-gate (*errorp)->message);
8220Sstevel@tonic-gate syslog(LOG_ERR, "libsldap: %s", errmsg);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate
8254522Schinlong __s_api_free_server_info(&sinfo);
8260Sstevel@tonic-gate if (host)
8270Sstevel@tonic-gate free(host);
8280Sstevel@tonic-gate return (NS_LDAP_OP_FAILED);
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate if (host)
8310Sstevel@tonic-gate free(host);
8320Sstevel@tonic-gate host = strdup(sinfo.server);
8330Sstevel@tonic-gate if (host == NULL) {
8344522Schinlong __s_api_free_server_info(&sinfo);
8350Sstevel@tonic-gate return (NS_LDAP_MEMORY);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate
8380Sstevel@tonic-gate /* check if server supports password management */
8390Sstevel@tonic-gate passwd_mgmt = __s_api_contain_passwd_control_oid(
8404522Schinlong sinfo.controls);
8411179Svv149972 /* check if server supports password less account mgmt */
8421179Svv149972 if (nopasswd_acct_mgmt &&
8434522Schinlong !__s_api_contain_account_usable_control_oid(
8444522Schinlong sinfo.controls)) {
8451179Svv149972 syslog(LOG_WARNING, "libsldap: server %s does not "
8464522Schinlong "provide account information without password",
8474522Schinlong host);
8481179Svv149972 free(host);
8494522Schinlong __s_api_free_server_info(&sinfo);
8501179Svv149972 return (NS_LDAP_OP_FAILED);
8511179Svv149972 }
8520Sstevel@tonic-gate /* make the connection */
8534522Schinlong rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp,
854*12969SJulian.Pullen@Sun.COM fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags);
8550Sstevel@tonic-gate /* if success, go to create connection structure */
8560Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS ||
8574522Schinlong rc == NS_LDAP_SUCCESS_WITH_INFO) {
8580Sstevel@tonic-gate exit_rc = rc;
8590Sstevel@tonic-gate break;
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate /*
8630Sstevel@tonic-gate * If not able to reach the server, inform the ldap
8640Sstevel@tonic-gate * cache manager that the server should be removed
8650Sstevel@tonic-gate * from its server list. Thus, the manager will not
8660Sstevel@tonic-gate * return this server on the next get-server request
8670Sstevel@tonic-gate * and will also reduce the server list refresh TTL,
8680Sstevel@tonic-gate * so that it will find out sooner when the server
8690Sstevel@tonic-gate * is up again.
8700Sstevel@tonic-gate */
8710Sstevel@tonic-gate if (rc == NS_LDAP_INTERNAL && *errorp != NULL) {
8720Sstevel@tonic-gate if ((*errorp)->status == LDAP_CONNECT_ERROR ||
8734522Schinlong (*errorp)->status == LDAP_SERVER_DOWN) {
8741687Sjanga /* Reset memory allocation error */
8751687Sjanga memerr = 0;
8761687Sjanga /*
8771687Sjanga * We contacted a server that we could
8781687Sjanga * not either authenticate to or contact.
8791687Sjanga * If it is due to authentication, then
8801687Sjanga * we need to try the server again. So,
8811687Sjanga * do not remove the server yet, but
8821687Sjanga * add it to the bad server list.
8831687Sjanga * The caller routine will remove
8841687Sjanga * the servers if:
8851687Sjanga * a). A good server is found or
8861687Sjanga * b). All the possible methods
8871687Sjanga * are tried without finding
8881687Sjanga * a good server
8891687Sjanga */
8901687Sjanga if (*badsrvrs == NULL) {
8914522Schinlong if (!(*badsrvrs = (char **)malloc
8924522Schinlong (sizeof (char *) * NUMTOMALLOC))) {
8934522Schinlong memerr = 1;
8944522Schinlong }
8951687Sjanga /* Allocate memory in chunks of NUMTOMALLOC */
8961687Sjanga } else if ((totalbad % NUMTOMALLOC) ==
8974522Schinlong NUMTOMALLOC - 1) {
8984522Schinlong char **tmpptr;
8994522Schinlong if (!(tmpptr = (char **)realloc(
9004522Schinlong *badsrvrs,
9011687Sjanga (sizeof (char *) * NUMTOMALLOC *
9021687Sjanga ((totalbad/NUMTOMALLOC) + 2))))) {
9034522Schinlong memerr = 1;
9044522Schinlong } else {
9054522Schinlong *badsrvrs = tmpptr;
9064522Schinlong }
907493Ssdussud }
9081687Sjanga /*
9091687Sjanga * Store host only if there were no unsuccessful
9101687Sjanga * memory allocations above
9111687Sjanga */
9121687Sjanga if (!memerr &&
9131687Sjanga !((*badsrvrs)[totalbad++] = strdup(host))) {
9141687Sjanga memerr = 1;
9151687Sjanga totalbad--;
9161687Sjanga }
9171687Sjanga (*badsrvrs)[totalbad] = NULL;
918493Ssdussud }
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate /* else, cleanup and go for the next server */
9224522Schinlong __s_api_free_server_info(&sinfo);
9234522Schinlong
9241687Sjanga /* Return if we had memory allocation errors */
9251687Sjanga if (memerr)
9261687Sjanga return (NS_LDAP_MEMORY);
9270Sstevel@tonic-gate if (*errorp) {
9280Sstevel@tonic-gate /*
9290Sstevel@tonic-gate * If openConnection() failed due to
9300Sstevel@tonic-gate * password policy, or invalid credential,
9310Sstevel@tonic-gate * keep *errorp and exit
9320Sstevel@tonic-gate */
9330Sstevel@tonic-gate if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD ||
9340Sstevel@tonic-gate (*errorp)->status == LDAP_INVALID_CREDENTIALS) {
9350Sstevel@tonic-gate free(host);
9360Sstevel@tonic-gate return (rc);
9370Sstevel@tonic-gate } else {
9380Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp);
9390Sstevel@tonic-gate *errorp = NULL;
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate create_con:
9450Sstevel@tonic-gate /* we have created ld, setup con structure */
9460Sstevel@tonic-gate if (host)
9470Sstevel@tonic-gate free(host);
9480Sstevel@tonic-gate if ((con = calloc(1, sizeof (Connection))) == NULL) {
9494522Schinlong __s_api_free_server_info(&sinfo);
9500Sstevel@tonic-gate /*
9510Sstevel@tonic-gate * If password control attached in **errorp,
9520Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
9530Sstevel@tonic-gate * free the error structure
9540Sstevel@tonic-gate */
9550Sstevel@tonic-gate if (*errorp) {
9560Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp);
9570Sstevel@tonic-gate *errorp = NULL;
9580Sstevel@tonic-gate }
9595559Ssdussud (void) ldap_unbind(ld);
9600Sstevel@tonic-gate return (NS_LDAP_MEMORY);
9610Sstevel@tonic-gate }
9620Sstevel@tonic-gate
9634522Schinlong con->serverAddr = sinfo.server; /* Store original format */
9644522Schinlong if (sinfo.serverFQDN != NULL) {
9654522Schinlong free(sinfo.serverFQDN);
9664522Schinlong sinfo.serverFQDN = NULL;
9674522Schinlong }
9680Sstevel@tonic-gate con->saslMechanisms = sinfo.saslMechanisms;
9690Sstevel@tonic-gate con->controls = sinfo.controls;
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate con->auth = __ns_ldap_dupAuth(auth);
9720Sstevel@tonic-gate if (con->auth == NULL) {
9735559Ssdussud (void) ldap_unbind(ld);
9746842Sth160488 __s_api_freeConnection(con);
9750Sstevel@tonic-gate /*
9760Sstevel@tonic-gate * If password control attached in **errorp,
9770Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
9780Sstevel@tonic-gate * free the error structure
9790Sstevel@tonic-gate */
9800Sstevel@tonic-gate if (*errorp) {
9810Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp);
9820Sstevel@tonic-gate *errorp = NULL;
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate return (NS_LDAP_MEMORY);
9850Sstevel@tonic-gate }
9860Sstevel@tonic-gate
9870Sstevel@tonic-gate con->threadID = thr_self();
9883387Schinlong con->pid = getpid();
9892830Sdjl
9900Sstevel@tonic-gate con->ld = ld;
9916842Sth160488 /* add MT connection to the MT connection pool */
9926842Sth160488 if (conn_user != NULL && conn_user->conn_mt != NULL) {
9936842Sth160488 if (__s_api_conn_mt_add(con, conn_user, errorp) ==
9946842Sth160488 NS_LDAP_SUCCESS) {
9956842Sth160488 *conp = con;
9966842Sth160488 return (exit_rc);
9976842Sth160488 } else {
9986842Sth160488 (void) ldap_unbind(ld);
9996842Sth160488 __s_api_freeConnection(con);
10006842Sth160488 return ((*errorp)->status);
10016842Sth160488 }
10026842Sth160488 }
10036842Sth160488
10046842Sth160488 /* MT connection not supported or not required case */
10050Sstevel@tonic-gate if ((id = addConnection(con)) == -1) {
10065559Ssdussud (void) ldap_unbind(ld);
10076842Sth160488 __s_api_freeConnection(con);
10080Sstevel@tonic-gate /*
10090Sstevel@tonic-gate * If password control attached in **errorp,
10100Sstevel@tonic-gate * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
10110Sstevel@tonic-gate * free the error structure
10120Sstevel@tonic-gate */
10130Sstevel@tonic-gate if (*errorp) {
10140Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp);
10150Sstevel@tonic-gate *errorp = NULL;
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate return (NS_LDAP_MEMORY);
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate #ifdef DEBUG
10202830Sdjl (void) fprintf(stderr, "tid= %d: connection added into "
10214522Schinlong "cache %d\n", thr_self(), id);
10220Sstevel@tonic-gate fflush(stderr);
10230Sstevel@tonic-gate #endif /* DEBUG */
10240Sstevel@tonic-gate *cID = id;
10250Sstevel@tonic-gate *conp = con;
10260Sstevel@tonic-gate return (exit_rc);
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate /*
10300Sstevel@tonic-gate * Return the specified connection to the pool. If necessary
10310Sstevel@tonic-gate * delete the connection.
10320Sstevel@tonic-gate */
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate static void
_DropConnection(ConnectionID cID,int flag,int fini)10350Sstevel@tonic-gate _DropConnection(ConnectionID cID, int flag, int fini)
10360Sstevel@tonic-gate {
10370Sstevel@tonic-gate Connection *cp;
10380Sstevel@tonic-gate int id;
10396842Sth160488 int use_mutex = !fini;
10406722Smj162486 struct timeval zerotime;
10416722Smj162486 LDAPMessage *res;
10426722Smj162486
10436722Smj162486 zerotime.tv_sec = zerotime.tv_usec = 0L;
10446722Smj162486
10450Sstevel@tonic-gate id = cID - CONID_OFFSET;
10460Sstevel@tonic-gate if (id < 0 || id >= sessionPoolSize)
10470Sstevel@tonic-gate return;
10480Sstevel@tonic-gate #ifdef DEBUG
10496842Sth160488 (void) fprintf(stderr,
10506842Sth160488 "tid %d: Dropping connection cID=%d flag=0x%x\n",
10516842Sth160488 thr_self(), cID, flag);
10520Sstevel@tonic-gate fflush(stderr);
10530Sstevel@tonic-gate #endif /* DEBUG */
10546842Sth160488 if (use_mutex)
10556842Sth160488 (void) mutex_lock(&sessionPoolLock);
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate cp = sessionPool[id];
10580Sstevel@tonic-gate /* sanity check before removing */
10596842Sth160488 if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) {
10606842Sth160488 if (use_mutex)
10616842Sth160488 (void) mutex_unlock(&sessionPoolLock);
10620Sstevel@tonic-gate return;
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate if (!fini &&
10666842Sth160488 ((flag & NS_LDAP_NEW_CONN) == 0) &&
10676072Smj162486 ((flag & NS_LDAP_KEEP_CONN) || __s_api_nscd_proc() ||
10686072Smj162486 __s_api_peruser_proc())) {
10690Sstevel@tonic-gate /* release Connection (keep alive) */
10700Sstevel@tonic-gate cp->usedBit = B_FALSE;
10710Sstevel@tonic-gate cp->threadID = 0; /* unmark the threadID */
10726722Smj162486 /*
10736842Sth160488 * Do sanity cleanup of remaining results.
10746722Smj162486 */
10756842Sth160488 while (ldap_result(cp->ld, LDAP_RES_ANY, LDAP_MSG_ALL,
10766842Sth160488 &zerotime, &res) > 0) {
10776842Sth160488 if (res != NULL)
10786842Sth160488 (void) ldap_msgfree(res);
10796722Smj162486 }
10806842Sth160488 if (use_mutex)
10816842Sth160488 (void) mutex_unlock(&sessionPoolLock);
10820Sstevel@tonic-gate } else {
10830Sstevel@tonic-gate /* delete Connection (disconnect) */
10846842Sth160488 sessionPool[id] = NULL;
10856842Sth160488 if (use_mutex)
10866842Sth160488 (void) mutex_unlock(&sessionPoolLock);
10876842Sth160488 (void) ldap_unbind(cp->ld);
10886842Sth160488 __s_api_freeConnection(cp);
10890Sstevel@tonic-gate }
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate void
DropConnection(ConnectionID cID,int flag)10930Sstevel@tonic-gate DropConnection(ConnectionID cID, int flag)
10940Sstevel@tonic-gate {
10950Sstevel@tonic-gate _DropConnection(cID, flag, 0);
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate
10980Sstevel@tonic-gate /*
10990Sstevel@tonic-gate * This routine is called after a bind operation is
11000Sstevel@tonic-gate * done in openConnection() to process the password
11010Sstevel@tonic-gate * management information, if any.
11020Sstevel@tonic-gate *
11030Sstevel@tonic-gate * Input:
11040Sstevel@tonic-gate * bind_type: "simple" or "sasl/DIGEST-MD5"
11050Sstevel@tonic-gate * ldaprc : ldap rc from the ldap bind operation
11060Sstevel@tonic-gate * controls : controls returned by the server
11070Sstevel@tonic-gate * errmsg : error message from the server
11080Sstevel@tonic-gate * fail_if_new_pwd_reqd:
11090Sstevel@tonic-gate * flag indicating if connection should be open
11100Sstevel@tonic-gate * when password needs to change immediately
11110Sstevel@tonic-gate * passwd_mgmt:
11120Sstevel@tonic-gate * flag indicating if server supports password
11130Sstevel@tonic-gate * policy/management
11140Sstevel@tonic-gate *
11150Sstevel@tonic-gate * Output : ns_ldap_error structure, which may contain
11160Sstevel@tonic-gate * password status and number of seconds until
11170Sstevel@tonic-gate * expired
11180Sstevel@tonic-gate *
11190Sstevel@tonic-gate * return rc:
11200Sstevel@tonic-gate * NS_LDAP_EXTERNAL: error, connection should not open
11210Sstevel@tonic-gate * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached
11220Sstevel@tonic-gate * NS_LDAP_SUCCESS: OK to open connection
11230Sstevel@tonic-gate *
11240Sstevel@tonic-gate */
11250Sstevel@tonic-gate
11260Sstevel@tonic-gate static int
process_pwd_mgmt(char * bind_type,int ldaprc,LDAPControl ** controls,char * errmsg,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt)11270Sstevel@tonic-gate process_pwd_mgmt(char *bind_type, int ldaprc,
11280Sstevel@tonic-gate LDAPControl **controls,
11290Sstevel@tonic-gate char *errmsg, ns_ldap_error_t **errorp,
11300Sstevel@tonic-gate int fail_if_new_pwd_reqd,
11310Sstevel@tonic-gate int passwd_mgmt)
11320Sstevel@tonic-gate {
11330Sstevel@tonic-gate char errstr[MAXERROR];
11340Sstevel@tonic-gate LDAPControl **ctrl = NULL;
11350Sstevel@tonic-gate int exit_rc;
11360Sstevel@tonic-gate ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD;
11370Sstevel@tonic-gate int sec_until_exp = 0;
11380Sstevel@tonic-gate
11390Sstevel@tonic-gate /*
11400Sstevel@tonic-gate * errmsg may be an empty string,
11410Sstevel@tonic-gate * even if ldaprc is LDAP_SUCCESS,
11420Sstevel@tonic-gate * free the empty string if that's the case
11430Sstevel@tonic-gate */
11440Sstevel@tonic-gate if (errmsg &&
11454522Schinlong (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) {
11460Sstevel@tonic-gate ldap_memfree(errmsg);
11470Sstevel@tonic-gate errmsg = NULL;
11480Sstevel@tonic-gate }
11490Sstevel@tonic-gate
11500Sstevel@tonic-gate if (ldaprc != LDAP_SUCCESS) {
11510Sstevel@tonic-gate /*
11520Sstevel@tonic-gate * try to map ldap rc and error message to
11530Sstevel@tonic-gate * a password status
11540Sstevel@tonic-gate */
11550Sstevel@tonic-gate if (errmsg) {
11560Sstevel@tonic-gate if (passwd_mgmt)
11570Sstevel@tonic-gate pwd_status =
11584522Schinlong __s_api_set_passwd_status(
11594522Schinlong ldaprc, errmsg);
11600Sstevel@tonic-gate ldap_memfree(errmsg);
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate
11630Sstevel@tonic-gate (void) snprintf(errstr, sizeof (errstr),
11644522Schinlong gettext("openConnection: "
11654522Schinlong "%s bind failed "
11664522Schinlong "- %s"), bind_type, ldap_err2string(ldaprc));
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate if (pwd_status != NS_PASSWD_GOOD) {
11690Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp,
11704522Schinlong ldaprc, strdup(errstr),
11714522Schinlong pwd_status, 0, NULL);
11720Sstevel@tonic-gate } else {
11730Sstevel@tonic-gate MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr),
11746842Sth160488 NS_LDAP_MEMORY);
11750Sstevel@tonic-gate }
11760Sstevel@tonic-gate if (controls)
11770Sstevel@tonic-gate ldap_controls_free(controls);
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate return (NS_LDAP_INTERNAL);
11800Sstevel@tonic-gate }
11810Sstevel@tonic-gate
11820Sstevel@tonic-gate /*
11830Sstevel@tonic-gate * ldaprc is LDAP_SUCCESS,
11840Sstevel@tonic-gate * process the password management controls, if any
11850Sstevel@tonic-gate */
11860Sstevel@tonic-gate exit_rc = NS_LDAP_SUCCESS;
11870Sstevel@tonic-gate if (controls && passwd_mgmt) {
11880Sstevel@tonic-gate /*
11890Sstevel@tonic-gate * The control with the OID
11900Sstevel@tonic-gate * 2.16.840.1.113730.3.4.4 (or
11910Sstevel@tonic-gate * LDAP_CONTROL_PWEXPIRED, as defined
11920Sstevel@tonic-gate * in the ldap.h header file) is the
11930Sstevel@tonic-gate * expired password control.
11940Sstevel@tonic-gate *
11950Sstevel@tonic-gate * This control is used if the server
11960Sstevel@tonic-gate * is configured to require users to
11970Sstevel@tonic-gate * change their passwords when first
11980Sstevel@tonic-gate * logging in and whenever the
11990Sstevel@tonic-gate * passwords are reset.
12000Sstevel@tonic-gate *
12010Sstevel@tonic-gate * If the user is logging in for the
12020Sstevel@tonic-gate * first time or if the user's
12030Sstevel@tonic-gate * password has been reset, the
12040Sstevel@tonic-gate * server sends this control to
12050Sstevel@tonic-gate * indicate that the client needs to
12060Sstevel@tonic-gate * change the password immediately.
12070Sstevel@tonic-gate *
12080Sstevel@tonic-gate * At this point, the only operation
12090Sstevel@tonic-gate * that the client can perform is to
12100Sstevel@tonic-gate * change the user's password. If the
12110Sstevel@tonic-gate * client requests any other LDAP
12120Sstevel@tonic-gate * operation, the server sends back
12130Sstevel@tonic-gate * an LDAP_UNWILLING_TO_PERFORM
12140Sstevel@tonic-gate * result code with an expired
12150Sstevel@tonic-gate * password control.
12160Sstevel@tonic-gate *
12170Sstevel@tonic-gate * The control with the OID
12180Sstevel@tonic-gate * 2.16.840.1.113730.3.4.5 (or
12190Sstevel@tonic-gate * LDAP_CONTROL_PWEXPIRING, as
12200Sstevel@tonic-gate * defined in the ldap.h header file)
12210Sstevel@tonic-gate * is the password expiration warning
12220Sstevel@tonic-gate * control.
12230Sstevel@tonic-gate *
12240Sstevel@tonic-gate * This control is used if the server
12250Sstevel@tonic-gate * is configured to expire user
12260Sstevel@tonic-gate * passwords after a certain amount
12270Sstevel@tonic-gate * of time.
12280Sstevel@tonic-gate *
12290Sstevel@tonic-gate * The server sends this control back
12300Sstevel@tonic-gate * to the client if the client binds
12310Sstevel@tonic-gate * using a password that will soon
12320Sstevel@tonic-gate * expire. The ldctl_value field of
12330Sstevel@tonic-gate * the LDAPControl structure
12340Sstevel@tonic-gate * specifies the number of seconds
12350Sstevel@tonic-gate * before the password will expire.
12360Sstevel@tonic-gate */
12370Sstevel@tonic-gate for (ctrl = controls; *ctrl; ctrl++) {
12380Sstevel@tonic-gate
12390Sstevel@tonic-gate if (strcmp((*ctrl)->ldctl_oid,
12404522Schinlong LDAP_CONTROL_PWEXPIRED) == 0) {
12410Sstevel@tonic-gate /*
12420Sstevel@tonic-gate * if the caller wants this bind
12430Sstevel@tonic-gate * to fail, set up the error info.
12440Sstevel@tonic-gate * If call to this function is
12450Sstevel@tonic-gate * for searching the LDAP directory,
12460Sstevel@tonic-gate * e.g., __ns_ldap_list(),
12470Sstevel@tonic-gate * there's really no sense to
12480Sstevel@tonic-gate * let a connection open and
12490Sstevel@tonic-gate * then fail immediately afterward
12500Sstevel@tonic-gate * on the LDAP search operation with
12510Sstevel@tonic-gate * the LDAP_UNWILLING_TO_PERFORM rc
12520Sstevel@tonic-gate */
12530Sstevel@tonic-gate pwd_status =
12544522Schinlong NS_PASSWD_CHANGE_NEEDED;
12550Sstevel@tonic-gate if (fail_if_new_pwd_reqd) {
12560Sstevel@tonic-gate (void) snprintf(errstr,
12574522Schinlong sizeof (errstr),
12584522Schinlong gettext(
12594522Schinlong "openConnection: "
12604522Schinlong "%s bind "
12614522Schinlong "failed "
12624522Schinlong "- password "
12634522Schinlong "expired. It "
12644522Schinlong " needs to change "
12654522Schinlong "immediately!"),
12664522Schinlong bind_type);
12670Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp,
12684522Schinlong LDAP_SUCCESS,
12694522Schinlong strdup(errstr),
12704522Schinlong pwd_status,
12714522Schinlong 0,
12724522Schinlong NULL);
12730Sstevel@tonic-gate exit_rc = NS_LDAP_INTERNAL;
12740Sstevel@tonic-gate } else {
12750Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp,
12764522Schinlong LDAP_SUCCESS,
12774522Schinlong NULL,
12784522Schinlong pwd_status,
12794522Schinlong 0,
12804522Schinlong NULL);
12810Sstevel@tonic-gate exit_rc =
12824522Schinlong NS_LDAP_SUCCESS_WITH_INFO;
12830Sstevel@tonic-gate }
12840Sstevel@tonic-gate break;
12850Sstevel@tonic-gate } else if (strcmp((*ctrl)->ldctl_oid,
12864522Schinlong LDAP_CONTROL_PWEXPIRING) == 0) {
12870Sstevel@tonic-gate pwd_status =
12884522Schinlong NS_PASSWD_ABOUT_TO_EXPIRE;
12890Sstevel@tonic-gate if ((*ctrl)->
12904522Schinlong ldctl_value.bv_len > 0 &&
12914522Schinlong (*ctrl)->
12924522Schinlong ldctl_value.bv_val)
12930Sstevel@tonic-gate sec_until_exp =
12944522Schinlong atoi((*ctrl)->
12954522Schinlong ldctl_value.bv_val);
12960Sstevel@tonic-gate MKERROR_PWD_MGMT(*errorp,
12974522Schinlong LDAP_SUCCESS,
12984522Schinlong NULL,
12994522Schinlong pwd_status,
13004522Schinlong sec_until_exp,
13014522Schinlong NULL);
13020Sstevel@tonic-gate exit_rc =
13034522Schinlong NS_LDAP_SUCCESS_WITH_INFO;
13040Sstevel@tonic-gate break;
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate }
13070Sstevel@tonic-gate }
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate if (controls)
13100Sstevel@tonic-gate ldap_controls_free(controls);
13110Sstevel@tonic-gate
13120Sstevel@tonic-gate return (exit_rc);
13130Sstevel@tonic-gate }
13140Sstevel@tonic-gate
13150Sstevel@tonic-gate static int
ldap_in_nss_switch(char * db)13166842Sth160488 ldap_in_nss_switch(char *db)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate enum __nsw_parse_err pserr;
13190Sstevel@tonic-gate struct __nsw_switchconfig *conf;
13200Sstevel@tonic-gate struct __nsw_lookup *lkp;
13210Sstevel@tonic-gate const char *name;
13220Sstevel@tonic-gate int found = 0;
13230Sstevel@tonic-gate
13246842Sth160488 conf = __nsw_getconfig(db, &pserr);
13250Sstevel@tonic-gate if (conf == NULL) {
13260Sstevel@tonic-gate return (-1);
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate /* check for skip and count other backends */
13300Sstevel@tonic-gate for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
13310Sstevel@tonic-gate name = lkp->service_name;
13320Sstevel@tonic-gate if (strcmp(name, "ldap") == 0) {
13330Sstevel@tonic-gate found = 1;
13340Sstevel@tonic-gate break;
13350Sstevel@tonic-gate }
13360Sstevel@tonic-gate }
133711411SSurya.Prakki@Sun.COM (void) __nsw_freeconfig(conf);
13380Sstevel@tonic-gate return (found);
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate
13410Sstevel@tonic-gate static int
openConnection(LDAP ** ldp,const char * serverAddr,const ns_cred_t * auth,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt,ns_conn_user_t * conn_user,int flags)13420Sstevel@tonic-gate openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
13430Sstevel@tonic-gate int timeoutSec, ns_ldap_error_t **errorp,
13446842Sth160488 int fail_if_new_pwd_reqd, int passwd_mgmt,
1345*12969SJulian.Pullen@Sun.COM ns_conn_user_t *conn_user, int flags)
13460Sstevel@tonic-gate {
13476842Sth160488 LDAP *ld = NULL;
13486842Sth160488 int ldapVersion = LDAP_VERSION3;
13496842Sth160488 int derefOption = LDAP_DEREF_ALWAYS;
13506842Sth160488 int zero = 0;
13516842Sth160488 int timeoutMilliSec = timeoutSec * 1000;
13526842Sth160488 uint16_t port = USE_DEFAULT_PORT;
13536842Sth160488 char *s;
13546842Sth160488 char errstr[MAXERROR];
1355*12969SJulian.Pullen@Sun.COM int followRef;
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 /*
1410*12969SJulian.Pullen@Sun.COM * This library will handle the referral itself based on API flags or
1411*12969SJulian.Pullen@Sun.COM * configuration file specification. The LDAP bind operation is an
1412*12969SJulian.Pullen@Sun.COM * exception where we rely on the LDAP library to follow the referal.
1413*12969SJulian.Pullen@Sun.COM *
1414*12969SJulian.Pullen@Sun.COM * The LDAP follow referral option must be set to OFF for the libldap5
1415*12969SJulian.Pullen@Sun.COM * to pass the referral info up to this library. This option MUST be
1416*12969SJulian.Pullen@Sun.COM * set to OFF after we have performed a sucessful bind. If we are not
1417*12969SJulian.Pullen@Sun.COM * to follow referrals we MUST also set the LDAP follow referral option
1418*12969SJulian.Pullen@Sun.COM * to OFF before we perform an LDAP bind.
14190Sstevel@tonic-gate */
1420*12969SJulian.Pullen@Sun.COM ret_code = __s_api_toFollowReferrals(flags, &followRef, errorp);
1421*12969SJulian.Pullen@Sun.COM if (ret_code != NS_LDAP_SUCCESS) {
1422*12969SJulian.Pullen@Sun.COM (void) ldap_unbind(ld);
1423*12969SJulian.Pullen@Sun.COM return (ret_code);
1424*12969SJulian.Pullen@Sun.COM }
1425*12969SJulian.Pullen@Sun.COM
1426*12969SJulian.Pullen@Sun.COM if (followRef)
1427*12969SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
1428*12969SJulian.Pullen@Sun.COM else
1429*12969SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1430*12969SJulian.Pullen@Sun.COM
14310Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero);
14320Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero);
14330Sstevel@tonic-gate /* setup TCP/IP connect timeout */
14340Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT,
14354522Schinlong &timeoutMilliSec);
14360Sstevel@tonic-gate /* retry if LDAP I/O was interrupted */
14370Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
14380Sstevel@tonic-gate
14396842Sth160488 ret_code = performBind(auth,
14406842Sth160488 ld,
14416842Sth160488 timeoutSec,
14426842Sth160488 errorp,
14436842Sth160488 fail_if_new_pwd_reqd,
14446842Sth160488 passwd_mgmt);
14450Sstevel@tonic-gate
14466842Sth160488 if (ret_code == NS_LDAP_SUCCESS ||
14476842Sth160488 ret_code == NS_LDAP_SUCCESS_WITH_INFO) {
1448*12969SJulian.Pullen@Sun.COM /*
1449*12969SJulian.Pullen@Sun.COM * Turn off LDAP referral following so that this library can
1450*12969SJulian.Pullen@Sun.COM * process referrals.
1451*12969SJulian.Pullen@Sun.COM */
1452*12969SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
14536842Sth160488 *ldp = ld;
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate
14566842Sth160488 return (ret_code);
14570Sstevel@tonic-gate }
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate /*
14600Sstevel@tonic-gate * FUNCTION: __s_api_getDefaultAuth
14610Sstevel@tonic-gate *
14620Sstevel@tonic-gate * Constructs a credential for authentication using the config module.
14630Sstevel@tonic-gate *
14640Sstevel@tonic-gate * RETURN VALUES:
14650Sstevel@tonic-gate *
14660Sstevel@tonic-gate * NS_LDAP_SUCCESS If successful
14670Sstevel@tonic-gate * NS_LDAP_CONFIG If there are any config errors.
14680Sstevel@tonic-gate * NS_LDAP_MEMORY Memory errors.
14690Sstevel@tonic-gate * NS_LDAP_OP_FAILED If there are no more authentication methods so can
14700Sstevel@tonic-gate * not build a new authp.
14710Sstevel@tonic-gate * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the
14720Sstevel@tonic-gate * necessary fields of a cred for a given auth method
14730Sstevel@tonic-gate * are not provided.
14740Sstevel@tonic-gate * INPUT:
14750Sstevel@tonic-gate *
14760Sstevel@tonic-gate * cLevel Currently requested credential level to be tried
14770Sstevel@tonic-gate *
14780Sstevel@tonic-gate * aMethod Currently requested authentication method to be tried
14790Sstevel@tonic-gate *
14809576SJulian.Pullen@Sun.COM * getAdmin If non 0, get Admin -i.e., not proxyAgent- DN and password
14819576SJulian.Pullen@Sun.COM *
14820Sstevel@tonic-gate * OUTPUT:
14830Sstevel@tonic-gate *
14840Sstevel@tonic-gate * authp authentication method to use.
14850Sstevel@tonic-gate */
14860Sstevel@tonic-gate static int
__s_api_getDefaultAuth(int * cLevel,ns_auth_t * aMethod,ns_cred_t ** authp,int getAdmin)14870Sstevel@tonic-gate __s_api_getDefaultAuth(
14880Sstevel@tonic-gate int *cLevel,
14890Sstevel@tonic-gate ns_auth_t *aMethod,
14909576SJulian.Pullen@Sun.COM ns_cred_t **authp,
14919576SJulian.Pullen@Sun.COM int getAdmin)
14920Sstevel@tonic-gate {
14930Sstevel@tonic-gate void **paramVal = NULL;
14940Sstevel@tonic-gate char *modparamVal = NULL;
14950Sstevel@tonic-gate int getUid = 0;
14960Sstevel@tonic-gate int getPasswd = 0;
14970Sstevel@tonic-gate int getCertpath = 0;
14980Sstevel@tonic-gate int rc = 0;
14990Sstevel@tonic-gate ns_ldap_error_t *errorp = NULL;
15009576SJulian.Pullen@Sun.COM UnixCred_t *AdminCred = NULL;
15010Sstevel@tonic-gate
15020Sstevel@tonic-gate #ifdef DEBUG
15030Sstevel@tonic-gate (void) fprintf(stderr, "__s_api_getDefaultAuth START\n");
15040Sstevel@tonic-gate #endif
15050Sstevel@tonic-gate
15060Sstevel@tonic-gate if (aMethod == NULL) {
15070Sstevel@tonic-gate /* Require an Auth */
15080Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM);
15090Sstevel@tonic-gate
15100Sstevel@tonic-gate }
15110Sstevel@tonic-gate /*
15122830Sdjl * credential level "self" can work with auth method sasl/GSSAPI only
15130Sstevel@tonic-gate */
15142830Sdjl if (cLevel && *cLevel == NS_LDAP_CRED_SELF &&
15154522Schinlong aMethod->saslmech != NS_LDAP_SASL_GSSAPI)
15160Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM);
15170Sstevel@tonic-gate
15180Sstevel@tonic-gate *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
15190Sstevel@tonic-gate if ((*authp) == NULL)
15200Sstevel@tonic-gate return (NS_LDAP_MEMORY);
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate (*authp)->auth = *aMethod;
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate switch (aMethod->type) {
15250Sstevel@tonic-gate case NS_LDAP_AUTH_NONE:
15260Sstevel@tonic-gate return (NS_LDAP_SUCCESS);
15270Sstevel@tonic-gate case NS_LDAP_AUTH_SIMPLE:
15280Sstevel@tonic-gate getUid++;
15290Sstevel@tonic-gate getPasswd++;
15300Sstevel@tonic-gate break;
15310Sstevel@tonic-gate case NS_LDAP_AUTH_SASL:
15320Sstevel@tonic-gate if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
15330Sstevel@tonic-gate (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) {
15340Sstevel@tonic-gate getUid++;
15350Sstevel@tonic-gate getPasswd++;
15362830Sdjl } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) {
15370Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp);
15380Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM);
15390Sstevel@tonic-gate }
15400Sstevel@tonic-gate break;
15410Sstevel@tonic-gate case NS_LDAP_AUTH_TLS:
15420Sstevel@tonic-gate if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) ||
15430Sstevel@tonic-gate ((aMethod->tlstype == NS_LDAP_TLS_SASL) &&
15440Sstevel@tonic-gate ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
15450Sstevel@tonic-gate (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) {
15460Sstevel@tonic-gate getUid++;
15470Sstevel@tonic-gate getPasswd++;
15480Sstevel@tonic-gate getCertpath++;
15490Sstevel@tonic-gate } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) {
15500Sstevel@tonic-gate getCertpath++;
15510Sstevel@tonic-gate } else {
15520Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp);
15530Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM);
15540Sstevel@tonic-gate }
15550Sstevel@tonic-gate break;
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate
15580Sstevel@tonic-gate if (getUid) {
15590Sstevel@tonic-gate paramVal = NULL;
15609576SJulian.Pullen@Sun.COM if (getAdmin) {
15619576SJulian.Pullen@Sun.COM /*
15629576SJulian.Pullen@Sun.COM * Assume AdminCred has been retrieved from
15639576SJulian.Pullen@Sun.COM * ldap_cachemgr already. It will not work
15649576SJulian.Pullen@Sun.COM * without userID or password. Flags getUid
15659576SJulian.Pullen@Sun.COM * and getPasswd should always be set
15669576SJulian.Pullen@Sun.COM * together.
15679576SJulian.Pullen@Sun.COM */
15689576SJulian.Pullen@Sun.COM AdminCred = calloc(1, sizeof (UnixCred_t));
15699576SJulian.Pullen@Sun.COM if (AdminCred == NULL) {
15709576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp);
15719576SJulian.Pullen@Sun.COM return (NS_LDAP_MEMORY);
15729576SJulian.Pullen@Sun.COM }
15739576SJulian.Pullen@Sun.COM
15749576SJulian.Pullen@Sun.COM rc = requestAdminCred(&AdminCred, &errorp);
15759576SJulian.Pullen@Sun.COM if (rc != NS_LDAP_SUCCESS) {
15769576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp);
15779576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
15789576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeError(&errorp);
15799576SJulian.Pullen@Sun.COM return (rc);
15809576SJulian.Pullen@Sun.COM }
15810Sstevel@tonic-gate
15829576SJulian.Pullen@Sun.COM if (AdminCred->userID == NULL) {
15839576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp);
15849576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
15859576SJulian.Pullen@Sun.COM return (NS_LDAP_INVALID_PARAM);
15869576SJulian.Pullen@Sun.COM }
15879576SJulian.Pullen@Sun.COM (*authp)->cred.unix_cred.userID = AdminCred->userID;
15889576SJulian.Pullen@Sun.COM AdminCred->userID = NULL;
15899576SJulian.Pullen@Sun.COM } else {
15909576SJulian.Pullen@Sun.COM rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P,
15919576SJulian.Pullen@Sun.COM ¶mVal, &errorp);
15929576SJulian.Pullen@Sun.COM if (rc != NS_LDAP_SUCCESS) {
15939576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp);
15949576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeError(&errorp);
15959576SJulian.Pullen@Sun.COM return (rc);
15969576SJulian.Pullen@Sun.COM }
15979576SJulian.Pullen@Sun.COM
15989576SJulian.Pullen@Sun.COM if (paramVal == NULL || *paramVal == NULL) {
15999576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp);
16009576SJulian.Pullen@Sun.COM return (NS_LDAP_INVALID_PARAM);
16019576SJulian.Pullen@Sun.COM }
16029576SJulian.Pullen@Sun.COM
16039576SJulian.Pullen@Sun.COM (*authp)->cred.unix_cred.userID =
16049576SJulian.Pullen@Sun.COM strdup((char *)*paramVal);
16059576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeParam(¶mVal);
16060Sstevel@tonic-gate }
16070Sstevel@tonic-gate if ((*authp)->cred.unix_cred.userID == NULL) {
16080Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp);
16099576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
16100Sstevel@tonic-gate return (NS_LDAP_MEMORY);
16110Sstevel@tonic-gate }
16120Sstevel@tonic-gate }
16130Sstevel@tonic-gate if (getPasswd) {
16140Sstevel@tonic-gate paramVal = NULL;
16159576SJulian.Pullen@Sun.COM if (getAdmin) {
16169576SJulian.Pullen@Sun.COM /*
16179576SJulian.Pullen@Sun.COM * Assume AdminCred has been retrieved from
16189576SJulian.Pullen@Sun.COM * ldap_cachemgr already. It will not work
16199576SJulian.Pullen@Sun.COM * without the userID anyway because for
16209576SJulian.Pullen@Sun.COM * getting admin credential, flags getUid
16219576SJulian.Pullen@Sun.COM * and getPasswd should always be set
16229576SJulian.Pullen@Sun.COM * together.
16239576SJulian.Pullen@Sun.COM */
16249576SJulian.Pullen@Sun.COM if (AdminCred == NULL || AdminCred->passwd == NULL) {
16259576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp);
16269576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
16279576SJulian.Pullen@Sun.COM return (NS_LDAP_INVALID_PARAM);
16289576SJulian.Pullen@Sun.COM }
16299576SJulian.Pullen@Sun.COM modparamVal = dvalue(AdminCred->passwd);
16309576SJulian.Pullen@Sun.COM } else {
16319576SJulian.Pullen@Sun.COM rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P,
16329576SJulian.Pullen@Sun.COM ¶mVal, &errorp);
16339576SJulian.Pullen@Sun.COM if (rc != NS_LDAP_SUCCESS) {
16349576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp);
16359576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeError(&errorp);
16369576SJulian.Pullen@Sun.COM return (rc);
16379576SJulian.Pullen@Sun.COM }
16389576SJulian.Pullen@Sun.COM
16399576SJulian.Pullen@Sun.COM if (paramVal == NULL || *paramVal == NULL) {
16409576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeCred(authp);
16419576SJulian.Pullen@Sun.COM return (NS_LDAP_INVALID_PARAM);
16429576SJulian.Pullen@Sun.COM }
16439576SJulian.Pullen@Sun.COM
16449576SJulian.Pullen@Sun.COM modparamVal = dvalue((char *)*paramVal);
16459576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeParam(¶mVal);
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) {
16490Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp);
16509576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
16510Sstevel@tonic-gate if (modparamVal != NULL)
16520Sstevel@tonic-gate free(modparamVal);
16530Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM);
16540Sstevel@tonic-gate }
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate (*authp)->cred.unix_cred.passwd = modparamVal;
16570Sstevel@tonic-gate }
16580Sstevel@tonic-gate if (getCertpath) {
16590Sstevel@tonic-gate paramVal = NULL;
16600Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
16614522Schinlong ¶mVal, &errorp)) != NS_LDAP_SUCCESS) {
16620Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp);
16639576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
16640Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp);
16650Sstevel@tonic-gate *authp = NULL;
16660Sstevel@tonic-gate return (rc);
16670Sstevel@tonic-gate }
16680Sstevel@tonic-gate
16690Sstevel@tonic-gate if (paramVal == NULL || *paramVal == NULL) {
16700Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp);
16719576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
16720Sstevel@tonic-gate *authp = NULL;
16730Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM);
16740Sstevel@tonic-gate }
16750Sstevel@tonic-gate
16760Sstevel@tonic-gate (*authp)->hostcertpath = strdup((char *)*paramVal);
16770Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal);
16780Sstevel@tonic-gate if ((*authp)->hostcertpath == NULL) {
16790Sstevel@tonic-gate (void) __ns_ldap_freeCred(authp);
16809576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
16810Sstevel@tonic-gate *authp = NULL;
16820Sstevel@tonic-gate return (NS_LDAP_MEMORY);
16830Sstevel@tonic-gate }
16840Sstevel@tonic-gate }
16859576SJulian.Pullen@Sun.COM (void) __ns_ldap_freeUnixCred(&AdminCred);
16860Sstevel@tonic-gate return (NS_LDAP_SUCCESS);
16870Sstevel@tonic-gate }
16880Sstevel@tonic-gate
16890Sstevel@tonic-gate /*
16906842Sth160488 * FUNCTION: getConnection
16910Sstevel@tonic-gate *
16926842Sth160488 * internal version of __s_api_getConnection()
16930Sstevel@tonic-gate */
16946842Sth160488 static int
getConnection(const char * server,const int flags,const ns_cred_t * cred,ConnectionID * sessionId,Connection ** session,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int nopasswd_acct_mgmt,ns_conn_user_t * conn_user)16956842Sth160488 getConnection(
16960Sstevel@tonic-gate const char *server,
16970Sstevel@tonic-gate const int flags,
16980Sstevel@tonic-gate const ns_cred_t *cred, /* credentials for bind */
16990Sstevel@tonic-gate ConnectionID *sessionId,
17000Sstevel@tonic-gate Connection **session,
17010Sstevel@tonic-gate ns_ldap_error_t **errorp,
17021179Svv149972 int fail_if_new_pwd_reqd,
17036842Sth160488 int nopasswd_acct_mgmt,
17046842Sth160488 ns_conn_user_t *conn_user)
17050Sstevel@tonic-gate {
17060Sstevel@tonic-gate char errmsg[MAXERROR];
17070Sstevel@tonic-gate ns_auth_t **aMethod = NULL;
17080Sstevel@tonic-gate ns_auth_t **aNext = NULL;
17090Sstevel@tonic-gate int **cLevel = NULL;
17100Sstevel@tonic-gate int **cNext = NULL;
17110Sstevel@tonic-gate int timeoutSec = NS_DEFAULT_BIND_TIMEOUT;
17120Sstevel@tonic-gate int rc;
17130Sstevel@tonic-gate Connection *con = NULL;
17140Sstevel@tonic-gate int sec = 1;
17150Sstevel@tonic-gate ns_cred_t *authp = NULL;
17160Sstevel@tonic-gate ns_cred_t anon;
17172830Sdjl int version = NS_LDAP_V2, self_gssapi_only = 0;
17180Sstevel@tonic-gate void **paramVal = NULL;
17191687Sjanga char **badSrvrs = NULL; /* List of problem hostnames */
17200Sstevel@tonic-gate
17210Sstevel@tonic-gate if ((session == NULL) || (sessionId == NULL)) {
17220Sstevel@tonic-gate return (NS_LDAP_INVALID_PARAM);
17230Sstevel@tonic-gate }
17240Sstevel@tonic-gate *session = NULL;
17250Sstevel@tonic-gate
17266842Sth160488 /* reuse MT connection if needed and if available */
17276842Sth160488 if (conn_user != NULL) {
17286842Sth160488 rc = __s_api_conn_mt_get(server, flags, cred, session, errorp,
17296842Sth160488 conn_user);
17306842Sth160488 if (rc != NS_LDAP_NOTFOUND)
17316842Sth160488 return (rc);
17320Sstevel@tonic-gate }
17330Sstevel@tonic-gate
17340Sstevel@tonic-gate /* get profile version number */
17350Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P,
17364522Schinlong ¶mVal, errorp)) != NS_LDAP_SUCCESS)
17370Sstevel@tonic-gate return (rc);
17380Sstevel@tonic-gate if (paramVal == NULL) {
17390Sstevel@tonic-gate (void) sprintf(errmsg, gettext("getConnection: no file "
17404522Schinlong "version"));
17410Sstevel@tonic-gate MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg),
17424522Schinlong NS_LDAP_CONFIG);
17430Sstevel@tonic-gate return (NS_LDAP_CONFIG);
17440Sstevel@tonic-gate }
17450Sstevel@tonic-gate if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0)
17460Sstevel@tonic-gate version = NS_LDAP_V1;
17470Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)¶mVal);
17480Sstevel@tonic-gate
17490Sstevel@tonic-gate /* Get the bind timeout value */
17500Sstevel@tonic-gate (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp);
17510Sstevel@tonic-gate if (paramVal != NULL && *paramVal != NULL) {
17520Sstevel@tonic-gate timeoutSec = **((int **)paramVal);
17530Sstevel@tonic-gate (void) __ns_ldap_freeParam(¶mVal);
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate if (*errorp)
17560Sstevel@tonic-gate (void) __ns_ldap_freeError(errorp);
17570Sstevel@tonic-gate
17580Sstevel@tonic-gate if (cred == NULL) {
17590Sstevel@tonic-gate /* Get the authentication method list */
17600Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P,
17614522Schinlong (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS)
17620Sstevel@tonic-gate return (rc);
17630Sstevel@tonic-gate if (aMethod == NULL) {
17640Sstevel@tonic-gate aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *));
17650Sstevel@tonic-gate if (aMethod == NULL)
17660Sstevel@tonic-gate return (NS_LDAP_MEMORY);
17670Sstevel@tonic-gate aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t));
17680Sstevel@tonic-gate if (aMethod[0] == NULL) {
17690Sstevel@tonic-gate free(aMethod);
17700Sstevel@tonic-gate return (NS_LDAP_MEMORY);
17710Sstevel@tonic-gate }
17720Sstevel@tonic-gate if (version == NS_LDAP_V1)
17730Sstevel@tonic-gate (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE;
17740Sstevel@tonic-gate else {
17750Sstevel@tonic-gate (aMethod[0])->type = NS_LDAP_AUTH_SASL;
17760Sstevel@tonic-gate (aMethod[0])->saslmech =
17774522Schinlong NS_LDAP_SASL_DIGEST_MD5;
17780Sstevel@tonic-gate (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE;
17790Sstevel@tonic-gate }
17800Sstevel@tonic-gate }
17810Sstevel@tonic-gate
17820Sstevel@tonic-gate /* Get the credential level list */
17830Sstevel@tonic-gate if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
17844522Schinlong (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) {
17850Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&aMethod);
17860Sstevel@tonic-gate return (rc);
17870Sstevel@tonic-gate }
17880Sstevel@tonic-gate if (cLevel == NULL) {
17890Sstevel@tonic-gate cLevel = (int **)calloc(2, sizeof (int *));
17900Sstevel@tonic-gate if (cLevel == NULL)
17910Sstevel@tonic-gate return (NS_LDAP_MEMORY);
17920Sstevel@tonic-gate cLevel[0] = (int *)calloc(1, sizeof (int));
17930Sstevel@tonic-gate if (cLevel[0] == NULL)
17940Sstevel@tonic-gate return (NS_LDAP_MEMORY);
17950Sstevel@tonic-gate if (version == NS_LDAP_V1)
17960Sstevel@tonic-gate *(cLevel[0]) = NS_LDAP_CRED_PROXY;
17970Sstevel@tonic-gate else
17980Sstevel@tonic-gate *(cLevel[0]) = NS_LDAP_CRED_ANON;
17990Sstevel@tonic-gate }
18000Sstevel@tonic-gate }
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate /* setup the anon credential for anonymous connection */
18030Sstevel@tonic-gate (void) memset(&anon, 0, sizeof (ns_cred_t));
18040Sstevel@tonic-gate anon.auth.type = NS_LDAP_AUTH_NONE;
18050Sstevel@tonic-gate
18066812Sraf for (;;) {
18070Sstevel@tonic-gate if (cred != NULL) {
18080Sstevel@tonic-gate /* using specified auth method */
18090Sstevel@tonic-gate rc = makeConnection(&con, server, cred,
18104522Schinlong sessionId, timeoutSec, errorp,
18114522Schinlong fail_if_new_pwd_reqd,
18126842Sth160488 nopasswd_acct_mgmt, flags, &badSrvrs, conn_user);
18134387Smj162486 /* not using bad server if credentials were supplied */
18144387Smj162486 if (badSrvrs && *badSrvrs) {
18154387Smj162486 __s_api_free2dArray(badSrvrs);
18164387Smj162486 badSrvrs = NULL;
18174387Smj162486 }
18180Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS ||
18194522Schinlong rc == NS_LDAP_SUCCESS_WITH_INFO) {
18200Sstevel@tonic-gate *session = con;
18210Sstevel@tonic-gate break;
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate } else {
18242830Sdjl self_gssapi_only = __s_api_self_gssapi_only_get();
18250Sstevel@tonic-gate /* for every cred level */
18260Sstevel@tonic-gate for (cNext = cLevel; *cNext != NULL; cNext++) {
18272830Sdjl if (self_gssapi_only &&
18284522Schinlong **cNext != NS_LDAP_CRED_SELF)
18292830Sdjl continue;
18300Sstevel@tonic-gate if (**cNext == NS_LDAP_CRED_ANON) {
18311687Sjanga /*
18321687Sjanga * make connection anonymously
18331687Sjanga * Free the down server list before
18341687Sjanga * looping through
18351687Sjanga */
18361687Sjanga if (badSrvrs && *badSrvrs) {
18371687Sjanga __s_api_free2dArray(badSrvrs);
18381687Sjanga badSrvrs = NULL;
18391687Sjanga }
18400Sstevel@tonic-gate rc = makeConnection(&con, server, &anon,
18414522Schinlong sessionId, timeoutSec, errorp,
18424522Schinlong fail_if_new_pwd_reqd,
18434522Schinlong nopasswd_acct_mgmt, flags,
18446842Sth160488 &badSrvrs, conn_user);
18450Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS ||
18464522Schinlong rc ==
18474522Schinlong NS_LDAP_SUCCESS_WITH_INFO) {
18480Sstevel@tonic-gate *session = con;
18490Sstevel@tonic-gate goto done;
18500Sstevel@tonic-gate }
18510Sstevel@tonic-gate continue;
18520Sstevel@tonic-gate }
18530Sstevel@tonic-gate /* for each cred level */
18540Sstevel@tonic-gate for (aNext = aMethod; *aNext != NULL; aNext++) {
18552830Sdjl if (self_gssapi_only &&
18564522Schinlong (*aNext)->saslmech !=
18574522Schinlong NS_LDAP_SASL_GSSAPI)
18582830Sdjl continue;
18592830Sdjl /*
18602830Sdjl * self coexists with sasl/GSSAPI only
18612830Sdjl * and non-self coexists with non-gssapi
18622830Sdjl * only
18632830Sdjl */
18642830Sdjl if ((**cNext == NS_LDAP_CRED_SELF &&
18654522Schinlong (*aNext)->saslmech !=
18664522Schinlong NS_LDAP_SASL_GSSAPI) ||
18674522Schinlong (**cNext != NS_LDAP_CRED_SELF &&
18684522Schinlong (*aNext)->saslmech ==
18694522Schinlong NS_LDAP_SASL_GSSAPI))
18702830Sdjl continue;
18710Sstevel@tonic-gate /* make connection and authenticate */
18720Sstevel@tonic-gate /* with default credentials */
18730Sstevel@tonic-gate authp = NULL;
18740Sstevel@tonic-gate rc = __s_api_getDefaultAuth(*cNext,
18759576SJulian.Pullen@Sun.COM *aNext, &authp,
18769576SJulian.Pullen@Sun.COM flags & NS_LDAP_READ_SHADOW);
18770Sstevel@tonic-gate if (rc != NS_LDAP_SUCCESS) {
18780Sstevel@tonic-gate continue;
18790Sstevel@tonic-gate }
18801687Sjanga /*
18811687Sjanga * Free the down server list before
18821687Sjanga * looping through
18831687Sjanga */
18841687Sjanga if (badSrvrs && *badSrvrs) {
18851687Sjanga __s_api_free2dArray(badSrvrs);
18861687Sjanga badSrvrs = NULL;
18871687Sjanga }
18880Sstevel@tonic-gate rc = makeConnection(&con, server, authp,
18894522Schinlong sessionId, timeoutSec, errorp,
18904522Schinlong fail_if_new_pwd_reqd,
18914522Schinlong nopasswd_acct_mgmt, flags,
18926842Sth160488 &badSrvrs, conn_user);
18930Sstevel@tonic-gate (void) __ns_ldap_freeCred(&authp);
18940Sstevel@tonic-gate if (rc == NS_LDAP_SUCCESS ||
18954522Schinlong rc ==
18964522Schinlong NS_LDAP_SUCCESS_WITH_INFO) {
18970Sstevel@tonic-gate *session = con;
18980Sstevel@tonic-gate goto done;
18990Sstevel@tonic-gate }
19000Sstevel@tonic-gate }
19010Sstevel@tonic-gate }
19020Sstevel@tonic-gate }
19030Sstevel@tonic-gate if (flags & NS_LDAP_HARD) {
19040Sstevel@tonic-gate if (sec < LDAPMAXHARDLOOKUPTIME)
19050Sstevel@tonic-gate sec *= 2;
19066812Sraf (void) sleep(sec);
19070Sstevel@tonic-gate } else {
19080Sstevel@tonic-gate break;
19090Sstevel@tonic-gate }
19100Sstevel@tonic-gate }
19110Sstevel@tonic-gate
19120Sstevel@tonic-gate done:
19132830Sdjl if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) {
19142830Sdjl /*
19152830Sdjl * self_gssapi_only is true but no self/sasl/gssapi is
19162830Sdjl * configured
19172830Sdjl */
19182830Sdjl rc = NS_LDAP_CONFIG;
19192830Sdjl }
19202830Sdjl
19210Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&aMethod);
19220Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&cLevel);
19231687Sjanga
19241687Sjanga if (badSrvrs && *badSrvrs) {
19251687Sjanga /*
19261687Sjanga * At this point, either we have a successful
19271687Sjanga * connection or exhausted all the possible auths.
19281687Sjanga * and creds. Mark the problem servers as down
19291687Sjanga * so that the problem servers are not contacted
19301687Sjanga * again until the refresh_ttl expires.
19311687Sjanga */
19321687Sjanga (void) __s_api_removeBadServers(badSrvrs);
19331687Sjanga __s_api_free2dArray(badSrvrs);
19341687Sjanga }
19350Sstevel@tonic-gate return (rc);
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate
19386842Sth160488 /*
19396842Sth160488 * FUNCTION: __s_api_getConnection
19406842Sth160488 *
19416842Sth160488 * Bind to the specified server or one from the server
19426842Sth160488 * list and return the pointer.
19436842Sth160488 *
19446842Sth160488 * This function can rebind or not (NS_LDAP_HARD), it can require a
19456842Sth160488 * credential or bind anonymously
19466842Sth160488 *
19476842Sth160488 * This function follows the DUA configuration schema algorithm
19486842Sth160488 *
19496842Sth160488 * RETURN VALUES:
19506842Sth160488 *
19516842Sth160488 * NS_LDAP_SUCCESS A connection was made successfully.
19526842Sth160488 * NS_LDAP_SUCCESS_WITH_INFO
19536842Sth160488 * A connection was made successfully, but with
19546842Sth160488 * password management info in *errorp
19556842Sth160488 * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function.
19566842Sth160488 * NS_LDAP_CONFIG If there are any config errors.
19576842Sth160488 * NS_LDAP_MEMORY Memory errors.
19586842Sth160488 * NS_LDAP_INTERNAL If there was a ldap error.
19596842Sth160488 *
19606842Sth160488 * INPUT:
19616842Sth160488 *
19626842Sth160488 * server Bind to this LDAP server only
19636842Sth160488 * flags If NS_LDAP_HARD is set function will not return until it has
19646842Sth160488 * a connection unless there is a authentication problem.
19656842Sth160488 * If NS_LDAP_NEW_CONN is set the function must force a new
19666842Sth160488 * connection to be created
19676842Sth160488 * If NS_LDAP_KEEP_CONN is set the connection is to be kept open
19686842Sth160488 * auth Credentials for bind. This could be NULL in which case
19696842Sth160488 * a default cred built from the config module is used.
19706842Sth160488 * sessionId cookie that points to a previous session
19716842Sth160488 * fail_if_new_pwd_reqd
19726842Sth160488 * a flag indicating this function should fail if the passwd
19736842Sth160488 * in auth needs to change immediately
19746842Sth160488 * nopasswd_acct_mgmt
19756842Sth160488 * a flag indicating that makeConnection should check before
19766842Sth160488 * binding if server supports LDAP V3 password less
19776842Sth160488 * account management
19786842Sth160488 *
19796842Sth160488 * OUTPUT:
19806842Sth160488 *
19816842Sth160488 * session pointer to a session with connection information
19826842Sth160488 * errorp Set if there are any INTERNAL, or CONFIG error.
19836842Sth160488 */
19846842Sth160488 int
__s_api_getConnection(const char * server,const int flags,const ns_cred_t * cred,ConnectionID * sessionId,Connection ** session,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int nopasswd_acct_mgmt,ns_conn_user_t * conn_user)19856842Sth160488 __s_api_getConnection(
19866842Sth160488 const char *server,
19876842Sth160488 const int flags,
19886842Sth160488 const ns_cred_t *cred, /* credentials for bind */
19896842Sth160488 ConnectionID *sessionId,
19906842Sth160488 Connection **session,
19916842Sth160488 ns_ldap_error_t **errorp,
19926842Sth160488 int fail_if_new_pwd_reqd,
19936842Sth160488 int nopasswd_acct_mgmt,
19946842Sth160488 ns_conn_user_t *conn_user)
19956842Sth160488 {
19966842Sth160488 int rc;
19976842Sth160488
19986842Sth160488 rc = getConnection(server, flags, cred, sessionId, session,
19996842Sth160488 errorp, fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
20006842Sth160488 conn_user);
20016842Sth160488
20026842Sth160488 if (rc != NS_LDAP_SUCCESS && rc != NS_LDAP_SUCCESS_WITH_INFO) {
20036842Sth160488 if (conn_user != NULL && conn_user->conn_mt != NULL)
20046842Sth160488 __s_api_conn_mt_remove(conn_user, rc, errorp);
20056842Sth160488 }
20066842Sth160488
20076842Sth160488 return (rc);
20086842Sth160488 }
20096842Sth160488
20106842Sth160488 void
__s_api_free_sessionPool()20116842Sth160488 __s_api_free_sessionPool()
20120Sstevel@tonic-gate {
20130Sstevel@tonic-gate int id;
20140Sstevel@tonic-gate
20156842Sth160488 (void) mutex_lock(&sessionPoolLock);
20166842Sth160488
20170Sstevel@tonic-gate if (sessionPool != NULL) {
20180Sstevel@tonic-gate for (id = 0; id < sessionPoolSize; id++)
20190Sstevel@tonic-gate _DropConnection(id + CONID_OFFSET, 0, 1);
20200Sstevel@tonic-gate free(sessionPool);
20210Sstevel@tonic-gate sessionPool = NULL;
20220Sstevel@tonic-gate sessionPoolSize = 0;
20230Sstevel@tonic-gate }
20246842Sth160488 (void) mutex_unlock(&sessionPoolLock);
20256842Sth160488 }
20266842Sth160488
20276842Sth160488 /*
20286842Sth160488 * This function initializes a TLS LDAP session. On success LDAP* is returned
20296842Sth160488 * (pointed by *ldp). Otherwise, the function returns an NS error code and
20306842Sth160488 * provide an additional info pointed by *errorp.
20316842Sth160488 */
20326842Sth160488 static
20336842Sth160488 ns_ldap_return_code
createTLSSession(const ns_cred_t * auth,const char * serverAddr,uint16_t port,int timeoutMilliSec,LDAP ** ldp,ns_ldap_error_t ** errorp)20346842Sth160488 createTLSSession(const ns_cred_t *auth, const char *serverAddr,
20356842Sth160488 uint16_t port, int timeoutMilliSec,
20366842Sth160488 LDAP **ldp, ns_ldap_error_t **errorp)
20376842Sth160488 {
20386842Sth160488 const char *hostcertpath;
20396842Sth160488 char *alloc_hcp = NULL, errstr[MAXERROR];
20406842Sth160488 int ldap_rc;
20416842Sth160488
20426842Sth160488 #ifdef DEBUG
20436842Sth160488 (void) fprintf(stderr, "tid= %d: +++TLS transport\n",
20446842Sth160488 thr_self());
20456842Sth160488 #endif /* DEBUG */
20466842Sth160488
20476842Sth160488 if (prldap_set_session_option(NULL, NULL,
20486842Sth160488 PRLDAP_OPT_IO_MAX_TIMEOUT,
20496842Sth160488 timeoutMilliSec) != LDAP_SUCCESS) {
20506842Sth160488 (void) snprintf(errstr, sizeof (errstr),
20516842Sth160488 gettext("createTLSSession: failed to initialize "
20526842Sth160488 "TLS security"));
20536842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
20546842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
20556842Sth160488 return (NS_LDAP_INTERNAL);
20566842Sth160488 }
20576842Sth160488
20586842Sth160488 hostcertpath = auth->hostcertpath;
20596842Sth160488 if (hostcertpath == NULL) {
20606842Sth160488 alloc_hcp = __s_get_hostcertpath();
20616842Sth160488 hostcertpath = alloc_hcp;
20626842Sth160488 }
20636842Sth160488
20646842Sth160488 if (hostcertpath == NULL)
20656842Sth160488 return (NS_LDAP_MEMORY);
20666842Sth160488
20676842Sth160488 if ((ldap_rc = ldapssl_client_init(hostcertpath, NULL)) < 0) {
20686842Sth160488 if (alloc_hcp != NULL) {
20696842Sth160488 free(alloc_hcp);
20706842Sth160488 }
20716842Sth160488 (void) snprintf(errstr, sizeof (errstr),
20726842Sth160488 gettext("createTLSSession: failed to initialize "
20736842Sth160488 "TLS security (%s)"),
20746842Sth160488 ldapssl_err2string(ldap_rc));
20756842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
20766842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
20776842Sth160488 return (NS_LDAP_INTERNAL);
20786842Sth160488 }
20796842Sth160488 if (alloc_hcp)
20806842Sth160488 free(alloc_hcp);
20816842Sth160488
20826842Sth160488 *ldp = ldapssl_init(serverAddr, port, 1);
20836842Sth160488
20846842Sth160488 if (*ldp == NULL ||
20856842Sth160488 ldapssl_install_gethostbyaddr(*ldp, "ldap") != 0) {
20866842Sth160488 (void) snprintf(errstr, sizeof (errstr),
20876842Sth160488 gettext("createTLSSession: failed to connect "
20886842Sth160488 "using TLS (%s)"), strerror(errno));
20896842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
20906842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
20916842Sth160488 return (NS_LDAP_INTERNAL);
20926842Sth160488 }
20936842Sth160488
20946842Sth160488 return (NS_LDAP_SUCCESS);
20956842Sth160488 }
20966842Sth160488
20976842Sth160488 /*
20986842Sth160488 * Convert (resolve) hostname to IP address.
20996842Sth160488 *
21006842Sth160488 * INPUT:
21016842Sth160488 *
21026842Sth160488 * server - \[IPv6_address\][:port]
21036842Sth160488 * - IPv4_address[:port]
21046842Sth160488 * - hostname[:port]
21056842Sth160488 *
21066842Sth160488 * newaddr - Buffer to which this function writes resulting address,
21076842Sth160488 * including the port number, if specified in server argument.
21086842Sth160488 *
21096842Sth160488 * newaddr_size - Size of the newaddr buffer.
21106842Sth160488 *
21116842Sth160488 * errstr - Buffer to which error string is written if error occurs.
21126842Sth160488 *
21136842Sth160488 * errstr_size - Size of the errstr buffer.
21146842Sth160488 *
21156842Sth160488 * OUTPUT:
21166842Sth160488 *
21176842Sth160488 * Returns 1 for success, 0 in case of error.
21186842Sth160488 *
21196842Sth160488 * newaddr - See above (INPUT section).
21206842Sth160488 *
21216842Sth160488 * errstr - See above (INPUT section).
21226842Sth160488 */
21236842Sth160488 static int
cvt_hostname2ip(char * server,char * newaddr,int newaddr_size,char * errstr,int errstr_size)21246842Sth160488 cvt_hostname2ip(char *server, char *newaddr, int newaddr_size,
21256842Sth160488 char *errstr, int errstr_size)
21266842Sth160488 {
21276842Sth160488 char *s;
21286842Sth160488 unsigned short port = 0;
21296842Sth160488 int err;
21306842Sth160488 char buffer[NSS_BUFLEN_HOSTS];
21316842Sth160488 struct hostent result;
21326842Sth160488
21336842Sth160488 /* Determine if the host name contains a port number. */
21346842Sth160488
21356842Sth160488 /* Skip over IPv6 address. */
21366842Sth160488 s = strchr(server, ']');
21376842Sth160488 s = strchr(s != NULL ? s : server, ':');
21386842Sth160488 if (s != NULL) {
21396842Sth160488 if (sscanf(s + 1, "%hu", &port) != 1) {
21406842Sth160488 /* Address misformatted. No port number after : */
21416842Sth160488 (void) snprintf(errstr, errstr_size, "%s",
21426842Sth160488 gettext("Invalid host:port format"));
21436842Sth160488 return (0);
21446842Sth160488 } else
21456842Sth160488 /* Cut off the :<port> part. */
21466842Sth160488 *s = '\0';
21476842Sth160488 }
21486842Sth160488
21496842Sth160488 buffer[0] = '\0';
21506842Sth160488 /*
21516842Sth160488 * Resolve hostname and fill in hostent structure.
21526842Sth160488 */
21536842Sth160488 if (!__s_api_hostname2ip(server, &result, buffer, NSS_BUFLEN_HOSTS,
21546842Sth160488 &err)) {
21556842Sth160488 /*
21566842Sth160488 * The only possible error here could be TRY_AGAIN if buffer was
21576842Sth160488 * not big enough. NSS_BUFLEN_HOSTS should have been enough
21586842Sth160488 * though.
21596842Sth160488 */
21606842Sth160488 (void) snprintf(errstr, errstr_size, "%s",
21616842Sth160488 gettext("Unable to resolve address."));
21626842Sth160488 return (0);
21636842Sth160488 }
21646842Sth160488
21656842Sth160488
21666842Sth160488 buffer[0] = '\0';
21676842Sth160488 /*
21686842Sth160488 * Convert the address to string.
21696842Sth160488 */
21706842Sth160488 if (!inet_ntop(result.h_addrtype, result.h_addr_list[0], buffer,
21716842Sth160488 NSS_BUFLEN_HOSTS)) {
21726842Sth160488 /* There's not much we can do. */
21736842Sth160488 (void) snprintf(errstr, errstr_size, "%s",
21746842Sth160488 gettext("Unable to convert address to string."));
21756842Sth160488 return (0);
21766842Sth160488 }
21776842Sth160488
21786842Sth160488 /* Put together the address and the port */
21796842Sth160488 if (port > 0) {
21806842Sth160488 switch (result.h_addrtype) {
21816842Sth160488 case AF_INET6:
21826842Sth160488 (void) snprintf(newaddr,
21836842Sth160488 /* [IP]:<port>\0 */
21846842Sth160488 1 + strlen(buffer) + 1 + 1 + 5 + 1,
21856842Sth160488 "[%s]:%hu",
21866842Sth160488 buffer,
21876842Sth160488 port);
21886842Sth160488 break;
21896842Sth160488 /* AF_INET */
21906842Sth160488 default :
21916842Sth160488 (void) snprintf(newaddr,
21926842Sth160488 /* IP:<port>\0 */
21936842Sth160488 strlen(buffer) + 1 + 5 + 1,
21946842Sth160488 "%s:%hu",
21956842Sth160488 buffer,
21966842Sth160488 port);
21976842Sth160488 break;
21986842Sth160488 }
21996842Sth160488 } else {
22006842Sth160488 (void) strncpy(newaddr, buffer, newaddr_size);
22016842Sth160488 }
22026842Sth160488
22036842Sth160488 return (1);
22046842Sth160488 }
22056842Sth160488
22066842Sth160488
22076842Sth160488 /*
22086842Sth160488 * This finction initializes a none-TLS LDAP session. On success LDAP*
22096842Sth160488 * is returned (pointed by *ldp). Otherwise, the function returns
22106842Sth160488 * an NS error code and provides an additional info pointed by *errorp.
22116842Sth160488 */
22126842Sth160488 static
22136842Sth160488 ns_ldap_return_code
createNonTLSSession(const char * serverAddr,uint16_t port,int gssapi,LDAP ** ldp,ns_ldap_error_t ** errorp)22146842Sth160488 createNonTLSSession(const char *serverAddr,
22156842Sth160488 uint16_t port, int gssapi,
22166842Sth160488 LDAP **ldp, ns_ldap_error_t **errorp)
22176842Sth160488 {
22186842Sth160488 char errstr[MAXERROR];
22196842Sth160488 char *addr;
22206842Sth160488 int is_ip = 0;
22216842Sth160488 /* [INET6_ADDRSTRLEN]:<port>\0 */
22226842Sth160488 char svraddr[1+INET6_ADDRSTRLEN+1+1+5+1];
22236842Sth160488 #ifdef DEBUG
22246842Sth160488 (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n",
22256842Sth160488 thr_self());
22266842Sth160488 #endif /* DEBUG */
22276842Sth160488
22286842Sth160488 if (gssapi == 0) {
22296842Sth160488 is_ip = (__s_api_isipv4((char *)serverAddr) ||
22306842Sth160488 __s_api_isipv6((char *)serverAddr));
22316842Sth160488 }
22326842Sth160488
22336842Sth160488 /*
22346842Sth160488 * Let's try to resolve IP address of server.
22356842Sth160488 */
22366842Sth160488 if (is_ip == 0 && !gssapi && (ldap_in_nss_switch((char *)"hosts") > 0 ||
22376842Sth160488 ldap_in_nss_switch((char *)"ipnodes") > 0)) {
22386842Sth160488 addr = strdup(serverAddr);
22396842Sth160488 if (addr == NULL)
22406842Sth160488 return (NS_LDAP_MEMORY);
22416842Sth160488 svraddr[0] = '\0';
22426842Sth160488 if (cvt_hostname2ip(addr, svraddr, sizeof (svraddr),
22436842Sth160488 errstr, MAXERROR) == 1) {
22446842Sth160488 serverAddr = svraddr;
22456842Sth160488 free(addr);
22466842Sth160488 } else {
22476842Sth160488 free(addr);
22486842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
22496842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
22506842Sth160488 return (NS_LDAP_INTERNAL);
22516842Sth160488 }
22526842Sth160488 }
22536842Sth160488
22546842Sth160488 /* Warning message IF cannot connect to host(s) */
22556842Sth160488 if ((*ldp = ldap_init((char *)serverAddr, port)) == NULL) {
22566842Sth160488 char *p = strerror(errno);
22576842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
22586842Sth160488 strdup(p), NS_LDAP_MEMORY);
22596842Sth160488 return (NS_LDAP_INTERNAL);
22606842Sth160488 }
22616842Sth160488
22626842Sth160488 return (NS_LDAP_SUCCESS);
22636842Sth160488 }
22646842Sth160488
22656842Sth160488 /*
22666842Sth160488 * This finction initializes an LDAP session.
22676842Sth160488 *
22686842Sth160488 * INPUT:
22696842Sth160488 * auth - a structure specified an authenticastion method and credentials,
22706842Sth160488 * serverAddr - the address of a server to which a connection
22716842Sth160488 * will be established,
22726842Sth160488 * port - a port being listened by the server,
22736842Sth160488 * timeoutMilliSec - a timeout in milliseconds for the Bind operation.
22746842Sth160488 *
22756842Sth160488 * OUTPUT:
22766842Sth160488 * ldp - a pointer to an LDAP structure which will be used
22776842Sth160488 * for all the subsequent operations against the server.
22786921Smichen * If an error occurs, the function returns an NS error code
22796842Sth160488 * and provides an additional info pointed by *errorp.
22806842Sth160488 */
22816842Sth160488 static
22826842Sth160488 ns_ldap_return_code
createSession(const ns_cred_t * auth,const char * serverAddr,uint16_t port,int timeoutMilliSec,LDAP ** ldp,ns_ldap_error_t ** errorp)22836842Sth160488 createSession(const ns_cred_t *auth, const char *serverAddr,
22846842Sth160488 uint16_t port, int timeoutMilliSec,
22856842Sth160488 LDAP **ldp, ns_ldap_error_t **errorp)
22866842Sth160488 {
22876842Sth160488 int useSSL = 0, gssapi = 0;
22886842Sth160488 char errstr[MAXERROR];
22896842Sth160488
22906842Sth160488 switch (auth->auth.type) {
22916842Sth160488 case NS_LDAP_AUTH_NONE:
22926842Sth160488 case NS_LDAP_AUTH_SIMPLE:
22936842Sth160488 case NS_LDAP_AUTH_SASL:
22946842Sth160488 break;
22956842Sth160488 case NS_LDAP_AUTH_TLS:
22966842Sth160488 useSSL = 1;
22976842Sth160488 break;
22986842Sth160488 default:
22996842Sth160488 (void) sprintf(errstr,
23006842Sth160488 gettext("openConnection: unsupported "
23016842Sth160488 "authentication method (%d)"), auth->auth.type);
23026842Sth160488 MKERROR(LOG_WARNING, *errorp,
23036842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
23046842Sth160488 NS_LDAP_MEMORY);
23056842Sth160488 return (NS_LDAP_INTERNAL);
23066842Sth160488 }
23076842Sth160488
23086842Sth160488 if (port == USE_DEFAULT_PORT) {
23096842Sth160488 port = useSSL ? LDAPS_PORT : LDAP_PORT;
23106842Sth160488 }
23116842Sth160488
23126842Sth160488 if (auth->auth.type == NS_LDAP_AUTH_SASL &&
23136842Sth160488 auth->auth.saslmech == NS_LDAP_SASL_GSSAPI)
23146842Sth160488 gssapi = 1;
23156842Sth160488
23166842Sth160488 if (useSSL)
23176842Sth160488 return (createTLSSession(auth, serverAddr, port,
23186842Sth160488 timeoutMilliSec, ldp, errorp));
23196842Sth160488 else
23206842Sth160488 return (createNonTLSSession(serverAddr, port, gssapi,
23216842Sth160488 ldp, errorp));
23220Sstevel@tonic-gate }
23236842Sth160488
23246842Sth160488 /*
23256842Sth160488 * This finction performs a non-SASL bind operation. If an error accures,
23266842Sth160488 * the function returns an NS error code and provides an additional info
23276842Sth160488 * pointed by *errorp.
23286842Sth160488 */
23296842Sth160488 static
23306842Sth160488 ns_ldap_return_code
doSimpleBind(const ns_cred_t * auth,LDAP * ld,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt)23316842Sth160488 doSimpleBind(const ns_cred_t *auth,
23326842Sth160488 LDAP *ld,
23336842Sth160488 int timeoutSec,
23346842Sth160488 ns_ldap_error_t **errorp,
23356842Sth160488 int fail_if_new_pwd_reqd,
23366842Sth160488 int passwd_mgmt)
23376842Sth160488 {
23386842Sth160488 char *binddn, *passwd, errstr[MAXERROR], *errmsg;
23396842Sth160488 int msgId, errnum = 0, ldap_rc;
23406842Sth160488 ns_ldap_return_code ret_code;
23416842Sth160488 LDAPMessage *resultMsg = NULL;
23426842Sth160488 LDAPControl **controls;
23436842Sth160488 struct timeval tv;
23446842Sth160488
23456842Sth160488 binddn = auth->cred.unix_cred.userID;
23466842Sth160488 passwd = auth->cred.unix_cred.passwd;
23476842Sth160488 if (passwd == NULL || *passwd == '\0' ||
23486842Sth160488 binddn == NULL || *binddn == '\0') {
23496842Sth160488 (void) sprintf(errstr, gettext("openConnection: "
23506842Sth160488 "missing credentials for Simple bind"));
23516842Sth160488 MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS,
23526842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
23536842Sth160488 (void) ldap_unbind(ld);
23546842Sth160488 return (NS_LDAP_INTERNAL);
23556842Sth160488 }
23566842Sth160488
23576842Sth160488 #ifdef DEBUG
23586842Sth160488 (void) fprintf(stderr, "tid= %d: +++Simple bind\n",
23596842Sth160488 thr_self());
23606842Sth160488 #endif /* DEBUG */
23616842Sth160488 msgId = ldap_simple_bind(ld, binddn, passwd);
23626842Sth160488
23636842Sth160488 if (msgId == -1) {
23646842Sth160488 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
23656842Sth160488 (void *)&errnum);
23666842Sth160488 (void) snprintf(errstr, sizeof (errstr),
23676842Sth160488 gettext("openConnection: simple bind failed "
23686842Sth160488 "- %s"), ldap_err2string(errnum));
23696842Sth160488 (void) ldap_unbind(ld);
23706842Sth160488 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
23716842Sth160488 NS_LDAP_MEMORY);
23726842Sth160488 return (NS_LDAP_INTERNAL);
23736842Sth160488 }
23746842Sth160488
23756842Sth160488 tv.tv_sec = timeoutSec;
23766842Sth160488 tv.tv_usec = 0;
23776842Sth160488 ldap_rc = ldap_result(ld, msgId, 0, &tv, &resultMsg);
23786842Sth160488
23796842Sth160488 if ((ldap_rc == -1) || (ldap_rc == 0)) {
23806842Sth160488 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
23816842Sth160488 (void *)&errnum);
23826842Sth160488 (void) snprintf(errstr, sizeof (errstr),
23836842Sth160488 gettext("openConnection: simple bind failed "
23846842Sth160488 "- %s"), ldap_err2string(errnum));
23856842Sth160488 (void) ldap_msgfree(resultMsg);
23866842Sth160488 (void) ldap_unbind(ld);
23876842Sth160488 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
23886842Sth160488 NS_LDAP_MEMORY);
23896842Sth160488 return (NS_LDAP_INTERNAL);
23906842Sth160488 }
23916842Sth160488
23926842Sth160488 /*
23936842Sth160488 * get ldaprc, controls, and error msg
23946842Sth160488 */
23956842Sth160488 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
23966842Sth160488 &errmsg, NULL, &controls, 1);
23976842Sth160488
23986842Sth160488 if (ldap_rc != LDAP_SUCCESS) {
23996842Sth160488 (void) snprintf(errstr, sizeof (errstr),
24006842Sth160488 gettext("openConnection: simple bind failed "
24016842Sth160488 "- unable to parse result"));
24026842Sth160488 (void) ldap_unbind(ld);
24036842Sth160488 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
24046842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
24056842Sth160488 return (NS_LDAP_INTERNAL);
24066842Sth160488 }
24076842Sth160488
24086842Sth160488 /* process the password management info, if any */
24096842Sth160488 ret_code = process_pwd_mgmt("simple",
24106842Sth160488 errnum, controls, errmsg,
24116842Sth160488 errorp,
24126842Sth160488 fail_if_new_pwd_reqd,
24136842Sth160488 passwd_mgmt);
24146842Sth160488
24156842Sth160488 if (ret_code == NS_LDAP_INTERNAL) {
24166842Sth160488 (void) ldap_unbind(ld);
24176842Sth160488 }
24186842Sth160488
24196842Sth160488 return (ret_code);
24206842Sth160488 }
24216842Sth160488
24226842Sth160488 /*
24236842Sth160488 * This finction performs a SASL bind operation. If an error accures,
24246842Sth160488 * the function returns an NS error code and provides an additional info
24256842Sth160488 * pointed by *errorp.
24266842Sth160488 */
24276842Sth160488 static
24286842Sth160488 ns_ldap_return_code
doSASLBind(const ns_cred_t * auth,LDAP * ld,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt)24296842Sth160488 doSASLBind(const ns_cred_t *auth,
24306842Sth160488 LDAP *ld,
24316842Sth160488 int timeoutSec,
24326842Sth160488 ns_ldap_error_t **errorp,
24336842Sth160488 int fail_if_new_pwd_reqd,
24346842Sth160488 int passwd_mgmt)
24356842Sth160488 {
24366842Sth160488 char *binddn, *passwd, *digest_md5_name,
24376842Sth160488 errstr[MAXERROR], *errmsg;
24386842Sth160488 struct berval cred;
24396842Sth160488 int ldap_rc, errnum = 0;
24406842Sth160488 ns_ldap_return_code ret_code;
24416842Sth160488 struct timeval tv;
24426842Sth160488 LDAPMessage *resultMsg;
24436842Sth160488 LDAPControl **controls;
24446842Sth160488 int min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF;
24456842Sth160488 ns_sasl_cb_param_t sasl_param;
24466842Sth160488
24476842Sth160488 if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE &&
24486842Sth160488 auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
24496842Sth160488 (void) sprintf(errstr,
24506842Sth160488 gettext("openConnection: SASL options are "
24516842Sth160488 "not supported (%d) for non-GSSAPI sasl bind"),
24526842Sth160488 auth->auth.saslopt);
24536842Sth160488 MKERROR(LOG_WARNING, *errorp,
24546842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED,
24556842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
24566842Sth160488 (void) ldap_unbind(ld);
24576842Sth160488 return (NS_LDAP_INTERNAL);
24586842Sth160488 }
24596842Sth160488 if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
24606842Sth160488 binddn = auth->cred.unix_cred.userID;
24616842Sth160488 passwd = auth->cred.unix_cred.passwd;
24626842Sth160488 if (passwd == NULL || *passwd == '\0' ||
24636842Sth160488 binddn == NULL || *binddn == '\0') {
24646842Sth160488 (void) sprintf(errstr,
24656842Sth160488 gettext("openConnection: missing credentials "
24666842Sth160488 "for SASL bind"));
24676842Sth160488 MKERROR(LOG_WARNING, *errorp,
24686842Sth160488 LDAP_INVALID_CREDENTIALS,
24696842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
24706842Sth160488 (void) ldap_unbind(ld);
24716842Sth160488 return (NS_LDAP_INTERNAL);
24726842Sth160488 }
24736842Sth160488 cred.bv_val = passwd;
24746842Sth160488 cred.bv_len = strlen(passwd);
24756842Sth160488 }
24766842Sth160488
24776842Sth160488 ret_code = NS_LDAP_SUCCESS;
24786842Sth160488
24796842Sth160488 switch (auth->auth.saslmech) {
24806842Sth160488 case NS_LDAP_SASL_CRAM_MD5:
24816842Sth160488 /*
24826842Sth160488 * NOTE: if iDS changes to support cram_md5,
24836842Sth160488 * please add password management code here.
24846842Sth160488 * Since ldap_sasl_cram_md5_bind_s does not
24856842Sth160488 * return anything that could be used to
24866842Sth160488 * extract the ldap rc/errmsg/control to
24876842Sth160488 * determine if bind failed due to password
24886842Sth160488 * policy, a new cram_md5_bind API will need
24896842Sth160488 * to be introduced. See
24906842Sth160488 * ldap_x_sasl_digest_md5_bind() and case
24916842Sth160488 * NS_LDAP_SASL_DIGEST_MD5 below for details.
24926842Sth160488 */
24936842Sth160488 if ((ldap_rc = ldap_sasl_cram_md5_bind_s(ld, binddn,
24946842Sth160488 &cred, NULL, NULL)) != LDAP_SUCCESS) {
24956842Sth160488 (void) ldap_get_option(ld,
24966842Sth160488 LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
24976842Sth160488 (void) snprintf(errstr, sizeof (errstr),
24986842Sth160488 gettext("openConnection: "
24996842Sth160488 "sasl/CRAM-MD5 bind failed - %s"),
25006842Sth160488 ldap_err2string(errnum));
25016842Sth160488 MKERROR(LOG_WARNING, *errorp, errnum,
25026842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
25036842Sth160488 (void) ldap_unbind(ld);
25046842Sth160488 return (NS_LDAP_INTERNAL);
25056842Sth160488 }
25066842Sth160488 break;
25076842Sth160488 case NS_LDAP_SASL_DIGEST_MD5:
25086842Sth160488 digest_md5_name = malloc(strlen(binddn) + 5);
25096842Sth160488 /* 5 = strlen("dn: ") + 1 */
25106842Sth160488 if (digest_md5_name == NULL) {
25116842Sth160488 (void) ldap_unbind(ld);
25126842Sth160488 return (NS_LDAP_MEMORY);
25136842Sth160488 }
25146842Sth160488 (void) strcpy(digest_md5_name, "dn: ");
25156842Sth160488 (void) strcat(digest_md5_name, binddn);
25166842Sth160488
25176842Sth160488 tv.tv_sec = timeoutSec;
25186842Sth160488 tv.tv_usec = 0;
25196842Sth160488 ldap_rc = ldap_x_sasl_digest_md5_bind(ld,
25206842Sth160488 digest_md5_name, &cred, NULL, NULL,
25216842Sth160488 &tv, &resultMsg);
25226842Sth160488
25236842Sth160488 if (resultMsg == NULL) {
25246842Sth160488 free(digest_md5_name);
25256842Sth160488 (void) ldap_get_option(ld,
25266842Sth160488 LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
25276842Sth160488 (void) snprintf(errstr, sizeof (errstr),
25286842Sth160488 gettext("openConnection: "
25296842Sth160488 "DIGEST-MD5 bind failed - %s"),
25306842Sth160488 ldap_err2string(errnum));
25316842Sth160488 (void) ldap_unbind(ld);
25326842Sth160488 MKERROR(LOG_WARNING, *errorp, errnum,
25336842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
25346842Sth160488 return (NS_LDAP_INTERNAL);
25356842Sth160488 }
25366842Sth160488
25376842Sth160488 /*
25386842Sth160488 * get ldaprc, controls, and error msg
25396842Sth160488 */
25406842Sth160488 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
25416842Sth160488 &errmsg, NULL, &controls, 1);
25426842Sth160488
25436842Sth160488 if (ldap_rc != LDAP_SUCCESS) {
25446842Sth160488 free(digest_md5_name);
25456842Sth160488 (void) snprintf(errstr, sizeof (errstr),
25466842Sth160488 gettext("openConnection: "
25476842Sth160488 "DIGEST-MD5 bind failed "
25486842Sth160488 "- unable to parse result"));
25496842Sth160488 (void) ldap_unbind(ld);
25506842Sth160488 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
25516842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
25526842Sth160488 return (NS_LDAP_INTERNAL);
25536842Sth160488 }
25546842Sth160488
25556842Sth160488 /* process the password management info, if any */
25566842Sth160488 ret_code = process_pwd_mgmt("sasl/DIGEST-MD5",
25576842Sth160488 errnum, controls, errmsg,
25586842Sth160488 errorp,
25596842Sth160488 fail_if_new_pwd_reqd,
25606842Sth160488 passwd_mgmt);
25616842Sth160488
25626842Sth160488 if (ret_code == NS_LDAP_INTERNAL) {
25636842Sth160488 (void) ldap_unbind(ld);
25646842Sth160488 }
25656842Sth160488
25666842Sth160488 free(digest_md5_name);
25676842Sth160488 break;
25686842Sth160488 case NS_LDAP_SASL_GSSAPI:
25696842Sth160488 (void) memset(&sasl_param, 0,
25706842Sth160488 sizeof (ns_sasl_cb_param_t));
25716842Sth160488 sasl_param.authid = NULL;
25726842Sth160488 sasl_param.authzid = "";
25736842Sth160488 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN,
25746842Sth160488 (void *)&min_ssf);
25756842Sth160488 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX,
25766842Sth160488 (void *)&max_ssf);
25776842Sth160488
25786842Sth160488 ldap_rc = ldap_sasl_interactive_bind_s(
25796842Sth160488 ld, NULL, "GSSAPI",
25806842Sth160488 NULL, NULL, LDAP_SASL_INTERACTIVE,
25816842Sth160488 __s_api_sasl_bind_callback,
25826842Sth160488 &sasl_param);
25836842Sth160488
25846842Sth160488 if (ldap_rc != LDAP_SUCCESS) {
25856842Sth160488 (void) snprintf(errstr, sizeof (errstr),
25866842Sth160488 gettext("openConnection: "
25876842Sth160488 "GSSAPI bind failed "
25886842Sth160488 "- %d %s"),
25896842Sth160488 ldap_rc,
25906842Sth160488 ldap_err2string(ldap_rc));
25916842Sth160488 (void) ldap_unbind(ld);
25926842Sth160488 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
25936842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
25946842Sth160488 return (NS_LDAP_INTERNAL);
25956842Sth160488 }
25966842Sth160488
25976842Sth160488 break;
25986842Sth160488 default:
25996842Sth160488 (void) ldap_unbind(ld);
26006842Sth160488 (void) sprintf(errstr,
26016842Sth160488 gettext("openConnection: unsupported SASL "
26026842Sth160488 "mechanism (%d)"), auth->auth.saslmech);
26036842Sth160488 MKERROR(LOG_WARNING, *errorp,
26046842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
26056842Sth160488 NS_LDAP_MEMORY);
26066842Sth160488 return (NS_LDAP_INTERNAL);
26076842Sth160488 }
26086842Sth160488
26096842Sth160488 return (ret_code);
26106842Sth160488 }
26116842Sth160488
26126842Sth160488 /*
26136842Sth160488 * This function performs an LDAP Bind operation proceeding
26146842Sth160488 * from a type of the connection specified by auth->auth.type.
26156842Sth160488 *
26166842Sth160488 * INPUT:
26176842Sth160488 * auth - a structure specified an authenticastion method and credentials,
26186842Sth160488 * ld - a pointer returned by the createSession() function,
26196842Sth160488 * timeoutSec - a timeout in seconds for the Bind operation,
26206842Sth160488 * fail_if_new_pwd_reqd - a flag indicating that the call should fail
26216842Sth160488 * if a new password is required,
26226842Sth160488 * passwd_mgmt - a flag indicating that the server supports
26236842Sth160488 * password management.
26246842Sth160488 *
26256842Sth160488 * OUTPUT:
26266842Sth160488 * If an error accures, the function returns an NS error code
26276842Sth160488 * and provides an additional info pointed by *errorp.
26286842Sth160488 */
26296842Sth160488 static
26306842Sth160488 ns_ldap_return_code
performBind(const ns_cred_t * auth,LDAP * ld,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt)26316842Sth160488 performBind(const ns_cred_t *auth,
26326842Sth160488 LDAP *ld,
26336842Sth160488 int timeoutSec,
26346842Sth160488 ns_ldap_error_t **errorp,
26356842Sth160488 int fail_if_new_pwd_reqd,
26366842Sth160488 int passwd_mgmt)
26376842Sth160488 {
26386842Sth160488 int bindType;
26396842Sth160488 char errstr[MAXERROR];
26406842Sth160488
26416842Sth160488 ns_ldap_return_code (*binder)(const ns_cred_t *auth,
26426842Sth160488 LDAP *ld,
26436842Sth160488 int timeoutSec,
26446842Sth160488 ns_ldap_error_t **errorp,
26456842Sth160488 int fail_if_new_pwd_reqd,
26466842Sth160488 int passwd_mgmt) = NULL;
26476842Sth160488
26486842Sth160488 if (!ld) {
26496842Sth160488 (void) sprintf(errstr,
26506842Sth160488 "performBind: LDAP session "
26516842Sth160488 "is not initialized.");
26526842Sth160488 MKERROR(LOG_WARNING, *errorp,
26536842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED,
26546842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
26556842Sth160488 return (NS_LDAP_INTERNAL);
26566842Sth160488 }
26576842Sth160488
26586842Sth160488 bindType = auth->auth.type == NS_LDAP_AUTH_TLS ?
26596842Sth160488 auth->auth.tlstype : auth->auth.type;
26606842Sth160488
26616842Sth160488 switch (bindType) {
26626842Sth160488 case NS_LDAP_AUTH_NONE:
26636842Sth160488 #ifdef DEBUG
26646842Sth160488 (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n",
26656842Sth160488 thr_self());
26666842Sth160488 #endif /* DEBUG */
26676842Sth160488 break;
26686842Sth160488 case NS_LDAP_AUTH_SIMPLE:
26696842Sth160488 binder = doSimpleBind;
26706842Sth160488 break;
26716842Sth160488 case NS_LDAP_AUTH_SASL:
26726842Sth160488 binder = doSASLBind;
26736842Sth160488 break;
26746842Sth160488 default:
26756842Sth160488 (void) sprintf(errstr,
26766842Sth160488 gettext("openConnection: unsupported "
26776842Sth160488 "authentication method "
26786842Sth160488 "(%d)"), bindType);
26796842Sth160488 MKERROR(LOG_WARNING, *errorp,
26806842Sth160488 LDAP_AUTH_METHOD_NOT_SUPPORTED,
26816842Sth160488 strdup(errstr), NS_LDAP_MEMORY);
26826842Sth160488 (void) ldap_unbind(ld);
26836842Sth160488 return (NS_LDAP_INTERNAL);
26846842Sth160488 }
26856842Sth160488
26866842Sth160488 if (binder != NULL) {
26876842Sth160488 return (*binder)(auth,
26886842Sth160488 ld,
26896842Sth160488 timeoutSec,
26906842Sth160488 errorp,
26916842Sth160488 fail_if_new_pwd_reqd,
26926842Sth160488 passwd_mgmt);
26936842Sth160488 }
26946842Sth160488
26956842Sth160488 return (NS_LDAP_SUCCESS);
26966842Sth160488 }
2697