xref: /titanic_44/usr/src/lib/libsldap/common/ns_connect.c (revision b3b48d8e61fb04617f1a22d673c555b155f02e64)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5689c2bf4Sjanga  * Common Development and Distribution License (the "License").
6689c2bf4Sjanga  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215ad42b1bSSurya Prakki 
227c478bd9Sstevel@tonic-gate /*
23442384bbSJulian Pullen  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24*b3b48d8eSHans Rosenfeld  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <errno.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <synch.h>
327c478bd9Sstevel@tonic-gate #include <time.h>
337c478bd9Sstevel@tonic-gate #include <libintl.h>
347c478bd9Sstevel@tonic-gate #include <thread.h>
357c478bd9Sstevel@tonic-gate #include <syslog.h>
367c478bd9Sstevel@tonic-gate #include <sys/mman.h>
377c478bd9Sstevel@tonic-gate #include <nsswitch.h>
387c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
397c478bd9Sstevel@tonic-gate #include "solaris-priv.h"
40cb5caa98Sdjl #include "solaris-int.h"
417c478bd9Sstevel@tonic-gate #include "ns_sldap.h"
427c478bd9Sstevel@tonic-gate #include "ns_internal.h"
437c478bd9Sstevel@tonic-gate #include "ns_cache_door.h"
44e1dd0a2fSth160488 #include "ns_connmgmt.h"
45da80a4abSjanga #include "ldappr.h"
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <fcntl.h>
487c478bd9Sstevel@tonic-gate #include <procfs.h>
497c478bd9Sstevel@tonic-gate #include <unistd.h>
507c478bd9Sstevel@tonic-gate 
51e1dd0a2fSth160488 #define	USE_DEFAULT_PORT 0
52e1dd0a2fSth160488 
53e1dd0a2fSth160488 static ns_ldap_return_code performBind(const ns_cred_t *,
54e1dd0a2fSth160488 					LDAP *,
55e1dd0a2fSth160488 					int,
56e1dd0a2fSth160488 					ns_ldap_error_t **,
57e1dd0a2fSth160488 					int,
58e1dd0a2fSth160488 					int);
59e1dd0a2fSth160488 static ns_ldap_return_code createSession(const ns_cred_t *,
60e1dd0a2fSth160488 					const char *,
61e1dd0a2fSth160488 					uint16_t,
62e1dd0a2fSth160488 					int,
63e1dd0a2fSth160488 					LDAP **,
64e1dd0a2fSth160488 					ns_ldap_error_t **);
65e1dd0a2fSth160488 
667c478bd9Sstevel@tonic-gate extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *,
677c478bd9Sstevel@tonic-gate 		LDAPControl **, LDAPControl **);
687c478bd9Sstevel@tonic-gate extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip);
697c478bd9Sstevel@tonic-gate 
70b57459abSJulian Pullen extern int __door_getconf(char **buffer, int *buflen,
71b57459abSJulian Pullen 		ns_ldap_error_t **error, int callnumber);
72b57459abSJulian Pullen extern int __ns_ldap_freeUnixCred(UnixCred_t **credp);
73b57459abSJulian Pullen extern int SetDoorInfoToUnixCred(char *buffer,
74b57459abSJulian Pullen 		ns_ldap_error_t **errorp,
75b57459abSJulian Pullen 		UnixCred_t **cred);
76b57459abSJulian Pullen 
777c478bd9Sstevel@tonic-gate static int openConnection(LDAP **, const char *, const ns_cred_t *,
786ad9980eSJulian Pullen 		int, ns_ldap_error_t **, int, int, ns_conn_user_t *, int);
79a1e48794Schinlong static void
80a1e48794Schinlong _DropConnection(ConnectionID cID, int flag, int fini);
81e1dd0a2fSth160488 
82e1dd0a2fSth160488 static mutex_t sessionPoolLock = DEFAULTMUTEX;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate static Connection **sessionPool = NULL;
857c478bd9Sstevel@tonic-gate static int sessionPoolSize = 0;
867c478bd9Sstevel@tonic-gate 
87cb5caa98Sdjl /*
88cb5caa98Sdjl  * SSF values are for SASL integrity & privacy.
89cb5caa98Sdjl  * JES DS5.2 does not support this feature but DS6 does.
90cb5caa98Sdjl  * The values between 0 and 65535 can work with both server versions.
91cb5caa98Sdjl  */
92cb5caa98Sdjl #define	MAX_SASL_SSF	65535
93cb5caa98Sdjl #define	MIN_SASL_SSF	0
947c478bd9Sstevel@tonic-gate 
95689c2bf4Sjanga /* Number of hostnames to allocate memory for */
96689c2bf4Sjanga #define	NUMTOMALLOC	32
97cb5caa98Sdjl 
98cb5caa98Sdjl /*
99e1dd0a2fSth160488  * This function get the servers from the lists and returns
100e1dd0a2fSth160488  * the first server with the empty lists of server controls and
101e1dd0a2fSth160488  * SASL mechanisms. It is invoked if it is not possible to obtain a server
102e1dd0a2fSth160488  * from ldap_cachemgr or the local list.
103cb5caa98Sdjl  */
104e1dd0a2fSth160488 static
105e1dd0a2fSth160488 ns_ldap_return_code
getFirstFromConfig(ns_server_info_t * ret,ns_ldap_error_t ** error)106e1dd0a2fSth160488 getFirstFromConfig(ns_server_info_t *ret, ns_ldap_error_t **error)
107cb5caa98Sdjl {
108e1dd0a2fSth160488 	char			**servers = NULL;
109e1dd0a2fSth160488 	ns_ldap_return_code	ret_code;
110e1dd0a2fSth160488 	char			errstr[MAXERROR];
111cb5caa98Sdjl 
112e1dd0a2fSth160488 	/* get first server from config list unavailable otherwise */
113e1dd0a2fSth160488 	ret_code = __s_api_getServers(&servers, error);
114e1dd0a2fSth160488 	if (ret_code != NS_LDAP_SUCCESS) {
115e1dd0a2fSth160488 		if (servers != NULL) {
116e1dd0a2fSth160488 			__s_api_free2dArray(servers);
117cb5caa98Sdjl 		}
118e1dd0a2fSth160488 		return (ret_code);
119cb5caa98Sdjl 	}
120cb5caa98Sdjl 
121e1dd0a2fSth160488 	if (servers == NULL || servers[0] == NULL) {
122e1dd0a2fSth160488 		__s_api_free2dArray(servers);
123e1dd0a2fSth160488 		(void) sprintf(errstr,
124e1dd0a2fSth160488 		    gettext("No server found in configuration"));
125e1dd0a2fSth160488 		MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT,
126e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
127e1dd0a2fSth160488 		return (NS_LDAP_CONFIG);
128cb5caa98Sdjl 	}
1294bd8a855Smichen 
130e1dd0a2fSth160488 	ret->server = strdup(servers[0]);
131e1dd0a2fSth160488 	if (ret->server == NULL) {
132e1dd0a2fSth160488 		__s_api_free2dArray(servers);
1338277a58bSchinlong 		return (NS_LDAP_MEMORY);
134e1dd0a2fSth160488 	}
135e1dd0a2fSth160488 
136e1dd0a2fSth160488 	ret->saslMechanisms = NULL;
137e1dd0a2fSth160488 	ret->controls = NULL;
138e1dd0a2fSth160488 
139e1dd0a2fSth160488 	__s_api_free2dArray(servers);
1408277a58bSchinlong 
1418277a58bSchinlong 	return (NS_LDAP_SUCCESS);
1428277a58bSchinlong }
1438277a58bSchinlong 
144b57459abSJulian Pullen /* very similar to __door_getldapconfig() in ns_config.c */
145b57459abSJulian Pullen static int
__door_getadmincred(char ** buffer,int * buflen,ns_ldap_error_t ** error)146b57459abSJulian Pullen __door_getadmincred(char **buffer, int *buflen, ns_ldap_error_t **error)
147b57459abSJulian Pullen {
148b57459abSJulian Pullen 	return (__door_getconf(buffer, buflen, error, GETADMINCRED));
149b57459abSJulian Pullen }
150b57459abSJulian Pullen 
151b57459abSJulian Pullen /*
152b57459abSJulian Pullen  * This function requests Admin credentials from the cache manager through
153b57459abSJulian Pullen  * the door functionality
154b57459abSJulian Pullen  */
155b57459abSJulian Pullen 
156b57459abSJulian Pullen static int
requestAdminCred(UnixCred_t ** cred,ns_ldap_error_t ** error)157b57459abSJulian Pullen requestAdminCred(UnixCred_t **cred, ns_ldap_error_t **error)
158b57459abSJulian Pullen {
159b57459abSJulian Pullen 	char	*buffer = NULL;
160b57459abSJulian Pullen 	int	buflen = 0;
161b57459abSJulian Pullen 	int	ret;
162b57459abSJulian Pullen 
163b57459abSJulian Pullen 	*error = NULL;
164b57459abSJulian Pullen 	ret = __door_getadmincred(&buffer, &buflen, error);
165b57459abSJulian Pullen 
166b57459abSJulian Pullen 	if (ret != NS_LDAP_SUCCESS) {
167b57459abSJulian Pullen 		if (*error != NULL && (*error)->message != NULL)
168b57459abSJulian Pullen 			syslog(LOG_WARNING, "libsldap: %s", (*error)->message);
169b57459abSJulian Pullen 		return (ret);
170b57459abSJulian Pullen 	}
171b57459abSJulian Pullen 
172b57459abSJulian Pullen 	/* now convert from door format */
173b57459abSJulian Pullen 	ret = SetDoorInfoToUnixCred(buffer, error, cred);
174b57459abSJulian Pullen 	free(buffer);
175b57459abSJulian Pullen 
176b57459abSJulian Pullen 	return (ret);
177b57459abSJulian Pullen }
178b57459abSJulian Pullen 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * This function requests a server from the cache manager through
1817c478bd9Sstevel@tonic-gate  * the door functionality
1827c478bd9Sstevel@tonic-gate  */
1837c478bd9Sstevel@tonic-gate 
184e1dd0a2fSth160488 int
__s_api_requestServer(const char * request,const char * server,ns_server_info_t * ret,ns_ldap_error_t ** error,const char * addrType)1857c478bd9Sstevel@tonic-gate __s_api_requestServer(const char *request, const char *server,
186cb5caa98Sdjl 	ns_server_info_t *ret, ns_ldap_error_t **error,  const char *addrType)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	union {
1897c478bd9Sstevel@tonic-gate 		ldap_data_t	s_d;
1907c478bd9Sstevel@tonic-gate 		char		s_b[DOORBUFFERSIZE];
1917c478bd9Sstevel@tonic-gate 	} space;
1927c478bd9Sstevel@tonic-gate 	ldap_data_t		*sptr;
1937c478bd9Sstevel@tonic-gate 	int			ndata;
1947c478bd9Sstevel@tonic-gate 	int			adata;
1957c478bd9Sstevel@tonic-gate 	char			errstr[MAXERROR];
1967c478bd9Sstevel@tonic-gate 	const char		*ireq;
1977c478bd9Sstevel@tonic-gate 	char			*rbuf, *ptr, *rest;
1987c478bd9Sstevel@tonic-gate 	char			*dptr;
1997c478bd9Sstevel@tonic-gate 	char			**mptr, **mptr1, **cptr, **cptr1;
2007c478bd9Sstevel@tonic-gate 	int			mcnt, ccnt;
201e1dd0a2fSth160488 	int			len;
202e1dd0a2fSth160488 	ns_ldap_return_code	ret_code;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if (ret == NULL || error == NULL) {
2057c478bd9Sstevel@tonic-gate 		return (NS_LDAP_OP_FAILED);
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 	(void) memset(ret, 0, sizeof (ns_server_info_t));
2087c478bd9Sstevel@tonic-gate 	*error = NULL;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (request == NULL)
2117c478bd9Sstevel@tonic-gate 		ireq = NS_CACHE_NEW;
2127c478bd9Sstevel@tonic-gate 	else
2137c478bd9Sstevel@tonic-gate 		ireq = request;
2147c478bd9Sstevel@tonic-gate 
215e1dd0a2fSth160488 	/*
216e1dd0a2fSth160488 	 * In the 'Standalone' mode a server will be obtained
217e1dd0a2fSth160488 	 * from the local libsldap's list
218e1dd0a2fSth160488 	 */
219e1dd0a2fSth160488 	if (__s_api_isStandalone()) {
22029836b19Smichen 		if ((ret_code = __s_api_findRootDSE(ireq,
221e1dd0a2fSth160488 		    server,
222e1dd0a2fSth160488 		    addrType,
223e1dd0a2fSth160488 		    ret,
22429836b19Smichen 		    error)) != NS_LDAP_SUCCESS) {
22529836b19Smichen 			/*
22629836b19Smichen 			 * get first server from local list only once
22729836b19Smichen 			 * to prevent looping
22829836b19Smichen 			 */
22929836b19Smichen 			if (strcmp(ireq, NS_CACHE_NEW) != 0)
23029836b19Smichen 				return (ret_code);
23129836b19Smichen 
232e1dd0a2fSth160488 			syslog(LOG_WARNING,
233e1dd0a2fSth160488 			    "libsldap (\"standalone\" mode): "
234e1dd0a2fSth160488 			    "can not find any available server. "
235e1dd0a2fSth160488 			    "Return the first one from the lists");
236e1dd0a2fSth160488 			if (*error != NULL) {
237e1dd0a2fSth160488 				(void) __ns_ldap_freeError(error);
238e1dd0a2fSth160488 			}
239e1dd0a2fSth160488 
240e1dd0a2fSth160488 			ret_code = getFirstFromConfig(ret, error);
241e1dd0a2fSth160488 			if (ret_code != NS_LDAP_SUCCESS) {
242e1dd0a2fSth160488 				return (ret_code);
243e1dd0a2fSth160488 			}
244e1dd0a2fSth160488 
245e1dd0a2fSth160488 			if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
246e1dd0a2fSth160488 				ret_code = __s_api_ip2hostname(ret->server,
247e1dd0a2fSth160488 				    &ret->serverFQDN);
248e1dd0a2fSth160488 				if (ret_code != NS_LDAP_SUCCESS) {
249e1dd0a2fSth160488 					(void) snprintf(errstr,
250e1dd0a2fSth160488 					    sizeof (errstr),
251e1dd0a2fSth160488 					    gettext("The %s address "
252e1dd0a2fSth160488 					    "can not be resolved into "
253e1dd0a2fSth160488 					    "a host name. Returning "
254e1dd0a2fSth160488 					    "the address as it is."),
255e1dd0a2fSth160488 					    ret->server);
256e1dd0a2fSth160488 					MKERROR(LOG_ERR,
257e1dd0a2fSth160488 					    *error,
258e1dd0a2fSth160488 					    NS_CONFIG_NOTLOADED,
259e1dd0a2fSth160488 					    strdup(errstr),
260e1dd0a2fSth160488 					    NS_LDAP_MEMORY);
261e1dd0a2fSth160488 					free(ret->server);
262e1dd0a2fSth160488 					ret->server = NULL;
263e1dd0a2fSth160488 					return (NS_LDAP_INTERNAL);
264e1dd0a2fSth160488 				}
265e1dd0a2fSth160488 			}
266e1dd0a2fSth160488 		}
267e1dd0a2fSth160488 
268e1dd0a2fSth160488 		return (NS_LDAP_SUCCESS);
269e1dd0a2fSth160488 	}
270e1dd0a2fSth160488 
271e1dd0a2fSth160488 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
272e1dd0a2fSth160488 
273cb5caa98Sdjl 	adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1);
2747c478bd9Sstevel@tonic-gate 	if (server != NULL) {
2757c478bd9Sstevel@tonic-gate 		adata += strlen(DOORLINESEP) + 1;
2767c478bd9Sstevel@tonic-gate 		adata += strlen(server) + 1;
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 	ndata = sizeof (space);
279cb5caa98Sdjl 	len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
2807c478bd9Sstevel@tonic-gate 	space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
281cb5caa98Sdjl 	if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
282cb5caa98Sdjl 		return (NS_LDAP_MEMORY);
283cb5caa98Sdjl 	if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >=
284cb5caa98Sdjl 	    len)
285cb5caa98Sdjl 		return (NS_LDAP_MEMORY);
2867c478bd9Sstevel@tonic-gate 	if (server != NULL) {
287cb5caa98Sdjl 		if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
288cb5caa98Sdjl 		    DOORLINESEP, len) >= len)
289cb5caa98Sdjl 			return (NS_LDAP_MEMORY);
290cb5caa98Sdjl 		if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server,
291cb5caa98Sdjl 		    len) >= len)
292cb5caa98Sdjl 			return (NS_LDAP_MEMORY);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	sptr = &space.s_d;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
297e1dd0a2fSth160488 	case NS_CACHE_SUCCESS:
2987c478bd9Sstevel@tonic-gate 		break;
2997c478bd9Sstevel@tonic-gate 	/* this case is for when the $mgr is not running, but ldapclient */
3007c478bd9Sstevel@tonic-gate 	/* is trying to initialize things */
301e1dd0a2fSth160488 	case NS_CACHE_NOSERVER:
302e1dd0a2fSth160488 		ret_code = getFirstFromConfig(ret, error);
303e1dd0a2fSth160488 		if (ret_code != NS_LDAP_SUCCESS) {
304e1dd0a2fSth160488 			return (ret_code);
3057c478bd9Sstevel@tonic-gate 		}
306e1dd0a2fSth160488 
307e1dd0a2fSth160488 		if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
308e1dd0a2fSth160488 			ret_code = __s_api_ip2hostname(ret->server,
309e1dd0a2fSth160488 			    &ret->serverFQDN);
310e1dd0a2fSth160488 			if (ret_code != NS_LDAP_SUCCESS) {
311e1dd0a2fSth160488 				(void) snprintf(errstr,
312e1dd0a2fSth160488 				    sizeof (errstr),
313e1dd0a2fSth160488 				    gettext("The %s address "
314e1dd0a2fSth160488 				    "can not be resolved into "
315e1dd0a2fSth160488 				    "a host name. Returning "
316e1dd0a2fSth160488 				    "the address as it is."),
317e1dd0a2fSth160488 				    ret->server);
318e1dd0a2fSth160488 				MKERROR(LOG_ERR,
319e1dd0a2fSth160488 				    *error,
320e1dd0a2fSth160488 				    NS_CONFIG_NOTLOADED,
321e1dd0a2fSth160488 				    strdup(errstr),
322e1dd0a2fSth160488 				    NS_LDAP_MEMORY);
323e1dd0a2fSth160488 				free(ret->server);
324e1dd0a2fSth160488 				ret->server = NULL;
325e1dd0a2fSth160488 				return (NS_LDAP_INTERNAL);
3267c478bd9Sstevel@tonic-gate 			}
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
329e1dd0a2fSth160488 	case NS_CACHE_NOTFOUND:
3307c478bd9Sstevel@tonic-gate 	default:
3317c478bd9Sstevel@tonic-gate 		return (NS_LDAP_OP_FAILED);
3327c478bd9Sstevel@tonic-gate 	}
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/* copy info from door call return structure here */
3357c478bd9Sstevel@tonic-gate 	rbuf =  space.s_d.ldap_ret.ldap_u.config;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	/* Get the host */
3387c478bd9Sstevel@tonic-gate 	ptr = strtok_r(rbuf, DOORLINESEP, &rest);
3397c478bd9Sstevel@tonic-gate 	if (ptr == NULL) {
3407c478bd9Sstevel@tonic-gate 		(void) sprintf(errstr, gettext("No server returned from "
3417c478bd9Sstevel@tonic-gate 		    "ldap_cachemgr"));
3427c478bd9Sstevel@tonic-gate 		MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
343e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
3447c478bd9Sstevel@tonic-gate 		return (NS_LDAP_OP_FAILED);
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 	ret->server = strdup(ptr);
3477c478bd9Sstevel@tonic-gate 	if (ret->server == NULL) {
3487c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
3497c478bd9Sstevel@tonic-gate 	}
3504a6b6ac4Schinlong 	/* Get the host FQDN format */
3514a6b6ac4Schinlong 	if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
3524a6b6ac4Schinlong 		ptr = strtok_r(NULL, DOORLINESEP, &rest);
3534a6b6ac4Schinlong 		if (ptr == NULL) {
3544a6b6ac4Schinlong 			(void) sprintf(errstr, gettext("No server FQDN format "
3554a6b6ac4Schinlong 			    "returned from ldap_cachemgr"));
3564a6b6ac4Schinlong 			MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
3574a6b6ac4Schinlong 			    strdup(errstr), NULL);
3584a6b6ac4Schinlong 			free(ret->server);
3594a6b6ac4Schinlong 			ret->server = NULL;
3604a6b6ac4Schinlong 			return (NS_LDAP_OP_FAILED);
3614a6b6ac4Schinlong 		}
3624a6b6ac4Schinlong 		ret->serverFQDN = strdup(ptr);
3634a6b6ac4Schinlong 		if (ret->serverFQDN == NULL) {
3644a6b6ac4Schinlong 			free(ret->server);
3654a6b6ac4Schinlong 			ret->server = NULL;
3664a6b6ac4Schinlong 			return (NS_LDAP_MEMORY);
3674a6b6ac4Schinlong 		}
3684a6b6ac4Schinlong 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	/* get the Supported Controls/SASL mechs */
3717c478bd9Sstevel@tonic-gate 	mptr = NULL;
3727c478bd9Sstevel@tonic-gate 	mcnt = 0;
3737c478bd9Sstevel@tonic-gate 	cptr = NULL;
3747c478bd9Sstevel@tonic-gate 	ccnt = 0;
3757c478bd9Sstevel@tonic-gate 	for (;;) {
3767c478bd9Sstevel@tonic-gate 		ptr = strtok_r(NULL, DOORLINESEP, &rest);
3777c478bd9Sstevel@tonic-gate 		if (ptr == NULL)
3787c478bd9Sstevel@tonic-gate 			break;
3797c478bd9Sstevel@tonic-gate 		if (strncasecmp(ptr, _SASLMECHANISM,
3807c478bd9Sstevel@tonic-gate 		    _SASLMECHANISM_LEN) == 0) {
3817c478bd9Sstevel@tonic-gate 			dptr = strchr(ptr, '=');
3827c478bd9Sstevel@tonic-gate 			if (dptr == NULL)
3837c478bd9Sstevel@tonic-gate 				continue;
3847c478bd9Sstevel@tonic-gate 			dptr++;
3857c478bd9Sstevel@tonic-gate 			mptr1 = (char **)realloc((void *)mptr,
3867c478bd9Sstevel@tonic-gate 			    sizeof (char *) * (mcnt+2));
3877c478bd9Sstevel@tonic-gate 			if (mptr1 == NULL) {
3887c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(mptr);
3897c478bd9Sstevel@tonic-gate 				if (sptr != &space.s_d) {
3907c478bd9Sstevel@tonic-gate 					(void) munmap((char *)sptr, ndata);
3917c478bd9Sstevel@tonic-gate 				}
3927c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(cptr);
3934a6b6ac4Schinlong 				__s_api_free_server_info(ret);
3947c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
3957c478bd9Sstevel@tonic-gate 			}
3967c478bd9Sstevel@tonic-gate 			mptr = mptr1;
3977c478bd9Sstevel@tonic-gate 			mptr[mcnt] = strdup(dptr);
3987c478bd9Sstevel@tonic-gate 			if (mptr[mcnt] == NULL) {
3997c478bd9Sstevel@tonic-gate 				if (sptr != &space.s_d) {
4007c478bd9Sstevel@tonic-gate 					(void) munmap((char *)sptr, ndata);
4017c478bd9Sstevel@tonic-gate 				}
4027c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(cptr);
4037c478bd9Sstevel@tonic-gate 				cptr = NULL;
4047c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(mptr);
4057c478bd9Sstevel@tonic-gate 				mptr = NULL;
4064a6b6ac4Schinlong 				__s_api_free_server_info(ret);
4077c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
4087c478bd9Sstevel@tonic-gate 			}
4097c478bd9Sstevel@tonic-gate 			mcnt++;
4107c478bd9Sstevel@tonic-gate 			mptr[mcnt] = NULL;
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 		if (strncasecmp(ptr, _SUPPORTEDCONTROL,
4137c478bd9Sstevel@tonic-gate 		    _SUPPORTEDCONTROL_LEN) == 0) {
4147c478bd9Sstevel@tonic-gate 			dptr = strchr(ptr, '=');
4157c478bd9Sstevel@tonic-gate 			if (dptr == NULL)
4167c478bd9Sstevel@tonic-gate 				continue;
4177c478bd9Sstevel@tonic-gate 			dptr++;
4187c478bd9Sstevel@tonic-gate 			cptr1 = (char **)realloc((void *)cptr,
4197c478bd9Sstevel@tonic-gate 			    sizeof (char *) * (ccnt+2));
4207c478bd9Sstevel@tonic-gate 			if (cptr1 == NULL) {
4217c478bd9Sstevel@tonic-gate 				if (sptr != &space.s_d) {
4227c478bd9Sstevel@tonic-gate 					(void) munmap((char *)sptr, ndata);
4237c478bd9Sstevel@tonic-gate 				}
4247c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(cptr);
4257c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(mptr);
4267c478bd9Sstevel@tonic-gate 				mptr = NULL;
4274a6b6ac4Schinlong 				__s_api_free_server_info(ret);
4287c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
4297c478bd9Sstevel@tonic-gate 			}
4307c478bd9Sstevel@tonic-gate 			cptr = cptr1;
4317c478bd9Sstevel@tonic-gate 			cptr[ccnt] = strdup(dptr);
4327c478bd9Sstevel@tonic-gate 			if (cptr[ccnt] == NULL) {
4337c478bd9Sstevel@tonic-gate 				if (sptr != &space.s_d) {
4347c478bd9Sstevel@tonic-gate 					(void) munmap((char *)sptr, ndata);
4357c478bd9Sstevel@tonic-gate 				}
4367c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(cptr);
4377c478bd9Sstevel@tonic-gate 				cptr = NULL;
4387c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(mptr);
4397c478bd9Sstevel@tonic-gate 				mptr = NULL;
4404a6b6ac4Schinlong 				__s_api_free_server_info(ret);
4417c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
4427c478bd9Sstevel@tonic-gate 			}
4437c478bd9Sstevel@tonic-gate 			ccnt++;
4447c478bd9Sstevel@tonic-gate 			cptr[ccnt] = NULL;
4457c478bd9Sstevel@tonic-gate 		}
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 	if (mptr != NULL) {
4487c478bd9Sstevel@tonic-gate 		ret->saslMechanisms = mptr;
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 	if (cptr != NULL) {
4517c478bd9Sstevel@tonic-gate 		ret->controls = cptr;
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	/* clean up door call */
4567c478bd9Sstevel@tonic-gate 	if (sptr != &space.s_d) {
4577c478bd9Sstevel@tonic-gate 		(void) munmap((char *)sptr, ndata);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 	*error = NULL;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 
465e1dd0a2fSth160488 #ifdef DEBUG
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate  * printCred(): prints the credential structure
4687c478bd9Sstevel@tonic-gate  */
4697c478bd9Sstevel@tonic-gate static void
printCred(FILE * fp,const ns_cred_t * cred)470e1dd0a2fSth160488 printCred(FILE *fp, const ns_cred_t *cred)
4717c478bd9Sstevel@tonic-gate {
472cb5caa98Sdjl 	thread_t	t = thr_self();
473cb5caa98Sdjl 
4747c478bd9Sstevel@tonic-gate 	if (cred == NULL) {
475e1dd0a2fSth160488 		(void) fprintf(fp, "tid= %d: printCred: cred is NULL\n", t);
4767c478bd9Sstevel@tonic-gate 		return;
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
479*b3b48d8eSHans Rosenfeld 	(void) fprintf(fp, "tid= %d: AuthType=%d\n", t, cred->auth.type);
480*b3b48d8eSHans Rosenfeld 	(void) fprintf(fp, "tid= %d: TlsType=%d\n", t, cred->auth.tlstype);
481*b3b48d8eSHans Rosenfeld 	(void) fprintf(fp, "tid= %d: SaslMech=%d\n", t, cred->auth.saslmech);
482*b3b48d8eSHans Rosenfeld 	(void) fprintf(fp, "tid= %d: SaslOpt=%d\n", t, cred->auth.saslopt);
4837c478bd9Sstevel@tonic-gate 	if (cred->hostcertpath)
484e1dd0a2fSth160488 		(void) fprintf(fp, "tid= %d: hostCertPath=%s\n",
485cb5caa98Sdjl 		    t, cred->hostcertpath);
4867c478bd9Sstevel@tonic-gate 	if (cred->cred.unix_cred.userID)
487e1dd0a2fSth160488 		(void) fprintf(fp, "tid= %d: userID=%s\n",
488cb5caa98Sdjl 		    t, cred->cred.unix_cred.userID);
4897c478bd9Sstevel@tonic-gate 	if (cred->cred.unix_cred.passwd)
490e1dd0a2fSth160488 		(void) fprintf(fp, "tid= %d: passwd=%s\n",
491cb5caa98Sdjl 		    t, cred->cred.unix_cred.passwd);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate  * printConnection(): prints the connection structure
4967c478bd9Sstevel@tonic-gate  */
4977c478bd9Sstevel@tonic-gate static void
printConnection(FILE * fp,Connection * con)498e1dd0a2fSth160488 printConnection(FILE *fp, Connection *con)
4997c478bd9Sstevel@tonic-gate {
500cb5caa98Sdjl 	thread_t	t = thr_self();
501cb5caa98Sdjl 
502cb5caa98Sdjl 	if (con == NULL)
5037c478bd9Sstevel@tonic-gate 		return;
5047c478bd9Sstevel@tonic-gate 
505e1dd0a2fSth160488 	(void) fprintf(fp, "tid= %d: connectionID=%d\n", t, con->connectionId);
506e1dd0a2fSth160488 	(void) fprintf(fp, "tid= %d: usedBit=%d\n", t, con->usedBit);
507e1dd0a2fSth160488 	(void) fprintf(fp, "tid= %d: threadID=%d\n", t, con->threadID);
5087c478bd9Sstevel@tonic-gate 	if (con->serverAddr) {
509e1dd0a2fSth160488 		(void) fprintf(fp, "tid= %d: serverAddr=%s\n",
510cb5caa98Sdjl 		    t, con->serverAddr);
5117c478bd9Sstevel@tonic-gate 	}
512e1dd0a2fSth160488 	printCred(fp, con->auth);
5137c478bd9Sstevel@tonic-gate }
514e1dd0a2fSth160488 #endif
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate /*
517e1dd0a2fSth160488  * addConnection(): inserts a connection in the connection list.
518e1dd0a2fSth160488  * It will also sets use bit and the thread Id for the thread
519e1dd0a2fSth160488  * using the connection for the first time.
5207c478bd9Sstevel@tonic-gate  * Returns: -1 = failure, new Connection ID = success
5217c478bd9Sstevel@tonic-gate  */
5227c478bd9Sstevel@tonic-gate static int
addConnection(Connection * con)5237c478bd9Sstevel@tonic-gate addConnection(Connection *con)
5247c478bd9Sstevel@tonic-gate {
525e1dd0a2fSth160488 	int i;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	if (!con)
5287c478bd9Sstevel@tonic-gate 		return (-1);
529e1dd0a2fSth160488 #ifdef DEBUG
530e1dd0a2fSth160488 	(void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID);
531e1dd0a2fSth160488 #endif /* DEBUG */
532e1dd0a2fSth160488 	(void) mutex_lock(&sessionPoolLock);
5337c478bd9Sstevel@tonic-gate 	if (sessionPool == NULL) {
5347c478bd9Sstevel@tonic-gate 		sessionPoolSize = SESSION_CACHE_INC;
5357c478bd9Sstevel@tonic-gate 		sessionPool = calloc(sessionPoolSize,
536e1dd0a2fSth160488 		    sizeof (Connection *));
5377c478bd9Sstevel@tonic-gate 		if (!sessionPool) {
538e1dd0a2fSth160488 			(void) mutex_unlock(&sessionPoolLock);
5397c478bd9Sstevel@tonic-gate 			return (-1);
5407c478bd9Sstevel@tonic-gate 		}
541e1dd0a2fSth160488 #ifdef DEBUG
542e1dd0a2fSth160488 		(void) fprintf(stderr, "Initialized sessionPool\n");
543e1dd0a2fSth160488 #endif /* DEBUG */
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 	for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i)
5467c478bd9Sstevel@tonic-gate 		;
5477c478bd9Sstevel@tonic-gate 	if (i == sessionPoolSize) {
5487c478bd9Sstevel@tonic-gate 		/* run out of array, need to increase sessionPool */
5497c478bd9Sstevel@tonic-gate 		Connection **cl;
5507c478bd9Sstevel@tonic-gate 		cl = (Connection **) realloc(sessionPool,
5517c478bd9Sstevel@tonic-gate 		    (sessionPoolSize + SESSION_CACHE_INC) *
5527c478bd9Sstevel@tonic-gate 		    sizeof (Connection *));
5537c478bd9Sstevel@tonic-gate 		if (!cl) {
554e1dd0a2fSth160488 			(void) mutex_unlock(&sessionPoolLock);
5557c478bd9Sstevel@tonic-gate 			return (-1);
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 		(void) memset(cl + sessionPoolSize, 0,
558e1dd0a2fSth160488 		    SESSION_CACHE_INC * sizeof (Connection *));
5597c478bd9Sstevel@tonic-gate 		sessionPool = cl;
5607c478bd9Sstevel@tonic-gate 		sessionPoolSize += SESSION_CACHE_INC;
561e1dd0a2fSth160488 #ifdef DEBUG
562e1dd0a2fSth160488 		(void) fprintf(stderr, "Increased sessionPoolSize to: %d\n",
563e1dd0a2fSth160488 		    sessionPoolSize);
564e1dd0a2fSth160488 #endif /* DEBUG */
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 	sessionPool[i] = con;
5677c478bd9Sstevel@tonic-gate 	con->usedBit = B_TRUE;
568e1dd0a2fSth160488 	(void) mutex_unlock(&sessionPoolLock);
5697c478bd9Sstevel@tonic-gate 	con->connectionId = i + CONID_OFFSET;
570e1dd0a2fSth160488 #ifdef DEBUG
571e1dd0a2fSth160488 	(void) fprintf(stderr, "Connection added [%d]\n", i);
572e1dd0a2fSth160488 	printConnection(stderr, con);
573e1dd0a2fSth160488 #endif /* DEBUG */
5747c478bd9Sstevel@tonic-gate 	return (i + CONID_OFFSET);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate  * findConnection(): find an available connection from the list
5797c478bd9Sstevel@tonic-gate  * that matches the criteria specified in Connection structure.
5807c478bd9Sstevel@tonic-gate  * If serverAddr is NULL, then find a connection to any server
5817c478bd9Sstevel@tonic-gate  * as long as it matches the rest of the parameters.
5827c478bd9Sstevel@tonic-gate  * Returns: -1 = failure, the Connection ID found = success.
5837c478bd9Sstevel@tonic-gate  */
5847c478bd9Sstevel@tonic-gate static int
findConnection(int flags,const char * serverAddr,const ns_cred_t * auth,Connection ** conp)585cb5caa98Sdjl findConnection(int flags, const char *serverAddr,
586cb5caa98Sdjl 	const ns_cred_t *auth, Connection **conp)
5877c478bd9Sstevel@tonic-gate {
5887c478bd9Sstevel@tonic-gate 	Connection *cp;
589e1dd0a2fSth160488 	int i;
590cb5caa98Sdjl #ifdef DEBUG
591e1dd0a2fSth160488 	thread_t t;
592cb5caa98Sdjl #endif /* DEBUG */
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	if (auth == NULL || conp == NULL)
5957c478bd9Sstevel@tonic-gate 		return (-1);
5967c478bd9Sstevel@tonic-gate 	*conp = NULL;
5977c478bd9Sstevel@tonic-gate 
59829680e55Smj162486 	/*
59929680e55Smj162486 	 * If a new connection is requested, no need to continue.
600e1dd0a2fSth160488 	 * If the process is not nscd and is not requesting keep
601e1dd0a2fSth160488 	 * connections alive, no need to continue.
60229680e55Smj162486 	 */
60329680e55Smj162486 	if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() &&
604253f5c5dSmj162486 	    !__s_api_peruser_proc() && !(flags & NS_LDAP_KEEP_CONN)))
605cb5caa98Sdjl 		return (-1);
606cb5caa98Sdjl 
6077c478bd9Sstevel@tonic-gate #ifdef DEBUG
608e1dd0a2fSth160488 	t = thr_self();
609cb5caa98Sdjl 	(void) fprintf(stderr, "tid= %d: Find connection\n", t);
610cb5caa98Sdjl 	(void) fprintf(stderr, "tid= %d: Looking for ....\n", t);
6117c478bd9Sstevel@tonic-gate 	if (serverAddr && *serverAddr)
612cb5caa98Sdjl 		(void) fprintf(stderr, "tid= %d: serverAddr=%s\n",
613cb5caa98Sdjl 		    t, serverAddr);
6147c478bd9Sstevel@tonic-gate 	else
615cb5caa98Sdjl 		(void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t);
616e1dd0a2fSth160488 	printCred(stderr, auth);
6177c478bd9Sstevel@tonic-gate 	fflush(stderr);
6187c478bd9Sstevel@tonic-gate #endif /* DEBUG */
619e1dd0a2fSth160488 	if (sessionPool == NULL)
6207c478bd9Sstevel@tonic-gate 		return (-1);
621e1dd0a2fSth160488 	(void) mutex_lock(&sessionPoolLock);
6227c478bd9Sstevel@tonic-gate 	for (i = 0; i < sessionPoolSize; ++i) {
6237c478bd9Sstevel@tonic-gate 		if (sessionPool[i] == NULL)
6247c478bd9Sstevel@tonic-gate 			continue;
6257c478bd9Sstevel@tonic-gate 		cp = sessionPool[i];
6267c478bd9Sstevel@tonic-gate #ifdef DEBUG
627e1dd0a2fSth160488 		(void) fprintf(stderr,
628e1dd0a2fSth160488 		    "tid: %d: checking connection [%d] ....\n", t, i);
629e1dd0a2fSth160488 		printConnection(stderr, cp);
6307c478bd9Sstevel@tonic-gate #endif /* DEBUG */
631e1dd0a2fSth160488 		if ((cp->usedBit) || (serverAddr && *serverAddr &&
6327c478bd9Sstevel@tonic-gate 		    (strcasecmp(serverAddr, cp->serverAddr) != 0)))
6337c478bd9Sstevel@tonic-gate 			continue;
634e1dd0a2fSth160488 
635e1dd0a2fSth160488 		if (__s_api_is_auth_matched(cp->auth, auth) == B_FALSE)
6367c478bd9Sstevel@tonic-gate 			continue;
637a1e48794Schinlong 
6387c478bd9Sstevel@tonic-gate 		/* found an available connection */
6397c478bd9Sstevel@tonic-gate 		cp->usedBit = B_TRUE;
640e1dd0a2fSth160488 		(void) mutex_unlock(&sessionPoolLock);
6417c478bd9Sstevel@tonic-gate 		cp->threadID = thr_self();
6427c478bd9Sstevel@tonic-gate 		*conp = cp;
6437c478bd9Sstevel@tonic-gate #ifdef DEBUG
644e1dd0a2fSth160488 		(void) fprintf(stderr,
645e1dd0a2fSth160488 		    "tid %d: Connection found cID=%d\n", t, i);
6467c478bd9Sstevel@tonic-gate 		fflush(stderr);
6477c478bd9Sstevel@tonic-gate #endif /* DEBUG */
6487c478bd9Sstevel@tonic-gate 		return (i + CONID_OFFSET);
6497c478bd9Sstevel@tonic-gate 	}
650e1dd0a2fSth160488 	(void) mutex_unlock(&sessionPoolLock);
6517c478bd9Sstevel@tonic-gate 	return (-1);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate /*
6557c478bd9Sstevel@tonic-gate  * Free a Connection structure
6567c478bd9Sstevel@tonic-gate  */
657e1dd0a2fSth160488 void
__s_api_freeConnection(Connection * con)658e1dd0a2fSth160488 __s_api_freeConnection(Connection *con)
6597c478bd9Sstevel@tonic-gate {
6607c478bd9Sstevel@tonic-gate 	if (con == NULL)
6617c478bd9Sstevel@tonic-gate 		return;
6627c478bd9Sstevel@tonic-gate 	if (con->serverAddr)
6637c478bd9Sstevel@tonic-gate 		free(con->serverAddr);
6647c478bd9Sstevel@tonic-gate 	if (con->auth)
6657c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeCred(&(con->auth));
6667c478bd9Sstevel@tonic-gate 	if (con->saslMechanisms) {
6677c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(con->saslMechanisms);
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 	if (con->controls) {
6707c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(con->controls);
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 	free(con);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate /*
6767c478bd9Sstevel@tonic-gate  * Find a connection matching the passed in criteria.  If an open
6777c478bd9Sstevel@tonic-gate  * connection with that criteria exists use it, otherwise open a
6787c478bd9Sstevel@tonic-gate  * new connection.
6797c478bd9Sstevel@tonic-gate  * Success: returns the pointer to the Connection structure
6807c478bd9Sstevel@tonic-gate  * Failure: returns NULL, error code and message should be in errorp
6817c478bd9Sstevel@tonic-gate  */
682689c2bf4Sjanga 
6837c478bd9Sstevel@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)6847c478bd9Sstevel@tonic-gate makeConnection(Connection **conp, const char *serverAddr,
6857c478bd9Sstevel@tonic-gate 	const ns_cred_t *auth, ConnectionID *cID, int timeoutSec,
68647789246Svv149972 	ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd,
687e1dd0a2fSth160488 	int nopasswd_acct_mgmt, int flags, char ***badsrvrs,
688e1dd0a2fSth160488 	ns_conn_user_t *conn_user)
6897c478bd9Sstevel@tonic-gate {
6907c478bd9Sstevel@tonic-gate 	Connection *con = NULL;
6917c478bd9Sstevel@tonic-gate 	ConnectionID id;
6927c478bd9Sstevel@tonic-gate 	char errmsg[MAXERROR];
6937c478bd9Sstevel@tonic-gate 	int rc, exit_rc = NS_LDAP_SUCCESS;
6947c478bd9Sstevel@tonic-gate 	ns_server_info_t sinfo;
6957c478bd9Sstevel@tonic-gate 	char *hReq, *host = NULL;
6967c478bd9Sstevel@tonic-gate 	LDAP *ld = NULL;
6977c478bd9Sstevel@tonic-gate 	int passwd_mgmt = 0;
698689c2bf4Sjanga 	int totalbad = 0; /* Number of servers contacted unsuccessfully */
699cb5caa98Sdjl 	short	memerr = 0; /* Variable for tracking memory allocation */
7004a6b6ac4Schinlong 	char *serverAddrType = NULL, **bindHost = NULL;
701cb5caa98Sdjl 
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if (conp == NULL || errorp == NULL || auth == NULL)
7047c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
705*b3b48d8eSHans Rosenfeld 	if (*errorp)
706*b3b48d8eSHans Rosenfeld 		(void) __ns_ldap_freeError(errorp);
7077c478bd9Sstevel@tonic-gate 	*conp = NULL;
7084a6b6ac4Schinlong 	(void) memset(&sinfo, 0, sizeof (sinfo));
7097c478bd9Sstevel@tonic-gate 
710e1dd0a2fSth160488 	if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) {
7117c478bd9Sstevel@tonic-gate 		/* connection found in cache */
7127c478bd9Sstevel@tonic-gate #ifdef DEBUG
713cb5caa98Sdjl 		(void) fprintf(stderr, "tid= %d: connection found in "
714cb5caa98Sdjl 		    "cache %d\n", thr_self(), id);
7157c478bd9Sstevel@tonic-gate 		fflush(stderr);
7167c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7177c478bd9Sstevel@tonic-gate 		*cID = id;
7187c478bd9Sstevel@tonic-gate 		*conp = con;
7197c478bd9Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
7224a6b6ac4Schinlong 	if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
723cb5caa98Sdjl 		serverAddrType = NS_CACHE_ADDR_HOSTNAME;
7244a6b6ac4Schinlong 		bindHost = &sinfo.serverFQDN;
7254a6b6ac4Schinlong 	} else {
726cb5caa98Sdjl 		serverAddrType = NS_CACHE_ADDR_IP;
7274a6b6ac4Schinlong 		bindHost = &sinfo.server;
7284a6b6ac4Schinlong 	}
729cb5caa98Sdjl 
7307c478bd9Sstevel@tonic-gate 	if (serverAddr) {
731e1dd0a2fSth160488 		if (__s_api_isInitializing()) {
732e1dd0a2fSth160488 			/*
733e1dd0a2fSth160488 			 * When obtaining the root DSE, connect to the server
734e1dd0a2fSth160488 			 * passed here through the serverAddr parameter
735e1dd0a2fSth160488 			 */
736e1dd0a2fSth160488 			sinfo.server = strdup(serverAddr);
737e1dd0a2fSth160488 			if (sinfo.server == NULL)
738e1dd0a2fSth160488 				return (NS_LDAP_MEMORY);
739e1dd0a2fSth160488 			if (strcmp(serverAddrType,
740e1dd0a2fSth160488 			    NS_CACHE_ADDR_HOSTNAME) == 0) {
741e1dd0a2fSth160488 				rc = __s_api_ip2hostname(sinfo.server,
742e1dd0a2fSth160488 				    &sinfo.serverFQDN);
743e1dd0a2fSth160488 				if (rc != NS_LDAP_SUCCESS) {
744e1dd0a2fSth160488 					(void) snprintf(errmsg,
745e1dd0a2fSth160488 					    sizeof (errmsg),
746e1dd0a2fSth160488 					    gettext("The %s address "
747e1dd0a2fSth160488 					    "can not be resolved into "
748e1dd0a2fSth160488 					    "a host name. Returning "
749e1dd0a2fSth160488 					    "the address as it is."),
750e1dd0a2fSth160488 					    serverAddr);
751e1dd0a2fSth160488 					MKERROR(LOG_ERR,
752e1dd0a2fSth160488 					    *errorp,
753e1dd0a2fSth160488 					    NS_CONFIG_NOTLOADED,
754e1dd0a2fSth160488 					    strdup(errmsg),
755e1dd0a2fSth160488 					    NS_LDAP_MEMORY);
756e1dd0a2fSth160488 					__s_api_free_server_info(&sinfo);
757e1dd0a2fSth160488 					return (NS_LDAP_INTERNAL);
758e1dd0a2fSth160488 				}
759e1dd0a2fSth160488 			}
760e1dd0a2fSth160488 		} else {
76153b52417Ssdussud 			/*
76253b52417Ssdussud 			 * We're given the server address, just use it.
763e1dd0a2fSth160488 			 * In case of sasl/GSSAPI, serverAddr would need
764e1dd0a2fSth160488 			 * to be a FQDN.  We assume this is the case for now.
76553b52417Ssdussud 			 *
766e1dd0a2fSth160488 			 * Only the server address fields of sinfo structure
767e1dd0a2fSth160488 			 * are filled in since these are the only relevant
768e1dd0a2fSth160488 			 * data that we have. Other fields of this structure
769e1dd0a2fSth160488 			 * (controls, saslMechanisms) are kept to NULL.
77053b52417Ssdussud 			 */
77153b52417Ssdussud 			sinfo.server = strdup(serverAddr);
77253b52417Ssdussud 			if (sinfo.server == NULL)  {
77353b52417Ssdussud 				return (NS_LDAP_MEMORY);
77453b52417Ssdussud 			}
77553b52417Ssdussud 			if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
77653b52417Ssdussud 				sinfo.serverFQDN = strdup(serverAddr);
77753b52417Ssdussud 				if (sinfo.serverFQDN == NULL) {
77853b52417Ssdussud 					free(sinfo.server);
77953b52417Ssdussud 					return (NS_LDAP_MEMORY);
78053b52417Ssdussud 				}
7817c478bd9Sstevel@tonic-gate 			}
782e1dd0a2fSth160488 		}
7834a6b6ac4Schinlong 		rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp,
7846ad9980eSJulian Pullen 		    fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags);
785cb5caa98Sdjl 		if (rc == NS_LDAP_SUCCESS || rc ==
786cb5caa98Sdjl 		    NS_LDAP_SUCCESS_WITH_INFO) {
787cb5caa98Sdjl 			exit_rc = rc;
7887c478bd9Sstevel@tonic-gate 			goto create_con;
7897c478bd9Sstevel@tonic-gate 		} else {
79053b52417Ssdussud 			if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
79153b52417Ssdussud 				(void) snprintf(errmsg, sizeof (errmsg),
79253b52417Ssdussud 				    "%s %s", gettext("makeConnection: "
79353b52417Ssdussud 				    "failed to open connection using "
79453b52417Ssdussud 				    "sasl/GSSAPI to"), *bindHost);
79553b52417Ssdussud 			} else {
79653b52417Ssdussud 				(void) snprintf(errmsg, sizeof (errmsg),
79753b52417Ssdussud 				    "%s %s", gettext("makeConnection: "
79853b52417Ssdussud 				    "failed to open connection to"),
79953b52417Ssdussud 				    *bindHost);
80053b52417Ssdussud 			}
80153b52417Ssdussud 			syslog(LOG_ERR, "libsldap: %s", errmsg);
80253b52417Ssdussud 			__s_api_free_server_info(&sinfo);
8037c478bd9Sstevel@tonic-gate 			return (rc);
8047c478bd9Sstevel@tonic-gate 		}
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	/* No cached connection, create one */
8087c478bd9Sstevel@tonic-gate 	for (; ; ) {
8097c478bd9Sstevel@tonic-gate 		if (host == NULL)
8107c478bd9Sstevel@tonic-gate 			hReq = NS_CACHE_NEW;
8117c478bd9Sstevel@tonic-gate 		else
8127c478bd9Sstevel@tonic-gate 			hReq = NS_CACHE_NEXT;
813cb5caa98Sdjl 		rc = __s_api_requestServer(hReq, host, &sinfo, errorp,
814cb5caa98Sdjl 		    serverAddrType);
8157c478bd9Sstevel@tonic-gate 		if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) ||
8167c478bd9Sstevel@tonic-gate 		    (host && (strcasecmp(host, sinfo.server) == 0))) {
8177c478bd9Sstevel@tonic-gate 			/* Log the error */
8187c478bd9Sstevel@tonic-gate 			if (*errorp) {
8197c478bd9Sstevel@tonic-gate 				(void) snprintf(errmsg, sizeof (errmsg),
8207c478bd9Sstevel@tonic-gate 				"%s: (%s)", gettext("makeConnection: "
8217c478bd9Sstevel@tonic-gate 				"unable to make LDAP connection, "
8227c478bd9Sstevel@tonic-gate 				"request for a server failed"),
8237c478bd9Sstevel@tonic-gate 				    (*errorp)->message);
8247c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "libsldap: %s", errmsg);
8257c478bd9Sstevel@tonic-gate 			}
8267c478bd9Sstevel@tonic-gate 
8274a6b6ac4Schinlong 			__s_api_free_server_info(&sinfo);
8287c478bd9Sstevel@tonic-gate 			if (host)
8297c478bd9Sstevel@tonic-gate 				free(host);
8307c478bd9Sstevel@tonic-gate 			return (NS_LDAP_OP_FAILED);
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 		if (host)
8337c478bd9Sstevel@tonic-gate 			free(host);
8347c478bd9Sstevel@tonic-gate 		host = strdup(sinfo.server);
8357c478bd9Sstevel@tonic-gate 		if (host == NULL) {
8364a6b6ac4Schinlong 			__s_api_free_server_info(&sinfo);
8377c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
8387c478bd9Sstevel@tonic-gate 		}
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 		/* check if server supports password management */
8417c478bd9Sstevel@tonic-gate 		passwd_mgmt = __s_api_contain_passwd_control_oid(
8427c478bd9Sstevel@tonic-gate 		    sinfo.controls);
84347789246Svv149972 		/* check if server supports password less account mgmt */
84447789246Svv149972 		if (nopasswd_acct_mgmt &&
84547789246Svv149972 		    !__s_api_contain_account_usable_control_oid(
84647789246Svv149972 		    sinfo.controls)) {
84747789246Svv149972 			syslog(LOG_WARNING, "libsldap: server %s does not "
84847789246Svv149972 			    "provide account information without password",
84947789246Svv149972 			    host);
85047789246Svv149972 			free(host);
8514a6b6ac4Schinlong 			__s_api_free_server_info(&sinfo);
85247789246Svv149972 			return (NS_LDAP_OP_FAILED);
85347789246Svv149972 		}
8547c478bd9Sstevel@tonic-gate 		/* make the connection */
8554a6b6ac4Schinlong 		rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp,
8566ad9980eSJulian Pullen 		    fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags);
8577c478bd9Sstevel@tonic-gate 		/* if success, go to create connection structure */
8587c478bd9Sstevel@tonic-gate 		if (rc == NS_LDAP_SUCCESS ||
8597c478bd9Sstevel@tonic-gate 		    rc == NS_LDAP_SUCCESS_WITH_INFO) {
8607c478bd9Sstevel@tonic-gate 			exit_rc = rc;
8617c478bd9Sstevel@tonic-gate 			break;
8627c478bd9Sstevel@tonic-gate 		}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 		/*
8657c478bd9Sstevel@tonic-gate 		 * If not able to reach the server, inform the ldap
8667c478bd9Sstevel@tonic-gate 		 * cache manager that the server should be removed
8677c478bd9Sstevel@tonic-gate 		 * from its server list. Thus, the manager will not
8687c478bd9Sstevel@tonic-gate 		 * return this server on the next get-server request
8697c478bd9Sstevel@tonic-gate 		 * and will also reduce the server list refresh TTL,
8707c478bd9Sstevel@tonic-gate 		 * so that it will find out sooner when the server
8717c478bd9Sstevel@tonic-gate 		 * is up again.
8727c478bd9Sstevel@tonic-gate 		 */
8737c478bd9Sstevel@tonic-gate 		if (rc == NS_LDAP_INTERNAL && *errorp != NULL) {
8747c478bd9Sstevel@tonic-gate 			if ((*errorp)->status == LDAP_CONNECT_ERROR ||
875e8ac3ceaSsdussud 			    (*errorp)->status == LDAP_SERVER_DOWN) {
876689c2bf4Sjanga 				/* Reset memory allocation error */
877689c2bf4Sjanga 				memerr = 0;
878e8ac3ceaSsdussud 				/*
879689c2bf4Sjanga 				 * We contacted a server that we could
880689c2bf4Sjanga 				 * not either authenticate to or contact.
881689c2bf4Sjanga 				 * If it is due to authentication, then
882689c2bf4Sjanga 				 * we need to try the server again. So,
883689c2bf4Sjanga 				 * do not remove the server yet, but
884689c2bf4Sjanga 				 * add it to the bad server list.
885689c2bf4Sjanga 				 * The caller routine will remove
886689c2bf4Sjanga 				 * the servers if:
887689c2bf4Sjanga 				 *	a). A good server is found or
888689c2bf4Sjanga 				 *	b). All the possible methods
889689c2bf4Sjanga 				 *	    are tried without finding
890689c2bf4Sjanga 				 *	    a good server
891e8ac3ceaSsdussud 				 */
892689c2bf4Sjanga 				if (*badsrvrs == NULL) {
893689c2bf4Sjanga 					if (!(*badsrvrs = (char **)malloc
894689c2bf4Sjanga 					    (sizeof (char *) * NUMTOMALLOC))) {
895689c2bf4Sjanga 						memerr = 1;
896e8ac3ceaSsdussud 					}
897689c2bf4Sjanga 				/* Allocate memory in chunks of NUMTOMALLOC */
898689c2bf4Sjanga 				} else if ((totalbad % NUMTOMALLOC) ==
899689c2bf4Sjanga 				    NUMTOMALLOC - 1) {
900689c2bf4Sjanga 					char **tmpptr;
9014a6b6ac4Schinlong 					if (!(tmpptr = (char **)realloc(
9024a6b6ac4Schinlong 					    *badsrvrs,
903689c2bf4Sjanga 					    (sizeof (char *) * NUMTOMALLOC *
904689c2bf4Sjanga 					    ((totalbad/NUMTOMALLOC) + 2))))) {
905689c2bf4Sjanga 						memerr = 1;
906689c2bf4Sjanga 					} else {
907689c2bf4Sjanga 						*badsrvrs = tmpptr;
908689c2bf4Sjanga 					}
909689c2bf4Sjanga 				}
910689c2bf4Sjanga 				/*
911689c2bf4Sjanga 				 * Store host only if there were no unsuccessful
912689c2bf4Sjanga 				 * memory allocations above
913689c2bf4Sjanga 				 */
914689c2bf4Sjanga 				if (!memerr &&
915689c2bf4Sjanga 				    !((*badsrvrs)[totalbad++] = strdup(host))) {
916689c2bf4Sjanga 					memerr = 1;
917689c2bf4Sjanga 					totalbad--;
918689c2bf4Sjanga 				}
919689c2bf4Sjanga 				(*badsrvrs)[totalbad] = NULL;
920e8ac3ceaSsdussud 			}
9217c478bd9Sstevel@tonic-gate 		}
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 		/* else, cleanup and go for the next server */
9244a6b6ac4Schinlong 		__s_api_free_server_info(&sinfo);
9254a6b6ac4Schinlong 
926689c2bf4Sjanga 		/* Return if we had memory allocation errors */
927689c2bf4Sjanga 		if (memerr)
928689c2bf4Sjanga 			return (NS_LDAP_MEMORY);
9297c478bd9Sstevel@tonic-gate 		if (*errorp) {
9307c478bd9Sstevel@tonic-gate 			/*
9317c478bd9Sstevel@tonic-gate 			 * If openConnection() failed due to
9327c478bd9Sstevel@tonic-gate 			 * password policy, or invalid credential,
9337c478bd9Sstevel@tonic-gate 			 * keep *errorp and exit
9347c478bd9Sstevel@tonic-gate 			 */
9357c478bd9Sstevel@tonic-gate 			if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD ||
9367c478bd9Sstevel@tonic-gate 			    (*errorp)->status == LDAP_INVALID_CREDENTIALS) {
9377c478bd9Sstevel@tonic-gate 				free(host);
9387c478bd9Sstevel@tonic-gate 				return (rc);
9397c478bd9Sstevel@tonic-gate 			} else {
9407c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeError(errorp);
9417c478bd9Sstevel@tonic-gate 				*errorp = NULL;
9427c478bd9Sstevel@tonic-gate 			}
9437c478bd9Sstevel@tonic-gate 		}
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate create_con:
9477c478bd9Sstevel@tonic-gate 	/* we have created ld, setup con structure */
9487c478bd9Sstevel@tonic-gate 	if (host)
9497c478bd9Sstevel@tonic-gate 		free(host);
9507c478bd9Sstevel@tonic-gate 	if ((con = calloc(1, sizeof (Connection))) == NULL) {
9514a6b6ac4Schinlong 		__s_api_free_server_info(&sinfo);
9527c478bd9Sstevel@tonic-gate 		/*
9537c478bd9Sstevel@tonic-gate 		 * If password control attached in **errorp,
9547c478bd9Sstevel@tonic-gate 		 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
9557c478bd9Sstevel@tonic-gate 		 * free the error structure
9567c478bd9Sstevel@tonic-gate 		 */
9577c478bd9Sstevel@tonic-gate 		if (*errorp) {
9587c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeError(errorp);
9597c478bd9Sstevel@tonic-gate 			*errorp = NULL;
9607c478bd9Sstevel@tonic-gate 		}
96153b52417Ssdussud 		(void) ldap_unbind(ld);
9627c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 
9654a6b6ac4Schinlong 	con->serverAddr = sinfo.server; /* Store original format */
9664a6b6ac4Schinlong 	if (sinfo.serverFQDN != NULL) {
9674a6b6ac4Schinlong 		free(sinfo.serverFQDN);
9684a6b6ac4Schinlong 		sinfo.serverFQDN = NULL;
9694a6b6ac4Schinlong 	}
9707c478bd9Sstevel@tonic-gate 	con->saslMechanisms = sinfo.saslMechanisms;
9717c478bd9Sstevel@tonic-gate 	con->controls = sinfo.controls;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	con->auth = __ns_ldap_dupAuth(auth);
9747c478bd9Sstevel@tonic-gate 	if (con->auth == NULL) {
97553b52417Ssdussud 		(void) ldap_unbind(ld);
976e1dd0a2fSth160488 		__s_api_freeConnection(con);
9777c478bd9Sstevel@tonic-gate 		/*
9787c478bd9Sstevel@tonic-gate 		 * If password control attached in **errorp,
9797c478bd9Sstevel@tonic-gate 		 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
9807c478bd9Sstevel@tonic-gate 		 * free the error structure
9817c478bd9Sstevel@tonic-gate 		 */
9827c478bd9Sstevel@tonic-gate 		if (*errorp) {
9837c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeError(errorp);
9847c478bd9Sstevel@tonic-gate 			*errorp = NULL;
9857c478bd9Sstevel@tonic-gate 		}
9867c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	con->threadID = thr_self();
9908277a58bSchinlong 	con->pid = getpid();
991cb5caa98Sdjl 
9927c478bd9Sstevel@tonic-gate 	con->ld = ld;
993e1dd0a2fSth160488 	/* add MT connection to the MT connection pool */
994e1dd0a2fSth160488 	if (conn_user != NULL && conn_user->conn_mt != NULL) {
995e1dd0a2fSth160488 		if (__s_api_conn_mt_add(con, conn_user, errorp) ==
996e1dd0a2fSth160488 		    NS_LDAP_SUCCESS) {
997e1dd0a2fSth160488 			*conp = con;
998e1dd0a2fSth160488 			return (exit_rc);
999e1dd0a2fSth160488 		} else {
1000e1dd0a2fSth160488 			(void) ldap_unbind(ld);
1001e1dd0a2fSth160488 			__s_api_freeConnection(con);
1002e1dd0a2fSth160488 			return ((*errorp)->status);
1003e1dd0a2fSth160488 		}
1004e1dd0a2fSth160488 	}
1005e1dd0a2fSth160488 
1006e1dd0a2fSth160488 	/* MT connection not supported or not required case */
10077c478bd9Sstevel@tonic-gate 	if ((id = addConnection(con)) == -1) {
100853b52417Ssdussud 		(void) ldap_unbind(ld);
1009e1dd0a2fSth160488 		__s_api_freeConnection(con);
10107c478bd9Sstevel@tonic-gate 		/*
10117c478bd9Sstevel@tonic-gate 		 * If password control attached in **errorp,
10127c478bd9Sstevel@tonic-gate 		 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
10137c478bd9Sstevel@tonic-gate 		 * free the error structure
10147c478bd9Sstevel@tonic-gate 		 */
10157c478bd9Sstevel@tonic-gate 		if (*errorp) {
10167c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeError(errorp);
10177c478bd9Sstevel@tonic-gate 			*errorp = NULL;
10187c478bd9Sstevel@tonic-gate 		}
10197c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
10207c478bd9Sstevel@tonic-gate 	}
10217c478bd9Sstevel@tonic-gate #ifdef DEBUG
1022cb5caa98Sdjl 	(void) fprintf(stderr, "tid= %d: connection added into "
1023cb5caa98Sdjl 	    "cache %d\n", thr_self(), id);
10247c478bd9Sstevel@tonic-gate 	fflush(stderr);
10257c478bd9Sstevel@tonic-gate #endif /* DEBUG */
10267c478bd9Sstevel@tonic-gate 	*cID = id;
10277c478bd9Sstevel@tonic-gate 	*conp = con;
10287c478bd9Sstevel@tonic-gate 	return (exit_rc);
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate /*
10327c478bd9Sstevel@tonic-gate  * Return the specified connection to the pool.  If necessary
10337c478bd9Sstevel@tonic-gate  * delete the connection.
10347c478bd9Sstevel@tonic-gate  */
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate static void
_DropConnection(ConnectionID cID,int flag,int fini)10377c478bd9Sstevel@tonic-gate _DropConnection(ConnectionID cID, int flag, int fini)
10387c478bd9Sstevel@tonic-gate {
10397c478bd9Sstevel@tonic-gate 	Connection *cp;
10407c478bd9Sstevel@tonic-gate 	int id;
1041e1dd0a2fSth160488 	int use_mutex = !fini;
1042b5d0e4ebSmj162486 	struct timeval	zerotime;
1043b5d0e4ebSmj162486 	LDAPMessage	*res;
1044b5d0e4ebSmj162486 
1045b5d0e4ebSmj162486 	zerotime.tv_sec = zerotime.tv_usec = 0L;
1046b5d0e4ebSmj162486 
10477c478bd9Sstevel@tonic-gate 	id = cID - CONID_OFFSET;
10487c478bd9Sstevel@tonic-gate 	if (id < 0 || id >= sessionPoolSize)
10497c478bd9Sstevel@tonic-gate 		return;
10507c478bd9Sstevel@tonic-gate #ifdef DEBUG
1051e1dd0a2fSth160488 	(void) fprintf(stderr,
1052e1dd0a2fSth160488 	    "tid %d: Dropping connection cID=%d flag=0x%x\n",
1053e1dd0a2fSth160488 	    thr_self(), cID, flag);
10547c478bd9Sstevel@tonic-gate 	fflush(stderr);
10557c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1056e1dd0a2fSth160488 	if (use_mutex)
1057e1dd0a2fSth160488 		(void) mutex_lock(&sessionPoolLock);
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	cp = sessionPool[id];
10607c478bd9Sstevel@tonic-gate 	/* sanity check before removing */
1061e1dd0a2fSth160488 	if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) {
1062e1dd0a2fSth160488 		if (use_mutex)
1063e1dd0a2fSth160488 			(void) mutex_unlock(&sessionPoolLock);
10647c478bd9Sstevel@tonic-gate 		return;
10657c478bd9Sstevel@tonic-gate 	}
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	if (!fini &&
1068e1dd0a2fSth160488 	    ((flag & NS_LDAP_NEW_CONN) == 0) &&
1069253f5c5dSmj162486 	    ((flag & NS_LDAP_KEEP_CONN) || __s_api_nscd_proc() ||
1070253f5c5dSmj162486 	    __s_api_peruser_proc())) {
10717c478bd9Sstevel@tonic-gate 		/* release Connection (keep alive) */
10727c478bd9Sstevel@tonic-gate 		cp->usedBit = B_FALSE;
10737c478bd9Sstevel@tonic-gate 		cp->threadID = 0;	/* unmark the threadID */
1074b5d0e4ebSmj162486 		/*
1075e1dd0a2fSth160488 		 * Do sanity cleanup of remaining results.
1076b5d0e4ebSmj162486 		 */
1077b5d0e4ebSmj162486 		while (ldap_result(cp->ld, LDAP_RES_ANY, LDAP_MSG_ALL,
1078b5d0e4ebSmj162486 		    &zerotime, &res) > 0) {
1079b5d0e4ebSmj162486 			if (res != NULL)
1080b5d0e4ebSmj162486 				(void) ldap_msgfree(res);
1081b5d0e4ebSmj162486 		}
1082e1dd0a2fSth160488 		if (use_mutex)
1083e1dd0a2fSth160488 			(void) mutex_unlock(&sessionPoolLock);
10847c478bd9Sstevel@tonic-gate 	} else {
10857c478bd9Sstevel@tonic-gate 		/* delete Connection (disconnect) */
10867c478bd9Sstevel@tonic-gate 		sessionPool[id] = NULL;
1087e1dd0a2fSth160488 		if (use_mutex)
1088e1dd0a2fSth160488 			(void) mutex_unlock(&sessionPoolLock);
10897c478bd9Sstevel@tonic-gate 		(void) ldap_unbind(cp->ld);
1090e1dd0a2fSth160488 		__s_api_freeConnection(cp);
1091cb5caa98Sdjl 	}
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate void
DropConnection(ConnectionID cID,int flag)10957c478bd9Sstevel@tonic-gate DropConnection(ConnectionID cID, int flag)
10967c478bd9Sstevel@tonic-gate {
10977c478bd9Sstevel@tonic-gate 	_DropConnection(cID, flag, 0);
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate /*
11017c478bd9Sstevel@tonic-gate  * This routine is called after a bind operation is
11027c478bd9Sstevel@tonic-gate  * done in openConnection() to process the password
11037c478bd9Sstevel@tonic-gate  * management information, if any.
11047c478bd9Sstevel@tonic-gate  *
11057c478bd9Sstevel@tonic-gate  * Input:
11067c478bd9Sstevel@tonic-gate  *   bind_type: "simple" or "sasl/DIGEST-MD5"
11077c478bd9Sstevel@tonic-gate  *   ldaprc   : ldap rc from the ldap bind operation
11087c478bd9Sstevel@tonic-gate  *   controls : controls returned by the server
11097c478bd9Sstevel@tonic-gate  *   errmsg   : error message from the server
11107c478bd9Sstevel@tonic-gate  *   fail_if_new_pwd_reqd:
11117c478bd9Sstevel@tonic-gate  *              flag indicating if connection should be open
11127c478bd9Sstevel@tonic-gate  *              when password needs to change immediately
11137c478bd9Sstevel@tonic-gate  *   passwd_mgmt:
11147c478bd9Sstevel@tonic-gate  *              flag indicating if server supports password
11157c478bd9Sstevel@tonic-gate  *              policy/management
11167c478bd9Sstevel@tonic-gate  *
11177c478bd9Sstevel@tonic-gate  * Output     : ns_ldap_error structure, which may contain
11187c478bd9Sstevel@tonic-gate  *              password status and number of seconds until
11197c478bd9Sstevel@tonic-gate  *              expired
11207c478bd9Sstevel@tonic-gate  *
11217c478bd9Sstevel@tonic-gate  * return rc:
11227c478bd9Sstevel@tonic-gate  * NS_LDAP_EXTERNAL: error, connection should not open
11237c478bd9Sstevel@tonic-gate  * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached
11247c478bd9Sstevel@tonic-gate  * NS_LDAP_SUCCESS: OK to open connection
11257c478bd9Sstevel@tonic-gate  *
11267c478bd9Sstevel@tonic-gate  */
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@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)11297c478bd9Sstevel@tonic-gate process_pwd_mgmt(char *bind_type, int ldaprc,
11307c478bd9Sstevel@tonic-gate 		LDAPControl **controls,
11317c478bd9Sstevel@tonic-gate 		char *errmsg, ns_ldap_error_t **errorp,
11327c478bd9Sstevel@tonic-gate 		int fail_if_new_pwd_reqd,
11337c478bd9Sstevel@tonic-gate 		int passwd_mgmt)
11347c478bd9Sstevel@tonic-gate {
11357c478bd9Sstevel@tonic-gate 	char		errstr[MAXERROR];
11367c478bd9Sstevel@tonic-gate 	LDAPControl	**ctrl = NULL;
11377c478bd9Sstevel@tonic-gate 	int		exit_rc;
11387c478bd9Sstevel@tonic-gate 	ns_ldap_passwd_status_t	pwd_status = NS_PASSWD_GOOD;
11397c478bd9Sstevel@tonic-gate 	int		sec_until_exp = 0;
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 	/*
11427c478bd9Sstevel@tonic-gate 	 * errmsg may be an empty string,
11437c478bd9Sstevel@tonic-gate 	 * even if ldaprc is LDAP_SUCCESS,
11447c478bd9Sstevel@tonic-gate 	 * free the empty string if that's the case
11457c478bd9Sstevel@tonic-gate 	 */
11467c478bd9Sstevel@tonic-gate 	if (errmsg &&
11477c478bd9Sstevel@tonic-gate 	    (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) {
11487c478bd9Sstevel@tonic-gate 		ldap_memfree(errmsg);
11497c478bd9Sstevel@tonic-gate 		errmsg = NULL;
11507c478bd9Sstevel@tonic-gate 	}
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	if (ldaprc != LDAP_SUCCESS) {
11537c478bd9Sstevel@tonic-gate 		/*
11547c478bd9Sstevel@tonic-gate 		 * try to map ldap rc and error message to
11557c478bd9Sstevel@tonic-gate 		 * a password status
11567c478bd9Sstevel@tonic-gate 		 */
11577c478bd9Sstevel@tonic-gate 		if (errmsg) {
11587c478bd9Sstevel@tonic-gate 			if (passwd_mgmt)
11597c478bd9Sstevel@tonic-gate 				pwd_status =
11607c478bd9Sstevel@tonic-gate 				    __s_api_set_passwd_status(
11617c478bd9Sstevel@tonic-gate 				    ldaprc, errmsg);
11627c478bd9Sstevel@tonic-gate 			ldap_memfree(errmsg);
11637c478bd9Sstevel@tonic-gate 		}
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 		(void) snprintf(errstr, sizeof (errstr),
11667c478bd9Sstevel@tonic-gate 		    gettext("openConnection: "
11677c478bd9Sstevel@tonic-gate 		    "%s bind failed "
11687c478bd9Sstevel@tonic-gate 		    "- %s"), bind_type, ldap_err2string(ldaprc));
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 		if (pwd_status != NS_PASSWD_GOOD) {
11717c478bd9Sstevel@tonic-gate 			MKERROR_PWD_MGMT(*errorp,
11727c478bd9Sstevel@tonic-gate 			    ldaprc, strdup(errstr),
11737c478bd9Sstevel@tonic-gate 			    pwd_status, 0, NULL);
11747c478bd9Sstevel@tonic-gate 		} else {
11757c478bd9Sstevel@tonic-gate 			MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr),
1176e1dd0a2fSth160488 			    NS_LDAP_MEMORY);
11777c478bd9Sstevel@tonic-gate 		}
11787c478bd9Sstevel@tonic-gate 		if (controls)
11797c478bd9Sstevel@tonic-gate 			ldap_controls_free(controls);
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INTERNAL);
11827c478bd9Sstevel@tonic-gate 	}
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	/*
11857c478bd9Sstevel@tonic-gate 	 * ldaprc is LDAP_SUCCESS,
11867c478bd9Sstevel@tonic-gate 	 * process the password management controls, if any
11877c478bd9Sstevel@tonic-gate 	 */
11887c478bd9Sstevel@tonic-gate 	exit_rc = NS_LDAP_SUCCESS;
11897c478bd9Sstevel@tonic-gate 	if (controls && passwd_mgmt) {
11907c478bd9Sstevel@tonic-gate 		/*
11917c478bd9Sstevel@tonic-gate 		 * The control with the OID
11927c478bd9Sstevel@tonic-gate 		 * 2.16.840.1.113730.3.4.4 (or
11937c478bd9Sstevel@tonic-gate 		 * LDAP_CONTROL_PWEXPIRED, as defined
11947c478bd9Sstevel@tonic-gate 		 * in the ldap.h header file) is the
11957c478bd9Sstevel@tonic-gate 		 * expired password control.
11967c478bd9Sstevel@tonic-gate 		 *
11977c478bd9Sstevel@tonic-gate 		 * This control is used if the server
11987c478bd9Sstevel@tonic-gate 		 * is configured to require users to
11997c478bd9Sstevel@tonic-gate 		 * change their passwords when first
12007c478bd9Sstevel@tonic-gate 		 * logging in and whenever the
12017c478bd9Sstevel@tonic-gate 		 * passwords are reset.
12027c478bd9Sstevel@tonic-gate 		 *
12037c478bd9Sstevel@tonic-gate 		 * If the user is logging in for the
12047c478bd9Sstevel@tonic-gate 		 * first time or if the user's
12057c478bd9Sstevel@tonic-gate 		 * password has been reset, the
12067c478bd9Sstevel@tonic-gate 		 * server sends this control to
12077c478bd9Sstevel@tonic-gate 		 * indicate that the client needs to
12087c478bd9Sstevel@tonic-gate 		 * change the password immediately.
12097c478bd9Sstevel@tonic-gate 		 *
12107c478bd9Sstevel@tonic-gate 		 * At this point, the only operation
12117c478bd9Sstevel@tonic-gate 		 * that the client can perform is to
12127c478bd9Sstevel@tonic-gate 		 * change the user's password. If the
12137c478bd9Sstevel@tonic-gate 		 * client requests any other LDAP
12147c478bd9Sstevel@tonic-gate 		 * operation, the server sends back
12157c478bd9Sstevel@tonic-gate 		 * an LDAP_UNWILLING_TO_PERFORM
12167c478bd9Sstevel@tonic-gate 		 * result code with an expired
12177c478bd9Sstevel@tonic-gate 		 * password control.
12187c478bd9Sstevel@tonic-gate 		 *
12197c478bd9Sstevel@tonic-gate 		 * The control with the OID
12207c478bd9Sstevel@tonic-gate 		 * 2.16.840.1.113730.3.4.5 (or
12217c478bd9Sstevel@tonic-gate 		 * LDAP_CONTROL_PWEXPIRING, as
12227c478bd9Sstevel@tonic-gate 		 * defined in the ldap.h header file)
12237c478bd9Sstevel@tonic-gate 		 * is the password expiration warning
12247c478bd9Sstevel@tonic-gate 		 * control.
12257c478bd9Sstevel@tonic-gate 		 *
12267c478bd9Sstevel@tonic-gate 		 * This control is used if the server
12277c478bd9Sstevel@tonic-gate 		 * is configured to expire user
12287c478bd9Sstevel@tonic-gate 		 * passwords after a certain amount
12297c478bd9Sstevel@tonic-gate 		 * of time.
12307c478bd9Sstevel@tonic-gate 		 *
12317c478bd9Sstevel@tonic-gate 		 * The server sends this control back
12327c478bd9Sstevel@tonic-gate 		 * to the client if the client binds
12337c478bd9Sstevel@tonic-gate 		 * using a password that will soon
12347c478bd9Sstevel@tonic-gate 		 * expire.  The ldctl_value field of
12357c478bd9Sstevel@tonic-gate 		 * the LDAPControl structure
12367c478bd9Sstevel@tonic-gate 		 * specifies the number of seconds
12377c478bd9Sstevel@tonic-gate 		 * before the password will expire.
12387c478bd9Sstevel@tonic-gate 		 */
12397c478bd9Sstevel@tonic-gate 		for (ctrl = controls; *ctrl; ctrl++) {
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 			if (strcmp((*ctrl)->ldctl_oid,
12427c478bd9Sstevel@tonic-gate 			    LDAP_CONTROL_PWEXPIRED) == 0) {
12437c478bd9Sstevel@tonic-gate 				/*
12447c478bd9Sstevel@tonic-gate 				 * if the caller wants this bind
12457c478bd9Sstevel@tonic-gate 				 * to fail, set up the error info.
12467c478bd9Sstevel@tonic-gate 				 * If call to this function is
12477c478bd9Sstevel@tonic-gate 				 * for searching the LDAP directory,
12487c478bd9Sstevel@tonic-gate 				 * e.g., __ns_ldap_list(),
12497c478bd9Sstevel@tonic-gate 				 * there's really no sense to
12507c478bd9Sstevel@tonic-gate 				 * let a connection open and
12517c478bd9Sstevel@tonic-gate 				 * then fail immediately afterward
12527c478bd9Sstevel@tonic-gate 				 * on the LDAP search operation with
12537c478bd9Sstevel@tonic-gate 				 * the LDAP_UNWILLING_TO_PERFORM rc
12547c478bd9Sstevel@tonic-gate 				 */
12557c478bd9Sstevel@tonic-gate 				pwd_status =
12567c478bd9Sstevel@tonic-gate 				    NS_PASSWD_CHANGE_NEEDED;
12577c478bd9Sstevel@tonic-gate 				if (fail_if_new_pwd_reqd) {
12587c478bd9Sstevel@tonic-gate 					(void) snprintf(errstr,
12597c478bd9Sstevel@tonic-gate 					    sizeof (errstr),
12607c478bd9Sstevel@tonic-gate 					    gettext(
12617c478bd9Sstevel@tonic-gate 					    "openConnection: "
12627c478bd9Sstevel@tonic-gate 					    "%s bind "
12637c478bd9Sstevel@tonic-gate 					    "failed "
12647c478bd9Sstevel@tonic-gate 					    "- password "
12657c478bd9Sstevel@tonic-gate 					    "expired. It "
12667c478bd9Sstevel@tonic-gate 					    " needs to change "
12677c478bd9Sstevel@tonic-gate 					    "immediately!"),
12687c478bd9Sstevel@tonic-gate 					    bind_type);
12697c478bd9Sstevel@tonic-gate 					MKERROR_PWD_MGMT(*errorp,
12707c478bd9Sstevel@tonic-gate 					    LDAP_SUCCESS,
12717c478bd9Sstevel@tonic-gate 					    strdup(errstr),
12727c478bd9Sstevel@tonic-gate 					    pwd_status,
12737c478bd9Sstevel@tonic-gate 					    0,
12747c478bd9Sstevel@tonic-gate 					    NULL);
12757c478bd9Sstevel@tonic-gate 					exit_rc = NS_LDAP_INTERNAL;
12767c478bd9Sstevel@tonic-gate 				} else {
12777c478bd9Sstevel@tonic-gate 					MKERROR_PWD_MGMT(*errorp,
12787c478bd9Sstevel@tonic-gate 					    LDAP_SUCCESS,
12797c478bd9Sstevel@tonic-gate 					    NULL,
12807c478bd9Sstevel@tonic-gate 					    pwd_status,
12817c478bd9Sstevel@tonic-gate 					    0,
12827c478bd9Sstevel@tonic-gate 					    NULL);
12837c478bd9Sstevel@tonic-gate 					exit_rc =
12847c478bd9Sstevel@tonic-gate 					    NS_LDAP_SUCCESS_WITH_INFO;
12857c478bd9Sstevel@tonic-gate 				}
12867c478bd9Sstevel@tonic-gate 				break;
12877c478bd9Sstevel@tonic-gate 			} else if (strcmp((*ctrl)->ldctl_oid,
12887c478bd9Sstevel@tonic-gate 			    LDAP_CONTROL_PWEXPIRING) == 0) {
12897c478bd9Sstevel@tonic-gate 				pwd_status =
12907c478bd9Sstevel@tonic-gate 				    NS_PASSWD_ABOUT_TO_EXPIRE;
12917c478bd9Sstevel@tonic-gate 				if ((*ctrl)->
12927c478bd9Sstevel@tonic-gate 				    ldctl_value.bv_len > 0 &&
12937c478bd9Sstevel@tonic-gate 				    (*ctrl)->
12947c478bd9Sstevel@tonic-gate 				    ldctl_value.bv_val)
12957c478bd9Sstevel@tonic-gate 					sec_until_exp =
12967c478bd9Sstevel@tonic-gate 					    atoi((*ctrl)->
12977c478bd9Sstevel@tonic-gate 					    ldctl_value.bv_val);
12987c478bd9Sstevel@tonic-gate 				MKERROR_PWD_MGMT(*errorp,
12997c478bd9Sstevel@tonic-gate 				    LDAP_SUCCESS,
13007c478bd9Sstevel@tonic-gate 				    NULL,
13017c478bd9Sstevel@tonic-gate 				    pwd_status,
13027c478bd9Sstevel@tonic-gate 				    sec_until_exp,
13037c478bd9Sstevel@tonic-gate 				    NULL);
13047c478bd9Sstevel@tonic-gate 				exit_rc =
13057c478bd9Sstevel@tonic-gate 				    NS_LDAP_SUCCESS_WITH_INFO;
13067c478bd9Sstevel@tonic-gate 				break;
13077c478bd9Sstevel@tonic-gate 			}
13087c478bd9Sstevel@tonic-gate 		}
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	if (controls)
13127c478bd9Sstevel@tonic-gate 		ldap_controls_free(controls);
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	return (exit_rc);
13157c478bd9Sstevel@tonic-gate }
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate static int
ldap_in_nss_switch(char * db)1318e1dd0a2fSth160488 ldap_in_nss_switch(char *db)
13197c478bd9Sstevel@tonic-gate {
13207c478bd9Sstevel@tonic-gate 	enum __nsw_parse_err		pserr;
13217c478bd9Sstevel@tonic-gate 	struct __nsw_switchconfig	*conf;
13227c478bd9Sstevel@tonic-gate 	struct __nsw_lookup		*lkp;
13237c478bd9Sstevel@tonic-gate 	const char			*name;
13247c478bd9Sstevel@tonic-gate 	int				found = 0;
13257c478bd9Sstevel@tonic-gate 
1326e1dd0a2fSth160488 	conf = __nsw_getconfig(db, &pserr);
13277c478bd9Sstevel@tonic-gate 	if (conf == NULL) {
13287c478bd9Sstevel@tonic-gate 		return (-1);
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	/* check for skip and count other backends */
13327c478bd9Sstevel@tonic-gate 	for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
13337c478bd9Sstevel@tonic-gate 		name = lkp->service_name;
13347c478bd9Sstevel@tonic-gate 		if (strcmp(name, "ldap") == 0) {
13357c478bd9Sstevel@tonic-gate 			found = 1;
13367c478bd9Sstevel@tonic-gate 			break;
13377c478bd9Sstevel@tonic-gate 		}
13387c478bd9Sstevel@tonic-gate 	}
13395ad42b1bSSurya Prakki 	(void) __nsw_freeconfig(conf);
13407c478bd9Sstevel@tonic-gate 	return (found);
13417c478bd9Sstevel@tonic-gate }
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@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)13447c478bd9Sstevel@tonic-gate openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
13457c478bd9Sstevel@tonic-gate 	int timeoutSec, ns_ldap_error_t **errorp,
1346e1dd0a2fSth160488 	int fail_if_new_pwd_reqd, int passwd_mgmt,
13476ad9980eSJulian Pullen 	ns_conn_user_t *conn_user, int flags)
13487c478bd9Sstevel@tonic-gate {
13497c478bd9Sstevel@tonic-gate 	LDAP			*ld = NULL;
13507c478bd9Sstevel@tonic-gate 	int			ldapVersion = LDAP_VERSION3;
13517c478bd9Sstevel@tonic-gate 	int			derefOption = LDAP_DEREF_ALWAYS;
13527c478bd9Sstevel@tonic-gate 	int			zero = 0;
13537c478bd9Sstevel@tonic-gate 	int			timeoutMilliSec = timeoutSec * 1000;
1354e1dd0a2fSth160488 	uint16_t		port = USE_DEFAULT_PORT;
1355e1dd0a2fSth160488 	char			*s;
1356e1dd0a2fSth160488 	char			errstr[MAXERROR];
13576ad9980eSJulian Pullen 	int			followRef;
1358e1dd0a2fSth160488 
1359e1dd0a2fSth160488 	ns_ldap_return_code	ret_code = NS_LDAP_SUCCESS;
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 	*errorp = NULL;
13627c478bd9Sstevel@tonic-gate 	*ldp = NULL;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	/* determine if the host name contains a port number */
13657c478bd9Sstevel@tonic-gate 	s = strchr(serverAddr, ']');	/* skip over ipv6 addr */
1366e1dd0a2fSth160488 	s = strchr(s != NULL ? s : serverAddr, ':');
13677c478bd9Sstevel@tonic-gate 	if (s != NULL) {
1368e1dd0a2fSth160488 		if (sscanf(s + 1, "%hu", &port) != 1) {
1369e1dd0a2fSth160488 			(void) snprintf(errstr,
1370e1dd0a2fSth160488 			    sizeof (errstr),
1371e1dd0a2fSth160488 			    gettext("openConnection: cannot "
1372e1dd0a2fSth160488 			    "convert %s into a valid "
1373e1dd0a2fSth160488 			    "port number for the "
1374e1dd0a2fSth160488 			    "%s server. A default value "
1375e1dd0a2fSth160488 			    "will be used."),
1376e1dd0a2fSth160488 			    s,
1377e1dd0a2fSth160488 			    serverAddr);
13787c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "libsldap: %s", errstr);
13797c478bd9Sstevel@tonic-gate 		} else {
1380e1dd0a2fSth160488 			*s = '\0';
1381e1dd0a2fSth160488 		}
1382cb5caa98Sdjl 	}
1383cb5caa98Sdjl 
1384e1dd0a2fSth160488 	ret_code = createSession(auth,
1385e1dd0a2fSth160488 	    serverAddr,
1386e1dd0a2fSth160488 	    port,
1387e1dd0a2fSth160488 	    timeoutMilliSec,
1388e1dd0a2fSth160488 	    &ld,
1389e1dd0a2fSth160488 	    errorp);
1390e1dd0a2fSth160488 	if (s != NULL) {
1391e1dd0a2fSth160488 		*s = ':';
1392e1dd0a2fSth160488 	}
1393e1dd0a2fSth160488 	if (ret_code != NS_LDAP_SUCCESS) {
1394e1dd0a2fSth160488 		return (ret_code);
1395e1dd0a2fSth160488 	}
1396e1dd0a2fSth160488 
1397e1dd0a2fSth160488 	/* check to see if the underlying libsldap supports MT connection */
1398e1dd0a2fSth160488 	if (conn_user != NULL) {
1399e1dd0a2fSth160488 		int rc;
1400e1dd0a2fSth160488 
1401e1dd0a2fSth160488 		rc = __s_api_check_libldap_MT_conn_support(conn_user, ld,
1402e1dd0a2fSth160488 		    errorp);
1403e1dd0a2fSth160488 		if (rc != NS_LDAP_SUCCESS) {
14047c478bd9Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1405e1dd0a2fSth160488 			return (rc);
14067c478bd9Sstevel@tonic-gate 		}
14077c478bd9Sstevel@tonic-gate 	}
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion);
14107c478bd9Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
14117c478bd9Sstevel@tonic-gate 	/*
14126ad9980eSJulian Pullen 	 * This library will handle the referral itself based on API flags or
14136ad9980eSJulian Pullen 	 * configuration file specification. The LDAP bind operation is an
14146ad9980eSJulian Pullen 	 * exception where we rely on the LDAP library to follow the referal.
14156ad9980eSJulian Pullen 	 *
14166ad9980eSJulian Pullen 	 * The LDAP follow referral option must be set to OFF for the libldap5
14176ad9980eSJulian Pullen 	 * to pass the referral info up to this library. This option MUST be
14186ad9980eSJulian Pullen 	 * set to OFF after we have performed a sucessful bind. If we are not
14196ad9980eSJulian Pullen 	 * to follow referrals we MUST also set the LDAP follow referral option
14206ad9980eSJulian Pullen 	 * to OFF before we perform an LDAP bind.
14217c478bd9Sstevel@tonic-gate 	 */
14226ad9980eSJulian Pullen 	ret_code = __s_api_toFollowReferrals(flags, &followRef, errorp);
14236ad9980eSJulian Pullen 	if (ret_code != NS_LDAP_SUCCESS) {
14246ad9980eSJulian Pullen 		(void) ldap_unbind(ld);
14256ad9980eSJulian Pullen 		return (ret_code);
14266ad9980eSJulian Pullen 	}
14276ad9980eSJulian Pullen 
14286ad9980eSJulian Pullen 	if (followRef)
14296ad9980eSJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
14306ad9980eSJulian Pullen 	else
14317c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
14326ad9980eSJulian Pullen 
14337c478bd9Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero);
14347c478bd9Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero);
14357c478bd9Sstevel@tonic-gate 	/* setup TCP/IP connect timeout */
14367c478bd9Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT,
14377c478bd9Sstevel@tonic-gate 	    &timeoutMilliSec);
14387c478bd9Sstevel@tonic-gate 	/* retry if LDAP I/O was interrupted */
14397c478bd9Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
14407c478bd9Sstevel@tonic-gate 
1441e1dd0a2fSth160488 	ret_code = performBind(auth,
1442e1dd0a2fSth160488 	    ld,
1443e1dd0a2fSth160488 	    timeoutSec,
14447c478bd9Sstevel@tonic-gate 	    errorp,
14457c478bd9Sstevel@tonic-gate 	    fail_if_new_pwd_reqd,
14467c478bd9Sstevel@tonic-gate 	    passwd_mgmt);
14477c478bd9Sstevel@tonic-gate 
1448e1dd0a2fSth160488 	if (ret_code == NS_LDAP_SUCCESS ||
1449e1dd0a2fSth160488 	    ret_code == NS_LDAP_SUCCESS_WITH_INFO) {
14506ad9980eSJulian Pullen 		/*
14516ad9980eSJulian Pullen 		 * Turn off LDAP referral following so that this library can
14526ad9980eSJulian Pullen 		 * process referrals.
14536ad9980eSJulian Pullen 		 */
14546ad9980eSJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
14557c478bd9Sstevel@tonic-gate 		*ldp = ld;
14567c478bd9Sstevel@tonic-gate 	}
14577c478bd9Sstevel@tonic-gate 
1458e1dd0a2fSth160488 	return (ret_code);
14597c478bd9Sstevel@tonic-gate }
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate /*
14627c478bd9Sstevel@tonic-gate  * FUNCTION:	__s_api_getDefaultAuth
14637c478bd9Sstevel@tonic-gate  *
14647c478bd9Sstevel@tonic-gate  *	Constructs a credential for authentication using the config module.
14657c478bd9Sstevel@tonic-gate  *
14667c478bd9Sstevel@tonic-gate  * RETURN VALUES:
14677c478bd9Sstevel@tonic-gate  *
14687c478bd9Sstevel@tonic-gate  * NS_LDAP_SUCCESS	If successful
14697c478bd9Sstevel@tonic-gate  * NS_LDAP_CONFIG	If there are any config errors.
14707c478bd9Sstevel@tonic-gate  * NS_LDAP_MEMORY	Memory errors.
14717c478bd9Sstevel@tonic-gate  * NS_LDAP_OP_FAILED	If there are no more authentication methods so can
14727c478bd9Sstevel@tonic-gate  *			not build a new authp.
14737c478bd9Sstevel@tonic-gate  * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the
14747c478bd9Sstevel@tonic-gate  *			necessary fields of a cred for a given auth method
14757c478bd9Sstevel@tonic-gate  *			are not provided.
14767c478bd9Sstevel@tonic-gate  * INPUT:
14777c478bd9Sstevel@tonic-gate  *
14787c478bd9Sstevel@tonic-gate  * cLevel	Currently requested credential level to be tried
14797c478bd9Sstevel@tonic-gate  *
14807c478bd9Sstevel@tonic-gate  * aMethod	Currently requested authentication method to be tried
14817c478bd9Sstevel@tonic-gate  *
1482b57459abSJulian Pullen  * getAdmin	If non 0,  get Admin -i.e., not proxyAgent- DN and password
1483b57459abSJulian Pullen  *
14847c478bd9Sstevel@tonic-gate  * OUTPUT:
14857c478bd9Sstevel@tonic-gate  *
14867c478bd9Sstevel@tonic-gate  * authp		authentication method to use.
14877c478bd9Sstevel@tonic-gate  */
14887c478bd9Sstevel@tonic-gate static int
__s_api_getDefaultAuth(int * cLevel,ns_auth_t * aMethod,ns_cred_t ** authp,int getAdmin)14897c478bd9Sstevel@tonic-gate __s_api_getDefaultAuth(
14907c478bd9Sstevel@tonic-gate 	int	*cLevel,
14917c478bd9Sstevel@tonic-gate 	ns_auth_t *aMethod,
1492b57459abSJulian Pullen 	ns_cred_t **authp,
1493b57459abSJulian Pullen 	int	getAdmin)
14947c478bd9Sstevel@tonic-gate {
14957c478bd9Sstevel@tonic-gate 	void		**paramVal = NULL;
14967c478bd9Sstevel@tonic-gate 	char		*modparamVal = NULL;
14977c478bd9Sstevel@tonic-gate 	int		getUid = 0;
14987c478bd9Sstevel@tonic-gate 	int		getPasswd = 0;
14997c478bd9Sstevel@tonic-gate 	int		getCertpath = 0;
15007c478bd9Sstevel@tonic-gate 	int		rc = 0;
15017c478bd9Sstevel@tonic-gate 	ns_ldap_error_t	*errorp = NULL;
1502b57459abSJulian Pullen 	UnixCred_t	*AdminCred = NULL;
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate #ifdef DEBUG
15057c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "__s_api_getDefaultAuth START\n");
15067c478bd9Sstevel@tonic-gate #endif
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	if (aMethod == NULL) {
15097c478bd9Sstevel@tonic-gate 		/* Require an Auth */
15107c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 	}
15137c478bd9Sstevel@tonic-gate 	/*
1514cb5caa98Sdjl 	 * credential level "self" can work with auth method sasl/GSSAPI only
15157c478bd9Sstevel@tonic-gate 	 */
1516cb5caa98Sdjl 	if (cLevel && *cLevel == NS_LDAP_CRED_SELF &&
1517cb5caa98Sdjl 	    aMethod->saslmech != NS_LDAP_SASL_GSSAPI)
15187c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	*authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
15217c478bd9Sstevel@tonic-gate 	if ((*authp) == NULL)
15227c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	(*authp)->auth = *aMethod;
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	switch (aMethod->type) {
15277c478bd9Sstevel@tonic-gate 		case NS_LDAP_AUTH_NONE:
15287c478bd9Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
15297c478bd9Sstevel@tonic-gate 		case NS_LDAP_AUTH_SIMPLE:
15307c478bd9Sstevel@tonic-gate 			getUid++;
15317c478bd9Sstevel@tonic-gate 			getPasswd++;
15327c478bd9Sstevel@tonic-gate 			break;
15337c478bd9Sstevel@tonic-gate 		case NS_LDAP_AUTH_SASL:
15347c478bd9Sstevel@tonic-gate 			if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
15357c478bd9Sstevel@tonic-gate 			    (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) {
15367c478bd9Sstevel@tonic-gate 				getUid++;
15377c478bd9Sstevel@tonic-gate 				getPasswd++;
1538cb5caa98Sdjl 			} else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) {
15397c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeCred(authp);
15407c478bd9Sstevel@tonic-gate 				return (NS_LDAP_INVALID_PARAM);
15417c478bd9Sstevel@tonic-gate 			}
15427c478bd9Sstevel@tonic-gate 			break;
15437c478bd9Sstevel@tonic-gate 		case NS_LDAP_AUTH_TLS:
15447c478bd9Sstevel@tonic-gate 			if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) ||
15457c478bd9Sstevel@tonic-gate 			    ((aMethod->tlstype == NS_LDAP_TLS_SASL) &&
15467c478bd9Sstevel@tonic-gate 			    ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
15477c478bd9Sstevel@tonic-gate 			    (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) {
15487c478bd9Sstevel@tonic-gate 				getUid++;
15497c478bd9Sstevel@tonic-gate 				getPasswd++;
15507c478bd9Sstevel@tonic-gate 				getCertpath++;
15517c478bd9Sstevel@tonic-gate 			} else if (aMethod->tlstype == NS_LDAP_TLS_NONE) {
15527c478bd9Sstevel@tonic-gate 				getCertpath++;
15537c478bd9Sstevel@tonic-gate 			} else {
15547c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeCred(authp);
15557c478bd9Sstevel@tonic-gate 				return (NS_LDAP_INVALID_PARAM);
15567c478bd9Sstevel@tonic-gate 			}
15577c478bd9Sstevel@tonic-gate 			break;
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	if (getUid) {
15617c478bd9Sstevel@tonic-gate 		paramVal = NULL;
1562b57459abSJulian Pullen 		if (getAdmin) {
1563b57459abSJulian Pullen 			/*
1564b57459abSJulian Pullen 			 * Assume AdminCred has been retrieved from
1565b57459abSJulian Pullen 			 * ldap_cachemgr already. It will not work
1566b57459abSJulian Pullen 			 * without userID or password. Flags getUid
1567b57459abSJulian Pullen 			 * and getPasswd should always be set
1568b57459abSJulian Pullen 			 * together.
1569b57459abSJulian Pullen 			 */
1570b57459abSJulian Pullen 			AdminCred = calloc(1, sizeof (UnixCred_t));
1571b57459abSJulian Pullen 			if (AdminCred == NULL) {
1572b57459abSJulian Pullen 				(void) __ns_ldap_freeCred(authp);
1573b57459abSJulian Pullen 				return (NS_LDAP_MEMORY);
1574b57459abSJulian Pullen 			}
1575b57459abSJulian Pullen 
1576b57459abSJulian Pullen 			rc = requestAdminCred(&AdminCred, &errorp);
1577b57459abSJulian Pullen 			if (rc != NS_LDAP_SUCCESS) {
1578b57459abSJulian Pullen 				(void) __ns_ldap_freeCred(authp);
1579b57459abSJulian Pullen 				(void) __ns_ldap_freeUnixCred(&AdminCred);
1580b57459abSJulian Pullen 				(void) __ns_ldap_freeError(&errorp);
1581b57459abSJulian Pullen 				return (rc);
1582b57459abSJulian Pullen 			}
1583b57459abSJulian Pullen 
1584b57459abSJulian Pullen 			if (AdminCred->userID == NULL) {
1585b57459abSJulian Pullen 				(void) __ns_ldap_freeCred(authp);
1586b57459abSJulian Pullen 				(void) __ns_ldap_freeUnixCred(&AdminCred);
1587b57459abSJulian Pullen 				return (NS_LDAP_INVALID_PARAM);
1588b57459abSJulian Pullen 			}
1589b57459abSJulian Pullen 			(*authp)->cred.unix_cred.userID = AdminCred->userID;
1590b57459abSJulian Pullen 			AdminCred->userID = NULL;
1591b57459abSJulian Pullen 		} else {
1592b57459abSJulian Pullen 			rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P,
1593b57459abSJulian Pullen 			    &paramVal, &errorp);
1594b57459abSJulian Pullen 			if (rc != NS_LDAP_SUCCESS) {
15957c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeCred(authp);
15967c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeError(&errorp);
15977c478bd9Sstevel@tonic-gate 				return (rc);
15987c478bd9Sstevel@tonic-gate 			}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 			if (paramVal == NULL || *paramVal == NULL) {
16017c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeCred(authp);
16027c478bd9Sstevel@tonic-gate 				return (NS_LDAP_INVALID_PARAM);
16037c478bd9Sstevel@tonic-gate 			}
16047c478bd9Sstevel@tonic-gate 
1605b57459abSJulian Pullen 			(*authp)->cred.unix_cred.userID =
1606b57459abSJulian Pullen 			    strdup((char *)*paramVal);
16077c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeParam(&paramVal);
1608b57459abSJulian Pullen 		}
16097c478bd9Sstevel@tonic-gate 		if ((*authp)->cred.unix_cred.userID == NULL) {
16107c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1611b57459abSJulian Pullen 			(void) __ns_ldap_freeUnixCred(&AdminCred);
16127c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
16137c478bd9Sstevel@tonic-gate 		}
16147c478bd9Sstevel@tonic-gate 	}
16157c478bd9Sstevel@tonic-gate 	if (getPasswd) {
16167c478bd9Sstevel@tonic-gate 		paramVal = NULL;
1617b57459abSJulian Pullen 		if (getAdmin) {
1618b57459abSJulian Pullen 			/*
1619b57459abSJulian Pullen 			 * Assume AdminCred has been retrieved from
1620b57459abSJulian Pullen 			 * ldap_cachemgr already. It will not work
1621b57459abSJulian Pullen 			 * without the userID anyway because for
1622b57459abSJulian Pullen 			 * getting admin credential, flags getUid
1623b57459abSJulian Pullen 			 * and getPasswd should always be set
1624b57459abSJulian Pullen 			 * together.
1625b57459abSJulian Pullen 			 */
1626b57459abSJulian Pullen 			if (AdminCred == NULL || AdminCred->passwd == NULL) {
1627b57459abSJulian Pullen 				(void) __ns_ldap_freeCred(authp);
1628b57459abSJulian Pullen 				(void) __ns_ldap_freeUnixCred(&AdminCred);
1629b57459abSJulian Pullen 				return (NS_LDAP_INVALID_PARAM);
1630b57459abSJulian Pullen 			}
1631b57459abSJulian Pullen 			modparamVal = dvalue(AdminCred->passwd);
1632b57459abSJulian Pullen 		} else {
1633b57459abSJulian Pullen 			rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P,
1634b57459abSJulian Pullen 			    &paramVal, &errorp);
1635b57459abSJulian Pullen 			if (rc != NS_LDAP_SUCCESS) {
16367c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeCred(authp);
16377c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeError(&errorp);
16387c478bd9Sstevel@tonic-gate 				return (rc);
16397c478bd9Sstevel@tonic-gate 			}
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 			if (paramVal == NULL || *paramVal == NULL) {
16427c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeCred(authp);
16437c478bd9Sstevel@tonic-gate 				return (NS_LDAP_INVALID_PARAM);
16447c478bd9Sstevel@tonic-gate 			}
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 			modparamVal = dvalue((char *)*paramVal);
16477c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeParam(&paramVal);
1648b57459abSJulian Pullen 		}
1649b57459abSJulian Pullen 
16507c478bd9Sstevel@tonic-gate 		if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) {
16517c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1652b57459abSJulian Pullen 			(void) __ns_ldap_freeUnixCred(&AdminCred);
16537c478bd9Sstevel@tonic-gate 			if (modparamVal != NULL)
16547c478bd9Sstevel@tonic-gate 				free(modparamVal);
16557c478bd9Sstevel@tonic-gate 			return (NS_LDAP_INVALID_PARAM);
16567c478bd9Sstevel@tonic-gate 		}
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 		(*authp)->cred.unix_cred.passwd = modparamVal;
16597c478bd9Sstevel@tonic-gate 	}
16607c478bd9Sstevel@tonic-gate 	if (getCertpath) {
16617c478bd9Sstevel@tonic-gate 		paramVal = NULL;
16627c478bd9Sstevel@tonic-gate 		if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
16637c478bd9Sstevel@tonic-gate 		    &paramVal, &errorp)) != NS_LDAP_SUCCESS) {
16647c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1665b57459abSJulian Pullen 			(void) __ns_ldap_freeUnixCred(&AdminCred);
16667c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeError(&errorp);
16677c478bd9Sstevel@tonic-gate 			*authp = NULL;
16687c478bd9Sstevel@tonic-gate 			return (rc);
16697c478bd9Sstevel@tonic-gate 		}
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 		if (paramVal == NULL || *paramVal == NULL) {
16727c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1673b57459abSJulian Pullen 			(void) __ns_ldap_freeUnixCred(&AdminCred);
16747c478bd9Sstevel@tonic-gate 			*authp = NULL;
16757c478bd9Sstevel@tonic-gate 			return (NS_LDAP_INVALID_PARAM);
16767c478bd9Sstevel@tonic-gate 		}
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 		(*authp)->hostcertpath = strdup((char *)*paramVal);
16797c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeParam(&paramVal);
16807c478bd9Sstevel@tonic-gate 		if ((*authp)->hostcertpath == NULL) {
16817c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1682b57459abSJulian Pullen 			(void) __ns_ldap_freeUnixCred(&AdminCred);
16837c478bd9Sstevel@tonic-gate 			*authp = NULL;
16847c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
16857c478bd9Sstevel@tonic-gate 		}
16867c478bd9Sstevel@tonic-gate 	}
1687b57459abSJulian Pullen 	(void) __ns_ldap_freeUnixCred(&AdminCred);
16887c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
16897c478bd9Sstevel@tonic-gate }
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate /*
1692e1dd0a2fSth160488  * FUNCTION:	getConnection
16937c478bd9Sstevel@tonic-gate  *
1694e1dd0a2fSth160488  *	internal version of __s_api_getConnection()
16957c478bd9Sstevel@tonic-gate  */
1696e1dd0a2fSth160488 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)1697e1dd0a2fSth160488 getConnection(
16987c478bd9Sstevel@tonic-gate 	const char *server,
16997c478bd9Sstevel@tonic-gate 	const int flags,
17007c478bd9Sstevel@tonic-gate 	const ns_cred_t *cred,		/* credentials for bind */
17017c478bd9Sstevel@tonic-gate 	ConnectionID *sessionId,
17027c478bd9Sstevel@tonic-gate 	Connection **session,
17037c478bd9Sstevel@tonic-gate 	ns_ldap_error_t **errorp,
170447789246Svv149972 	int fail_if_new_pwd_reqd,
1705e1dd0a2fSth160488 	int nopasswd_acct_mgmt,
1706e1dd0a2fSth160488 	ns_conn_user_t *conn_user)
17077c478bd9Sstevel@tonic-gate {
17087c478bd9Sstevel@tonic-gate 	char		errmsg[MAXERROR];
17097c478bd9Sstevel@tonic-gate 	ns_auth_t	**aMethod = NULL;
17107c478bd9Sstevel@tonic-gate 	ns_auth_t	**aNext = NULL;
17117c478bd9Sstevel@tonic-gate 	int		**cLevel = NULL;
17127c478bd9Sstevel@tonic-gate 	int		**cNext = NULL;
17137c478bd9Sstevel@tonic-gate 	int		timeoutSec = NS_DEFAULT_BIND_TIMEOUT;
17147c478bd9Sstevel@tonic-gate 	int		rc;
17157c478bd9Sstevel@tonic-gate 	Connection	*con = NULL;
17167c478bd9Sstevel@tonic-gate 	int		sec = 1;
17177c478bd9Sstevel@tonic-gate 	ns_cred_t 	*authp = NULL;
17187c478bd9Sstevel@tonic-gate 	ns_cred_t	anon;
1719cb5caa98Sdjl 	int		version = NS_LDAP_V2, self_gssapi_only = 0;
17207c478bd9Sstevel@tonic-gate 	void		**paramVal = NULL;
1721689c2bf4Sjanga 	char		**badSrvrs = NULL; /* List of problem hostnames */
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	if ((session == NULL) || (sessionId == NULL)) {
17247c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
17257c478bd9Sstevel@tonic-gate 	}
17267c478bd9Sstevel@tonic-gate 	*session = NULL;
17277c478bd9Sstevel@tonic-gate 
1728e1dd0a2fSth160488 	/* reuse MT connection if needed and if available */
1729e1dd0a2fSth160488 	if (conn_user != NULL) {
1730e1dd0a2fSth160488 		rc = __s_api_conn_mt_get(server, flags, cred, session, errorp,
1731e1dd0a2fSth160488 		    conn_user);
1732e1dd0a2fSth160488 		if (rc != NS_LDAP_NOTFOUND)
1733e1dd0a2fSth160488 			return (rc);
17347c478bd9Sstevel@tonic-gate 	}
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	/* get profile version number */
17377c478bd9Sstevel@tonic-gate 	if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P,
17387c478bd9Sstevel@tonic-gate 	    &paramVal, errorp)) != NS_LDAP_SUCCESS)
17397c478bd9Sstevel@tonic-gate 		return (rc);
17407c478bd9Sstevel@tonic-gate 	if (paramVal == NULL) {
17417c478bd9Sstevel@tonic-gate 		(void) sprintf(errmsg, gettext("getConnection: no file "
17427c478bd9Sstevel@tonic-gate 		    "version"));
17437c478bd9Sstevel@tonic-gate 		MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg),
17447c478bd9Sstevel@tonic-gate 		    NS_LDAP_CONFIG);
17457c478bd9Sstevel@tonic-gate 		return (NS_LDAP_CONFIG);
17467c478bd9Sstevel@tonic-gate 	}
17477c478bd9Sstevel@tonic-gate 	if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0)
17487c478bd9Sstevel@tonic-gate 		version = NS_LDAP_V1;
17497c478bd9Sstevel@tonic-gate 	(void) __ns_ldap_freeParam((void ***)&paramVal);
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	/* Get the bind timeout value */
17527c478bd9Sstevel@tonic-gate 	(void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, &paramVal, errorp);
17537c478bd9Sstevel@tonic-gate 	if (paramVal != NULL && *paramVal != NULL) {
17547c478bd9Sstevel@tonic-gate 		timeoutSec = **((int **)paramVal);
17557c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeParam(&paramVal);
17567c478bd9Sstevel@tonic-gate 	}
17577c478bd9Sstevel@tonic-gate 	if (*errorp)
17587c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeError(errorp);
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	if (cred == NULL) {
17617c478bd9Sstevel@tonic-gate 		/* Get the authentication method list */
17627c478bd9Sstevel@tonic-gate 		if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P,
17637c478bd9Sstevel@tonic-gate 		    (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS)
17647c478bd9Sstevel@tonic-gate 			return (rc);
17657c478bd9Sstevel@tonic-gate 		if (aMethod == NULL) {
17667c478bd9Sstevel@tonic-gate 			aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *));
17677c478bd9Sstevel@tonic-gate 			if (aMethod == NULL)
17687c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
17697c478bd9Sstevel@tonic-gate 			aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t));
17707c478bd9Sstevel@tonic-gate 			if (aMethod[0] == NULL) {
17717c478bd9Sstevel@tonic-gate 				free(aMethod);
17727c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
17737c478bd9Sstevel@tonic-gate 			}
17747c478bd9Sstevel@tonic-gate 			if (version == NS_LDAP_V1)
17757c478bd9Sstevel@tonic-gate 				(aMethod[0])->type = NS_LDAP_AUTH_SIMPLE;
17767c478bd9Sstevel@tonic-gate 			else {
17777c478bd9Sstevel@tonic-gate 				(aMethod[0])->type = NS_LDAP_AUTH_SASL;
17787c478bd9Sstevel@tonic-gate 				(aMethod[0])->saslmech =
17797c478bd9Sstevel@tonic-gate 				    NS_LDAP_SASL_DIGEST_MD5;
17807c478bd9Sstevel@tonic-gate 				(aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE;
17817c478bd9Sstevel@tonic-gate 			}
17827c478bd9Sstevel@tonic-gate 		}
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 		/* Get the credential level list */
17857c478bd9Sstevel@tonic-gate 		if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
17867c478bd9Sstevel@tonic-gate 		    (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) {
17877c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeParam((void ***)&aMethod);
17887c478bd9Sstevel@tonic-gate 			return (rc);
17897c478bd9Sstevel@tonic-gate 		}
17907c478bd9Sstevel@tonic-gate 		if (cLevel == NULL) {
17917c478bd9Sstevel@tonic-gate 			cLevel = (int **)calloc(2, sizeof (int *));
17927c478bd9Sstevel@tonic-gate 			if (cLevel == NULL)
17937c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
17947c478bd9Sstevel@tonic-gate 			cLevel[0] = (int *)calloc(1, sizeof (int));
17957c478bd9Sstevel@tonic-gate 			if (cLevel[0] == NULL)
17967c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
17977c478bd9Sstevel@tonic-gate 			if (version == NS_LDAP_V1)
17987c478bd9Sstevel@tonic-gate 				*(cLevel[0]) = NS_LDAP_CRED_PROXY;
17997c478bd9Sstevel@tonic-gate 			else
18007c478bd9Sstevel@tonic-gate 				*(cLevel[0]) = NS_LDAP_CRED_ANON;
18017c478bd9Sstevel@tonic-gate 		}
18027c478bd9Sstevel@tonic-gate 	}
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 	/* setup the anon credential for anonymous connection */
18057c478bd9Sstevel@tonic-gate 	(void) memset(&anon, 0, sizeof (ns_cred_t));
18067c478bd9Sstevel@tonic-gate 	anon.auth.type = NS_LDAP_AUTH_NONE;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	for (;;) {
18097c478bd9Sstevel@tonic-gate 		if (cred != NULL) {
18107c478bd9Sstevel@tonic-gate 			/* using specified auth method */
18117c478bd9Sstevel@tonic-gate 			rc = makeConnection(&con, server, cred,
18127c478bd9Sstevel@tonic-gate 			    sessionId, timeoutSec, errorp,
1813cb5caa98Sdjl 			    fail_if_new_pwd_reqd,
1814e1dd0a2fSth160488 			    nopasswd_acct_mgmt, flags, &badSrvrs, conn_user);
18157df6d046Smj162486 			/* not using bad server if credentials were supplied */
18167df6d046Smj162486 			if (badSrvrs && *badSrvrs) {
18177df6d046Smj162486 				__s_api_free2dArray(badSrvrs);
18187df6d046Smj162486 				badSrvrs = NULL;
18197df6d046Smj162486 			}
18207c478bd9Sstevel@tonic-gate 			if (rc == NS_LDAP_SUCCESS ||
18217c478bd9Sstevel@tonic-gate 			    rc == NS_LDAP_SUCCESS_WITH_INFO) {
18227c478bd9Sstevel@tonic-gate 				*session = con;
18237c478bd9Sstevel@tonic-gate 				break;
18247c478bd9Sstevel@tonic-gate 			}
18257c478bd9Sstevel@tonic-gate 		} else {
1826cb5caa98Sdjl 			self_gssapi_only = __s_api_self_gssapi_only_get();
18277c478bd9Sstevel@tonic-gate 			/* for every cred level */
18287c478bd9Sstevel@tonic-gate 			for (cNext = cLevel; *cNext != NULL; cNext++) {
1829cb5caa98Sdjl 				if (self_gssapi_only &&
1830cb5caa98Sdjl 				    **cNext != NS_LDAP_CRED_SELF)
1831cb5caa98Sdjl 					continue;
18327c478bd9Sstevel@tonic-gate 				if (**cNext == NS_LDAP_CRED_ANON) {
1833689c2bf4Sjanga 					/*
1834689c2bf4Sjanga 					 * make connection anonymously
1835689c2bf4Sjanga 					 * Free the down server list before
1836689c2bf4Sjanga 					 * looping through
1837689c2bf4Sjanga 					 */
1838689c2bf4Sjanga 					if (badSrvrs && *badSrvrs) {
1839689c2bf4Sjanga 						__s_api_free2dArray(badSrvrs);
1840689c2bf4Sjanga 						badSrvrs = NULL;
1841689c2bf4Sjanga 					}
18427c478bd9Sstevel@tonic-gate 					rc = makeConnection(&con, server, &anon,
18437c478bd9Sstevel@tonic-gate 					    sessionId, timeoutSec, errorp,
184447789246Svv149972 					    fail_if_new_pwd_reqd,
1845cb5caa98Sdjl 					    nopasswd_acct_mgmt, flags,
1846e1dd0a2fSth160488 					    &badSrvrs, conn_user);
18477c478bd9Sstevel@tonic-gate 					if (rc == NS_LDAP_SUCCESS ||
18487c478bd9Sstevel@tonic-gate 					    rc ==
18497c478bd9Sstevel@tonic-gate 					    NS_LDAP_SUCCESS_WITH_INFO) {
18507c478bd9Sstevel@tonic-gate 						*session = con;
18517c478bd9Sstevel@tonic-gate 						goto done;
18527c478bd9Sstevel@tonic-gate 					}
18537c478bd9Sstevel@tonic-gate 					continue;
18547c478bd9Sstevel@tonic-gate 				}
18557c478bd9Sstevel@tonic-gate 				/* for each cred level */
18567c478bd9Sstevel@tonic-gate 				for (aNext = aMethod; *aNext != NULL; aNext++) {
1857cb5caa98Sdjl 					if (self_gssapi_only &&
1858cb5caa98Sdjl 					    (*aNext)->saslmech !=
1859cb5caa98Sdjl 					    NS_LDAP_SASL_GSSAPI)
1860cb5caa98Sdjl 						continue;
1861cb5caa98Sdjl 					/*
1862cb5caa98Sdjl 					 * self coexists with sasl/GSSAPI only
1863cb5caa98Sdjl 					 * and non-self coexists with non-gssapi
1864cb5caa98Sdjl 					 * only
1865cb5caa98Sdjl 					 */
1866cb5caa98Sdjl 					if ((**cNext == NS_LDAP_CRED_SELF &&
1867cb5caa98Sdjl 					    (*aNext)->saslmech !=
1868cb5caa98Sdjl 					    NS_LDAP_SASL_GSSAPI) ||
1869cb5caa98Sdjl 					    (**cNext != NS_LDAP_CRED_SELF &&
1870cb5caa98Sdjl 					    (*aNext)->saslmech ==
1871cb5caa98Sdjl 					    NS_LDAP_SASL_GSSAPI))
1872cb5caa98Sdjl 						continue;
18737c478bd9Sstevel@tonic-gate 					/* make connection and authenticate */
18747c478bd9Sstevel@tonic-gate 					/* with default credentials */
18757c478bd9Sstevel@tonic-gate 					authp = NULL;
18767c478bd9Sstevel@tonic-gate 					rc = __s_api_getDefaultAuth(*cNext,
1877b57459abSJulian Pullen 					    *aNext, &authp,
1878b57459abSJulian Pullen 					    flags & NS_LDAP_READ_SHADOW);
18797c478bd9Sstevel@tonic-gate 					if (rc != NS_LDAP_SUCCESS) {
18807c478bd9Sstevel@tonic-gate 						continue;
18817c478bd9Sstevel@tonic-gate 					}
1882689c2bf4Sjanga 					/*
1883689c2bf4Sjanga 					 * Free the down server list before
1884689c2bf4Sjanga 					 * looping through
1885689c2bf4Sjanga 					 */
1886689c2bf4Sjanga 					if (badSrvrs && *badSrvrs) {
1887689c2bf4Sjanga 						__s_api_free2dArray(badSrvrs);
1888689c2bf4Sjanga 						badSrvrs = NULL;
1889689c2bf4Sjanga 					}
18907c478bd9Sstevel@tonic-gate 					rc = makeConnection(&con, server, authp,
18917c478bd9Sstevel@tonic-gate 					    sessionId, timeoutSec, errorp,
189247789246Svv149972 					    fail_if_new_pwd_reqd,
1893cb5caa98Sdjl 					    nopasswd_acct_mgmt, flags,
1894e1dd0a2fSth160488 					    &badSrvrs, conn_user);
18957c478bd9Sstevel@tonic-gate 					(void) __ns_ldap_freeCred(&authp);
18967c478bd9Sstevel@tonic-gate 					if (rc == NS_LDAP_SUCCESS ||
18977c478bd9Sstevel@tonic-gate 					    rc ==
18987c478bd9Sstevel@tonic-gate 					    NS_LDAP_SUCCESS_WITH_INFO) {
18997c478bd9Sstevel@tonic-gate 						*session = con;
19007c478bd9Sstevel@tonic-gate 						goto done;
19017c478bd9Sstevel@tonic-gate 					}
19027c478bd9Sstevel@tonic-gate 				}
19037c478bd9Sstevel@tonic-gate 			}
19047c478bd9Sstevel@tonic-gate 		}
19057c478bd9Sstevel@tonic-gate 		if (flags & NS_LDAP_HARD) {
19067c478bd9Sstevel@tonic-gate 			if (sec < LDAPMAXHARDLOOKUPTIME)
19077c478bd9Sstevel@tonic-gate 				sec *= 2;
19087257d1b4Sraf 			(void) sleep(sec);
19097c478bd9Sstevel@tonic-gate 		} else {
19107c478bd9Sstevel@tonic-gate 			break;
19117c478bd9Sstevel@tonic-gate 		}
19127c478bd9Sstevel@tonic-gate 	}
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate done:
1915cb5caa98Sdjl 	if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) {
1916cb5caa98Sdjl 		/*
1917cb5caa98Sdjl 		 * self_gssapi_only is true but no self/sasl/gssapi is
1918cb5caa98Sdjl 		 * configured
1919cb5caa98Sdjl 		 */
1920cb5caa98Sdjl 		rc = NS_LDAP_CONFIG;
1921cb5caa98Sdjl 	}
1922cb5caa98Sdjl 
19237c478bd9Sstevel@tonic-gate 	(void) __ns_ldap_freeParam((void ***)&aMethod);
19247c478bd9Sstevel@tonic-gate 	(void) __ns_ldap_freeParam((void ***)&cLevel);
1925689c2bf4Sjanga 
1926689c2bf4Sjanga 	if (badSrvrs && *badSrvrs) {
1927689c2bf4Sjanga 		/*
1928689c2bf4Sjanga 		 * At this point, either we have a successful
1929689c2bf4Sjanga 		 * connection or exhausted all the possible auths.
1930689c2bf4Sjanga 		 * and creds. Mark the problem servers as down
1931689c2bf4Sjanga 		 * so that the problem servers are not contacted
1932689c2bf4Sjanga 		 * again until the refresh_ttl expires.
1933689c2bf4Sjanga 		 */
1934689c2bf4Sjanga 		(void) __s_api_removeBadServers(badSrvrs);
1935689c2bf4Sjanga 		__s_api_free2dArray(badSrvrs);
1936689c2bf4Sjanga 	}
19377c478bd9Sstevel@tonic-gate 	return (rc);
19387c478bd9Sstevel@tonic-gate }
19397c478bd9Sstevel@tonic-gate 
1940e1dd0a2fSth160488 /*
1941e1dd0a2fSth160488  * FUNCTION:	__s_api_getConnection
1942e1dd0a2fSth160488  *
1943e1dd0a2fSth160488  *	Bind to the specified server or one from the server
1944e1dd0a2fSth160488  *	list and return the pointer.
1945e1dd0a2fSth160488  *
1946e1dd0a2fSth160488  *	This function can rebind or not (NS_LDAP_HARD), it can require a
1947e1dd0a2fSth160488  *	credential or bind anonymously
1948e1dd0a2fSth160488  *
1949e1dd0a2fSth160488  *	This function follows the DUA configuration schema algorithm
1950e1dd0a2fSth160488  *
1951e1dd0a2fSth160488  * RETURN VALUES:
1952e1dd0a2fSth160488  *
1953e1dd0a2fSth160488  * NS_LDAP_SUCCESS	A connection was made successfully.
1954e1dd0a2fSth160488  * NS_LDAP_SUCCESS_WITH_INFO
1955e1dd0a2fSth160488  * 			A connection was made successfully, but with
1956e1dd0a2fSth160488  *			password management info in *errorp
1957e1dd0a2fSth160488  * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function.
1958e1dd0a2fSth160488  * NS_LDAP_CONFIG	If there are any config errors.
1959e1dd0a2fSth160488  * NS_LDAP_MEMORY	Memory errors.
1960e1dd0a2fSth160488  * NS_LDAP_INTERNAL	If there was a ldap error.
1961e1dd0a2fSth160488  *
1962e1dd0a2fSth160488  * INPUT:
1963e1dd0a2fSth160488  *
1964e1dd0a2fSth160488  * server	Bind to this LDAP server only
1965e1dd0a2fSth160488  * flags	If NS_LDAP_HARD is set function will not return until it has
1966e1dd0a2fSth160488  *		a connection unless there is a authentication problem.
1967e1dd0a2fSth160488  *		If NS_LDAP_NEW_CONN is set the function must force a new
1968e1dd0a2fSth160488  *              connection to be created
1969e1dd0a2fSth160488  *		If NS_LDAP_KEEP_CONN is set the connection is to be kept open
1970e1dd0a2fSth160488  * auth		Credentials for bind. This could be NULL in which case
1971e1dd0a2fSth160488  *		a default cred built from the config module is used.
1972e1dd0a2fSth160488  * sessionId	cookie that points to a previous session
1973e1dd0a2fSth160488  * fail_if_new_pwd_reqd
1974e1dd0a2fSth160488  *		a flag indicating this function should fail if the passwd
1975e1dd0a2fSth160488  *		in auth needs to change immediately
1976e1dd0a2fSth160488  * nopasswd_acct_mgmt
1977e1dd0a2fSth160488  *		a flag indicating that makeConnection should check before
1978e1dd0a2fSth160488  *		binding if server supports LDAP V3 password less
1979e1dd0a2fSth160488  *		account management
1980e1dd0a2fSth160488  *
1981e1dd0a2fSth160488  * OUTPUT:
1982e1dd0a2fSth160488  *
1983e1dd0a2fSth160488  * session	pointer to a session with connection information
1984e1dd0a2fSth160488  * errorp	Set if there are any INTERNAL, or CONFIG error.
1985e1dd0a2fSth160488  */
1986e1dd0a2fSth160488 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)1987e1dd0a2fSth160488 __s_api_getConnection(
1988e1dd0a2fSth160488 	const char *server,
1989e1dd0a2fSth160488 	const int flags,
1990e1dd0a2fSth160488 	const ns_cred_t *cred,		/* credentials for bind */
1991e1dd0a2fSth160488 	ConnectionID *sessionId,
1992e1dd0a2fSth160488 	Connection **session,
1993e1dd0a2fSth160488 	ns_ldap_error_t **errorp,
1994e1dd0a2fSth160488 	int fail_if_new_pwd_reqd,
1995e1dd0a2fSth160488 	int nopasswd_acct_mgmt,
1996e1dd0a2fSth160488 	ns_conn_user_t *conn_user)
1997e1dd0a2fSth160488 {
1998e1dd0a2fSth160488 	int rc;
1999e1dd0a2fSth160488 
2000e1dd0a2fSth160488 	rc = getConnection(server, flags, cred, sessionId, session,
2001e1dd0a2fSth160488 	    errorp, fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
2002e1dd0a2fSth160488 	    conn_user);
2003e1dd0a2fSth160488 
2004e1dd0a2fSth160488 	if (rc != NS_LDAP_SUCCESS && rc != NS_LDAP_SUCCESS_WITH_INFO) {
2005e1dd0a2fSth160488 		if (conn_user != NULL && conn_user->conn_mt != NULL)
2006e1dd0a2fSth160488 			__s_api_conn_mt_remove(conn_user, rc, errorp);
2007e1dd0a2fSth160488 	}
2008e1dd0a2fSth160488 
2009e1dd0a2fSth160488 	return (rc);
2010e1dd0a2fSth160488 }
2011e1dd0a2fSth160488 
2012e1dd0a2fSth160488 void
__s_api_free_sessionPool()2013e1dd0a2fSth160488 __s_api_free_sessionPool()
20147c478bd9Sstevel@tonic-gate {
20157c478bd9Sstevel@tonic-gate 	int id;
20167c478bd9Sstevel@tonic-gate 
2017e1dd0a2fSth160488 	(void) mutex_lock(&sessionPoolLock);
2018e1dd0a2fSth160488 
20197c478bd9Sstevel@tonic-gate 	if (sessionPool != NULL) {
20207c478bd9Sstevel@tonic-gate 		for (id = 0; id < sessionPoolSize; id++)
20217c478bd9Sstevel@tonic-gate 			_DropConnection(id + CONID_OFFSET, 0, 1);
20227c478bd9Sstevel@tonic-gate 		free(sessionPool);
20237c478bd9Sstevel@tonic-gate 		sessionPool = NULL;
20247c478bd9Sstevel@tonic-gate 		sessionPoolSize = 0;
20257c478bd9Sstevel@tonic-gate 	}
2026e1dd0a2fSth160488 	(void) mutex_unlock(&sessionPoolLock);
2027e1dd0a2fSth160488 }
2028e1dd0a2fSth160488 
2029e1dd0a2fSth160488 /*
2030e1dd0a2fSth160488  * This function initializes a TLS LDAP session. On success LDAP* is returned
2031e1dd0a2fSth160488  * (pointed by *ldp). Otherwise, the function returns an NS error code and
2032e1dd0a2fSth160488  * provide an additional info pointed by *errorp.
2033e1dd0a2fSth160488  */
2034e1dd0a2fSth160488 static
2035e1dd0a2fSth160488 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)2036e1dd0a2fSth160488 createTLSSession(const ns_cred_t *auth, const char *serverAddr,
2037e1dd0a2fSth160488 		    uint16_t port, int timeoutMilliSec,
2038e1dd0a2fSth160488 		    LDAP **ldp, ns_ldap_error_t **errorp)
2039e1dd0a2fSth160488 {
2040e1dd0a2fSth160488 	const char	*hostcertpath;
2041e1dd0a2fSth160488 	char		*alloc_hcp = NULL, errstr[MAXERROR];
2042e1dd0a2fSth160488 	int		ldap_rc;
2043e1dd0a2fSth160488 
2044e1dd0a2fSth160488 #ifdef DEBUG
2045e1dd0a2fSth160488 	(void) fprintf(stderr, "tid= %d: +++TLS transport\n",
2046e1dd0a2fSth160488 	    thr_self());
2047e1dd0a2fSth160488 #endif /* DEBUG */
2048e1dd0a2fSth160488 
2049e1dd0a2fSth160488 	if (prldap_set_session_option(NULL, NULL,
2050e1dd0a2fSth160488 	    PRLDAP_OPT_IO_MAX_TIMEOUT,
2051e1dd0a2fSth160488 	    timeoutMilliSec) != LDAP_SUCCESS) {
2052e1dd0a2fSth160488 		(void) snprintf(errstr, sizeof (errstr),
2053e1dd0a2fSth160488 		    gettext("createTLSSession: failed to initialize "
2054e1dd0a2fSth160488 		    "TLS security"));
2055e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2056e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
2057e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2058e1dd0a2fSth160488 	}
2059e1dd0a2fSth160488 
2060e1dd0a2fSth160488 	hostcertpath = auth->hostcertpath;
2061e1dd0a2fSth160488 	if (hostcertpath == NULL) {
2062e1dd0a2fSth160488 		alloc_hcp = __s_get_hostcertpath();
2063e1dd0a2fSth160488 		hostcertpath = alloc_hcp;
2064e1dd0a2fSth160488 	}
2065e1dd0a2fSth160488 
2066e1dd0a2fSth160488 	if (hostcertpath == NULL)
2067e1dd0a2fSth160488 		return (NS_LDAP_MEMORY);
2068e1dd0a2fSth160488 
2069e1dd0a2fSth160488 	if ((ldap_rc = ldapssl_client_init(hostcertpath, NULL)) < 0) {
2070e1dd0a2fSth160488 		if (alloc_hcp != NULL) {
2071e1dd0a2fSth160488 			free(alloc_hcp);
2072e1dd0a2fSth160488 		}
2073e1dd0a2fSth160488 		(void) snprintf(errstr, sizeof (errstr),
2074e1dd0a2fSth160488 		    gettext("createTLSSession: failed to initialize "
2075e1dd0a2fSth160488 		    "TLS security (%s)"),
2076e1dd0a2fSth160488 		    ldapssl_err2string(ldap_rc));
2077e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2078e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
2079e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2080e1dd0a2fSth160488 	}
2081e1dd0a2fSth160488 	if (alloc_hcp)
2082e1dd0a2fSth160488 		free(alloc_hcp);
2083e1dd0a2fSth160488 
2084e1dd0a2fSth160488 	*ldp = ldapssl_init(serverAddr, port, 1);
2085e1dd0a2fSth160488 
2086e1dd0a2fSth160488 	if (*ldp == NULL ||
2087e1dd0a2fSth160488 	    ldapssl_install_gethostbyaddr(*ldp, "ldap") != 0) {
2088e1dd0a2fSth160488 		(void) snprintf(errstr, sizeof (errstr),
2089e1dd0a2fSth160488 		    gettext("createTLSSession: failed to connect "
2090e1dd0a2fSth160488 		    "using TLS (%s)"), strerror(errno));
2091e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2092e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
2093e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2094e1dd0a2fSth160488 	}
2095e1dd0a2fSth160488 
2096e1dd0a2fSth160488 	return (NS_LDAP_SUCCESS);
2097e1dd0a2fSth160488 }
2098e1dd0a2fSth160488 
2099e1dd0a2fSth160488 /*
2100e1dd0a2fSth160488  * Convert (resolve) hostname to IP address.
2101e1dd0a2fSth160488  *
2102e1dd0a2fSth160488  * INPUT:
2103e1dd0a2fSth160488  *
2104e1dd0a2fSth160488  * 	server	- \[IPv6_address\][:port]
2105e1dd0a2fSth160488  *		- IPv4_address[:port]
2106e1dd0a2fSth160488  *		- hostname[:port]
2107e1dd0a2fSth160488  *
2108e1dd0a2fSth160488  * 	newaddr - Buffer to which this function writes resulting address,
2109e1dd0a2fSth160488  *		including the port number, if specified in server argument.
2110e1dd0a2fSth160488  *
2111e1dd0a2fSth160488  * 	newaddr_size - Size of the newaddr buffer.
2112e1dd0a2fSth160488  *
2113e1dd0a2fSth160488  * 	errstr  - Buffer to which error string is written if error occurs.
2114e1dd0a2fSth160488  *
2115e1dd0a2fSth160488  * 	errstr_size - Size of the errstr buffer.
2116e1dd0a2fSth160488  *
2117e1dd0a2fSth160488  * OUTPUT:
2118e1dd0a2fSth160488  *
2119e1dd0a2fSth160488  * 	Returns 1 for success, 0 in case of error.
2120e1dd0a2fSth160488  *
2121e1dd0a2fSth160488  * 	newaddr - See above (INPUT section).
2122e1dd0a2fSth160488  *
2123e1dd0a2fSth160488  *	errstr	- See above (INPUT section).
2124e1dd0a2fSth160488  */
2125e1dd0a2fSth160488 static int
cvt_hostname2ip(char * server,char * newaddr,int newaddr_size,char * errstr,int errstr_size)2126e1dd0a2fSth160488 cvt_hostname2ip(char *server, char *newaddr, int newaddr_size,
2127e1dd0a2fSth160488     char *errstr, int errstr_size)
2128e1dd0a2fSth160488 {
2129e1dd0a2fSth160488 	char	*s;
2130e1dd0a2fSth160488 	unsigned short port = 0;
2131e1dd0a2fSth160488 	int	err;
2132e1dd0a2fSth160488 	char	buffer[NSS_BUFLEN_HOSTS];
2133e1dd0a2fSth160488 	struct hostent	result;
2134e1dd0a2fSth160488 
2135e1dd0a2fSth160488 	/* Determine if the host name contains a port number. */
2136e1dd0a2fSth160488 
2137e1dd0a2fSth160488 	/* Skip over IPv6 address. */
2138e1dd0a2fSth160488 	s = strchr(server, ']');
2139e1dd0a2fSth160488 	s = strchr(s != NULL ? s : server, ':');
2140e1dd0a2fSth160488 	if (s != NULL) {
2141e1dd0a2fSth160488 		if (sscanf(s + 1, "%hu", &port) != 1) {
2142e1dd0a2fSth160488 			/* Address misformatted. No port number after : */
2143e1dd0a2fSth160488 			(void) snprintf(errstr, errstr_size, "%s",
2144e1dd0a2fSth160488 			    gettext("Invalid host:port format"));
2145e1dd0a2fSth160488 			return (0);
2146e1dd0a2fSth160488 		} else
2147e1dd0a2fSth160488 			/* Cut off the :<port> part. */
2148e1dd0a2fSth160488 			*s = '\0';
2149e1dd0a2fSth160488 	}
2150e1dd0a2fSth160488 
2151e1dd0a2fSth160488 	buffer[0] = '\0';
2152e1dd0a2fSth160488 	/*
2153e1dd0a2fSth160488 	 * Resolve hostname and fill in hostent structure.
2154e1dd0a2fSth160488 	 */
2155e1dd0a2fSth160488 	if (!__s_api_hostname2ip(server, &result, buffer, NSS_BUFLEN_HOSTS,
2156e1dd0a2fSth160488 	    &err)) {
2157e1dd0a2fSth160488 		/*
2158e1dd0a2fSth160488 		 * The only possible error here could be TRY_AGAIN if buffer was
2159e1dd0a2fSth160488 		 * not big enough. NSS_BUFLEN_HOSTS should have been enough
2160e1dd0a2fSth160488 		 * though.
2161e1dd0a2fSth160488 		 */
2162e1dd0a2fSth160488 		(void) snprintf(errstr, errstr_size, "%s",
2163e1dd0a2fSth160488 		    gettext("Unable to resolve address."));
2164e1dd0a2fSth160488 		return (0);
2165e1dd0a2fSth160488 	}
2166e1dd0a2fSth160488 
2167e1dd0a2fSth160488 
2168e1dd0a2fSth160488 	buffer[0] = '\0';
2169e1dd0a2fSth160488 	/*
2170e1dd0a2fSth160488 	 * Convert the address to string.
2171e1dd0a2fSth160488 	 */
2172e1dd0a2fSth160488 	if (!inet_ntop(result.h_addrtype, result.h_addr_list[0], buffer,
2173e1dd0a2fSth160488 	    NSS_BUFLEN_HOSTS)) {
2174e1dd0a2fSth160488 		/* There's not much we can do. */
2175e1dd0a2fSth160488 		(void) snprintf(errstr, errstr_size, "%s",
2176e1dd0a2fSth160488 		    gettext("Unable to convert address to string."));
2177e1dd0a2fSth160488 		return (0);
2178e1dd0a2fSth160488 	}
2179e1dd0a2fSth160488 
2180e1dd0a2fSth160488 	/* Put together the address and the port */
2181e1dd0a2fSth160488 	if (port > 0) {
2182e1dd0a2fSth160488 		switch (result.h_addrtype) {
2183e1dd0a2fSth160488 			case AF_INET6:
2184e1dd0a2fSth160488 				(void) snprintf(newaddr,
2185e1dd0a2fSth160488 				    /* [IP]:<port>\0 */
2186e1dd0a2fSth160488 				    1 + strlen(buffer) + 1 + 1 + 5 + 1,
2187e1dd0a2fSth160488 				    "[%s]:%hu",
2188e1dd0a2fSth160488 				    buffer,
2189e1dd0a2fSth160488 				    port);
2190e1dd0a2fSth160488 				break;
2191e1dd0a2fSth160488 			/* AF_INET */
2192e1dd0a2fSth160488 			default :
2193e1dd0a2fSth160488 				(void) snprintf(newaddr,
2194e1dd0a2fSth160488 				    /* IP:<port>\0 */
2195e1dd0a2fSth160488 				    strlen(buffer) + 1 + 5 + 1,
2196e1dd0a2fSth160488 				    "%s:%hu",
2197e1dd0a2fSth160488 				    buffer,
2198e1dd0a2fSth160488 				    port);
2199e1dd0a2fSth160488 				break;
2200e1dd0a2fSth160488 		}
2201e1dd0a2fSth160488 	} else {
2202e1dd0a2fSth160488 		(void) strncpy(newaddr, buffer, newaddr_size);
2203e1dd0a2fSth160488 	}
2204e1dd0a2fSth160488 
2205e1dd0a2fSth160488 	return (1);
2206e1dd0a2fSth160488 }
2207e1dd0a2fSth160488 
2208e1dd0a2fSth160488 
2209e1dd0a2fSth160488 /*
2210e1dd0a2fSth160488  * This finction initializes a none-TLS LDAP session.  On success LDAP*
2211e1dd0a2fSth160488  * is returned (pointed by *ldp). Otherwise, the function returns
2212e1dd0a2fSth160488  * an NS error code and provides an additional info pointed by *errorp.
2213e1dd0a2fSth160488  */
2214e1dd0a2fSth160488 static
2215e1dd0a2fSth160488 ns_ldap_return_code
createNonTLSSession(const char * serverAddr,uint16_t port,int gssapi,LDAP ** ldp,ns_ldap_error_t ** errorp)2216e1dd0a2fSth160488 createNonTLSSession(const char *serverAddr,
2217e1dd0a2fSth160488 		uint16_t port, int gssapi,
2218e1dd0a2fSth160488 		LDAP **ldp, ns_ldap_error_t **errorp)
2219e1dd0a2fSth160488 {
2220e1dd0a2fSth160488 	char		errstr[MAXERROR];
2221e1dd0a2fSth160488 	char		*addr;
2222e1dd0a2fSth160488 	int		is_ip = 0;
2223e1dd0a2fSth160488 			/* [INET6_ADDRSTRLEN]:<port>\0 */
2224e1dd0a2fSth160488 	char		svraddr[1+INET6_ADDRSTRLEN+1+1+5+1];
2225e1dd0a2fSth160488 #ifdef DEBUG
2226e1dd0a2fSth160488 	(void) fprintf(stderr, "tid= %d: +++Unsecure transport\n",
2227e1dd0a2fSth160488 	    thr_self());
2228e1dd0a2fSth160488 #endif /* DEBUG */
2229e1dd0a2fSth160488 
2230e1dd0a2fSth160488 	if (gssapi == 0) {
2231e1dd0a2fSth160488 		is_ip = (__s_api_isipv4((char *)serverAddr) ||
2232e1dd0a2fSth160488 		    __s_api_isipv6((char *)serverAddr));
2233e1dd0a2fSth160488 	}
2234e1dd0a2fSth160488 
2235e1dd0a2fSth160488 	/*
2236e1dd0a2fSth160488 	 * Let's try to resolve IP address of server.
2237e1dd0a2fSth160488 	 */
2238e1dd0a2fSth160488 	if (is_ip == 0 && !gssapi && (ldap_in_nss_switch((char *)"hosts") > 0 ||
2239e1dd0a2fSth160488 	    ldap_in_nss_switch((char *)"ipnodes") > 0)) {
2240e1dd0a2fSth160488 		addr = strdup(serverAddr);
2241e1dd0a2fSth160488 		if (addr == NULL)
2242e1dd0a2fSth160488 			return (NS_LDAP_MEMORY);
2243e1dd0a2fSth160488 		svraddr[0] = '\0';
2244e1dd0a2fSth160488 		if (cvt_hostname2ip(addr, svraddr, sizeof (svraddr),
2245e1dd0a2fSth160488 		    errstr, MAXERROR) == 1) {
2246e1dd0a2fSth160488 			serverAddr = svraddr;
2247e1dd0a2fSth160488 			free(addr);
2248e1dd0a2fSth160488 		} else {
2249e1dd0a2fSth160488 			free(addr);
2250e1dd0a2fSth160488 			MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2251e1dd0a2fSth160488 			    strdup(errstr), NS_LDAP_MEMORY);
2252e1dd0a2fSth160488 			return (NS_LDAP_INTERNAL);
2253e1dd0a2fSth160488 		}
2254e1dd0a2fSth160488 	}
2255e1dd0a2fSth160488 
2256e1dd0a2fSth160488 	/* Warning message IF cannot connect to host(s) */
2257e1dd0a2fSth160488 	if ((*ldp = ldap_init((char *)serverAddr, port)) == NULL) {
2258e1dd0a2fSth160488 		char *p = strerror(errno);
2259e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2260e1dd0a2fSth160488 		    strdup(p), NS_LDAP_MEMORY);
2261e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2262e1dd0a2fSth160488 	}
2263e1dd0a2fSth160488 
2264e1dd0a2fSth160488 	return (NS_LDAP_SUCCESS);
2265e1dd0a2fSth160488 }
2266e1dd0a2fSth160488 
2267e1dd0a2fSth160488 /*
2268e1dd0a2fSth160488  * This finction initializes an LDAP session.
2269e1dd0a2fSth160488  *
2270e1dd0a2fSth160488  * INPUT:
2271e1dd0a2fSth160488  *     auth - a structure specified an authenticastion method and credentials,
2272e1dd0a2fSth160488  *     serverAddr - the address of a server to which a connection
2273e1dd0a2fSth160488  *                  will be established,
2274e1dd0a2fSth160488  *     port - a port being listened by the server,
2275e1dd0a2fSth160488  *     timeoutMilliSec - a timeout in milliseconds for the Bind operation.
2276e1dd0a2fSth160488  *
2277e1dd0a2fSth160488  * OUTPUT:
2278e1dd0a2fSth160488  *     ldp - a pointer to an LDAP structure which will be used
2279e1dd0a2fSth160488  *           for all the subsequent operations against the server.
2280ca190d8dSmichen  *     If an error occurs, the function returns an NS error code
2281e1dd0a2fSth160488  *     and provides an additional info pointed by *errorp.
2282e1dd0a2fSth160488  */
2283e1dd0a2fSth160488 static
2284e1dd0a2fSth160488 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)2285e1dd0a2fSth160488 createSession(const ns_cred_t *auth, const char *serverAddr,
2286e1dd0a2fSth160488 		    uint16_t port, int timeoutMilliSec,
2287e1dd0a2fSth160488 		    LDAP **ldp, ns_ldap_error_t **errorp)
2288e1dd0a2fSth160488 {
2289e1dd0a2fSth160488 	int	useSSL = 0, gssapi = 0;
2290e1dd0a2fSth160488 	char	errstr[MAXERROR];
2291e1dd0a2fSth160488 
2292e1dd0a2fSth160488 	switch (auth->auth.type) {
2293e1dd0a2fSth160488 		case NS_LDAP_AUTH_NONE:
2294e1dd0a2fSth160488 		case NS_LDAP_AUTH_SIMPLE:
2295e1dd0a2fSth160488 		case NS_LDAP_AUTH_SASL:
2296e1dd0a2fSth160488 			break;
2297e1dd0a2fSth160488 		case NS_LDAP_AUTH_TLS:
2298e1dd0a2fSth160488 			useSSL = 1;
2299e1dd0a2fSth160488 			break;
2300e1dd0a2fSth160488 		default:
2301e1dd0a2fSth160488 			(void) sprintf(errstr,
2302e1dd0a2fSth160488 			    gettext("openConnection: unsupported "
2303e1dd0a2fSth160488 			    "authentication method (%d)"), auth->auth.type);
2304e1dd0a2fSth160488 			MKERROR(LOG_WARNING, *errorp,
2305e1dd0a2fSth160488 			    LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
2306e1dd0a2fSth160488 			    NS_LDAP_MEMORY);
2307e1dd0a2fSth160488 			return (NS_LDAP_INTERNAL);
2308e1dd0a2fSth160488 	}
2309e1dd0a2fSth160488 
2310e1dd0a2fSth160488 	if (port == USE_DEFAULT_PORT) {
2311e1dd0a2fSth160488 		port = useSSL ? LDAPS_PORT : LDAP_PORT;
2312e1dd0a2fSth160488 	}
2313e1dd0a2fSth160488 
2314e1dd0a2fSth160488 	if (auth->auth.type == NS_LDAP_AUTH_SASL &&
2315e1dd0a2fSth160488 	    auth->auth.saslmech == NS_LDAP_SASL_GSSAPI)
2316e1dd0a2fSth160488 		gssapi = 1;
2317e1dd0a2fSth160488 
2318e1dd0a2fSth160488 	if (useSSL)
2319e1dd0a2fSth160488 		return (createTLSSession(auth, serverAddr, port,
2320e1dd0a2fSth160488 		    timeoutMilliSec, ldp, errorp));
2321e1dd0a2fSth160488 	else
2322e1dd0a2fSth160488 		return (createNonTLSSession(serverAddr, port, gssapi,
2323e1dd0a2fSth160488 		    ldp, errorp));
2324e1dd0a2fSth160488 }
2325e1dd0a2fSth160488 
2326e1dd0a2fSth160488 /*
2327e1dd0a2fSth160488  * This finction performs a non-SASL bind operation.  If an error accures,
2328e1dd0a2fSth160488  * the function returns an NS error code and provides an additional info
2329e1dd0a2fSth160488  * pointed by *errorp.
2330e1dd0a2fSth160488  */
2331e1dd0a2fSth160488 static
2332e1dd0a2fSth160488 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)2333e1dd0a2fSth160488 doSimpleBind(const ns_cred_t *auth,
2334e1dd0a2fSth160488 		LDAP *ld,
2335e1dd0a2fSth160488 		int timeoutSec,
2336e1dd0a2fSth160488 		ns_ldap_error_t **errorp,
2337e1dd0a2fSth160488 		int fail_if_new_pwd_reqd,
2338e1dd0a2fSth160488 		int passwd_mgmt)
2339e1dd0a2fSth160488 {
2340e1dd0a2fSth160488 	char			*binddn, *passwd, errstr[MAXERROR], *errmsg;
2341e1dd0a2fSth160488 	int			msgId, errnum = 0, ldap_rc;
2342e1dd0a2fSth160488 	ns_ldap_return_code	ret_code;
2343e1dd0a2fSth160488 	LDAPMessage		*resultMsg = NULL;
2344e1dd0a2fSth160488 	LDAPControl		**controls;
2345e1dd0a2fSth160488 	struct timeval		tv;
2346e1dd0a2fSth160488 
2347e1dd0a2fSth160488 	binddn = auth->cred.unix_cred.userID;
2348e1dd0a2fSth160488 	passwd = auth->cred.unix_cred.passwd;
2349e1dd0a2fSth160488 	if (passwd == NULL || *passwd == '\0' ||
2350e1dd0a2fSth160488 	    binddn == NULL || *binddn == '\0') {
2351e1dd0a2fSth160488 		(void) sprintf(errstr, gettext("openConnection: "
2352e1dd0a2fSth160488 		    "missing credentials for Simple bind"));
2353e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS,
2354e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
2355e1dd0a2fSth160488 		(void) ldap_unbind(ld);
2356e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2357e1dd0a2fSth160488 	}
2358e1dd0a2fSth160488 
2359e1dd0a2fSth160488 #ifdef DEBUG
2360e1dd0a2fSth160488 	(void) fprintf(stderr, "tid= %d: +++Simple bind\n",
2361e1dd0a2fSth160488 	    thr_self());
2362e1dd0a2fSth160488 #endif /* DEBUG */
2363e1dd0a2fSth160488 	msgId = ldap_simple_bind(ld, binddn, passwd);
2364e1dd0a2fSth160488 
2365e1dd0a2fSth160488 	if (msgId == -1) {
2366e1dd0a2fSth160488 		(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
2367e1dd0a2fSth160488 		    (void *)&errnum);
2368e1dd0a2fSth160488 		(void) snprintf(errstr, sizeof (errstr),
2369e1dd0a2fSth160488 		    gettext("openConnection: simple bind failed "
2370e1dd0a2fSth160488 		    "- %s"), ldap_err2string(errnum));
2371e1dd0a2fSth160488 		(void) ldap_unbind(ld);
2372e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
2373e1dd0a2fSth160488 		    NS_LDAP_MEMORY);
2374e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2375e1dd0a2fSth160488 	}
2376e1dd0a2fSth160488 
2377e1dd0a2fSth160488 	tv.tv_sec = timeoutSec;
2378e1dd0a2fSth160488 	tv.tv_usec = 0;
2379e1dd0a2fSth160488 	ldap_rc = ldap_result(ld, msgId, 0, &tv, &resultMsg);
2380e1dd0a2fSth160488 
2381e1dd0a2fSth160488 	if ((ldap_rc == -1) || (ldap_rc == 0)) {
2382e1dd0a2fSth160488 		(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
2383e1dd0a2fSth160488 		    (void *)&errnum);
2384e1dd0a2fSth160488 		(void) snprintf(errstr, sizeof (errstr),
2385e1dd0a2fSth160488 		    gettext("openConnection: simple bind failed "
2386e1dd0a2fSth160488 		    "- %s"), ldap_err2string(errnum));
2387e1dd0a2fSth160488 		(void) ldap_msgfree(resultMsg);
2388e1dd0a2fSth160488 		(void) ldap_unbind(ld);
2389e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
2390e1dd0a2fSth160488 		    NS_LDAP_MEMORY);
2391e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2392e1dd0a2fSth160488 	}
2393e1dd0a2fSth160488 
2394e1dd0a2fSth160488 	/*
2395e1dd0a2fSth160488 	 * get ldaprc, controls, and error msg
2396e1dd0a2fSth160488 	 */
2397e1dd0a2fSth160488 	ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
2398e1dd0a2fSth160488 	    &errmsg, NULL, &controls, 1);
2399e1dd0a2fSth160488 
2400e1dd0a2fSth160488 	if (ldap_rc != LDAP_SUCCESS) {
2401e1dd0a2fSth160488 		(void) snprintf(errstr, sizeof (errstr),
2402e1dd0a2fSth160488 		    gettext("openConnection: simple bind failed "
2403e1dd0a2fSth160488 		    "- unable to parse result"));
2404e1dd0a2fSth160488 		(void) ldap_unbind(ld);
2405e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2406e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
2407e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2408e1dd0a2fSth160488 	}
2409e1dd0a2fSth160488 
2410e1dd0a2fSth160488 	/* process the password management info, if any */
2411e1dd0a2fSth160488 	ret_code = process_pwd_mgmt("simple",
2412e1dd0a2fSth160488 	    errnum, controls, errmsg,
2413e1dd0a2fSth160488 	    errorp,
2414e1dd0a2fSth160488 	    fail_if_new_pwd_reqd,
2415e1dd0a2fSth160488 	    passwd_mgmt);
2416e1dd0a2fSth160488 
2417e1dd0a2fSth160488 	if (ret_code == NS_LDAP_INTERNAL) {
2418e1dd0a2fSth160488 		(void) ldap_unbind(ld);
2419e1dd0a2fSth160488 	}
2420e1dd0a2fSth160488 
2421e1dd0a2fSth160488 	return (ret_code);
2422e1dd0a2fSth160488 }
2423e1dd0a2fSth160488 
2424e1dd0a2fSth160488 /*
2425e1dd0a2fSth160488  * This finction performs a SASL bind operation.  If an error accures,
2426e1dd0a2fSth160488  * the function returns an NS error code and provides an additional info
2427e1dd0a2fSth160488  * pointed by *errorp.
2428e1dd0a2fSth160488  */
2429e1dd0a2fSth160488 static
2430e1dd0a2fSth160488 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)2431e1dd0a2fSth160488 doSASLBind(const ns_cred_t *auth,
2432e1dd0a2fSth160488 		LDAP *ld,
2433e1dd0a2fSth160488 		int timeoutSec,
2434e1dd0a2fSth160488 		ns_ldap_error_t **errorp,
2435e1dd0a2fSth160488 		int fail_if_new_pwd_reqd,
2436e1dd0a2fSth160488 		int passwd_mgmt)
2437e1dd0a2fSth160488 {
2438e1dd0a2fSth160488 	char			*binddn, *passwd, *digest_md5_name,
2439e1dd0a2fSth160488 	    errstr[MAXERROR], *errmsg;
2440e1dd0a2fSth160488 	struct berval		cred;
2441e1dd0a2fSth160488 	int			ldap_rc, errnum = 0;
2442e1dd0a2fSth160488 	ns_ldap_return_code	ret_code;
2443e1dd0a2fSth160488 	struct timeval		tv;
2444e1dd0a2fSth160488 	LDAPMessage		*resultMsg;
2445e1dd0a2fSth160488 	LDAPControl		**controls;
2446e1dd0a2fSth160488 	int			min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF;
2447e1dd0a2fSth160488 	ns_sasl_cb_param_t	sasl_param;
2448e1dd0a2fSth160488 
2449e1dd0a2fSth160488 	if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE &&
2450e1dd0a2fSth160488 	    auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
2451e1dd0a2fSth160488 		(void) sprintf(errstr,
2452e1dd0a2fSth160488 		    gettext("openConnection: SASL options are "
2453e1dd0a2fSth160488 		    "not supported (%d) for non-GSSAPI sasl bind"),
2454e1dd0a2fSth160488 		    auth->auth.saslopt);
2455e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp,
2456e1dd0a2fSth160488 		    LDAP_AUTH_METHOD_NOT_SUPPORTED,
2457e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
2458e1dd0a2fSth160488 		(void) ldap_unbind(ld);
2459e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2460e1dd0a2fSth160488 	}
2461e1dd0a2fSth160488 	if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
2462e1dd0a2fSth160488 		binddn = auth->cred.unix_cred.userID;
2463e1dd0a2fSth160488 		passwd = auth->cred.unix_cred.passwd;
2464e1dd0a2fSth160488 		if (passwd == NULL || *passwd == '\0' ||
2465e1dd0a2fSth160488 		    binddn == NULL || *binddn == '\0') {
2466e1dd0a2fSth160488 			(void) sprintf(errstr,
2467e1dd0a2fSth160488 			gettext("openConnection: missing credentials "
2468e1dd0a2fSth160488 			    "for SASL bind"));
2469e1dd0a2fSth160488 			MKERROR(LOG_WARNING, *errorp,
2470e1dd0a2fSth160488 			    LDAP_INVALID_CREDENTIALS,
2471e1dd0a2fSth160488 			    strdup(errstr), NS_LDAP_MEMORY);
2472e1dd0a2fSth160488 			(void) ldap_unbind(ld);
2473e1dd0a2fSth160488 			return (NS_LDAP_INTERNAL);
2474e1dd0a2fSth160488 		}
2475e1dd0a2fSth160488 		cred.bv_val = passwd;
2476e1dd0a2fSth160488 		cred.bv_len = strlen(passwd);
2477e1dd0a2fSth160488 	}
2478e1dd0a2fSth160488 
2479e1dd0a2fSth160488 	ret_code = NS_LDAP_SUCCESS;
2480e1dd0a2fSth160488 
2481e1dd0a2fSth160488 	switch (auth->auth.saslmech) {
2482e1dd0a2fSth160488 	case NS_LDAP_SASL_CRAM_MD5:
2483e1dd0a2fSth160488 		/*
2484e1dd0a2fSth160488 		 * NOTE: if iDS changes to support cram_md5,
2485e1dd0a2fSth160488 		 * please add password management code here.
2486e1dd0a2fSth160488 		 * Since ldap_sasl_cram_md5_bind_s does not
2487e1dd0a2fSth160488 		 * return anything that could be used to
2488e1dd0a2fSth160488 		 * extract the ldap rc/errmsg/control to
2489e1dd0a2fSth160488 		 * determine if bind failed due to password
2490e1dd0a2fSth160488 		 * policy, a new cram_md5_bind API will need
2491e1dd0a2fSth160488 		 * to be introduced. See
2492e1dd0a2fSth160488 		 * ldap_x_sasl_digest_md5_bind() and case
2493e1dd0a2fSth160488 		 * NS_LDAP_SASL_DIGEST_MD5 below for details.
2494e1dd0a2fSth160488 		 */
2495e1dd0a2fSth160488 		if ((ldap_rc = ldap_sasl_cram_md5_bind_s(ld, binddn,
2496e1dd0a2fSth160488 		    &cred, NULL, NULL)) != LDAP_SUCCESS) {
2497e1dd0a2fSth160488 			(void) ldap_get_option(ld,
2498e1dd0a2fSth160488 			    LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
2499e1dd0a2fSth160488 			(void) snprintf(errstr, sizeof (errstr),
2500e1dd0a2fSth160488 			    gettext("openConnection: "
2501e1dd0a2fSth160488 			    "sasl/CRAM-MD5 bind failed - %s"),
2502e1dd0a2fSth160488 			    ldap_err2string(errnum));
2503e1dd0a2fSth160488 			MKERROR(LOG_WARNING, *errorp, errnum,
2504e1dd0a2fSth160488 			    strdup(errstr), NS_LDAP_MEMORY);
2505e1dd0a2fSth160488 			(void) ldap_unbind(ld);
2506e1dd0a2fSth160488 			return (NS_LDAP_INTERNAL);
2507e1dd0a2fSth160488 		}
2508e1dd0a2fSth160488 		break;
2509e1dd0a2fSth160488 	case NS_LDAP_SASL_DIGEST_MD5:
2510e1dd0a2fSth160488 		digest_md5_name = malloc(strlen(binddn) + 5);
2511e1dd0a2fSth160488 		/* 5 = strlen("dn: ") + 1 */
2512e1dd0a2fSth160488 		if (digest_md5_name == NULL) {
2513e1dd0a2fSth160488 			(void) ldap_unbind(ld);
2514e1dd0a2fSth160488 			return (NS_LDAP_MEMORY);
2515e1dd0a2fSth160488 		}
2516e1dd0a2fSth160488 		(void) strcpy(digest_md5_name, "dn: ");
2517e1dd0a2fSth160488 		(void) strcat(digest_md5_name, binddn);
2518e1dd0a2fSth160488 
2519e1dd0a2fSth160488 		tv.tv_sec = timeoutSec;
2520e1dd0a2fSth160488 		tv.tv_usec = 0;
2521e1dd0a2fSth160488 		ldap_rc = ldap_x_sasl_digest_md5_bind(ld,
2522e1dd0a2fSth160488 		    digest_md5_name, &cred, NULL, NULL,
2523e1dd0a2fSth160488 		    &tv, &resultMsg);
2524e1dd0a2fSth160488 
2525e1dd0a2fSth160488 		if (resultMsg == NULL) {
2526e1dd0a2fSth160488 			free(digest_md5_name);
2527e1dd0a2fSth160488 			(void) ldap_get_option(ld,
2528e1dd0a2fSth160488 			    LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
2529e1dd0a2fSth160488 			(void) snprintf(errstr, sizeof (errstr),
2530e1dd0a2fSth160488 			    gettext("openConnection: "
2531e1dd0a2fSth160488 			    "DIGEST-MD5 bind failed - %s"),
2532e1dd0a2fSth160488 			    ldap_err2string(errnum));
2533e1dd0a2fSth160488 			(void) ldap_unbind(ld);
2534e1dd0a2fSth160488 			MKERROR(LOG_WARNING, *errorp, errnum,
2535e1dd0a2fSth160488 			    strdup(errstr), NS_LDAP_MEMORY);
2536e1dd0a2fSth160488 			return (NS_LDAP_INTERNAL);
2537e1dd0a2fSth160488 		}
2538e1dd0a2fSth160488 
2539e1dd0a2fSth160488 		/*
2540e1dd0a2fSth160488 		 * get ldaprc, controls, and error msg
2541e1dd0a2fSth160488 		 */
2542e1dd0a2fSth160488 		ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
2543e1dd0a2fSth160488 		    &errmsg, NULL, &controls, 1);
2544e1dd0a2fSth160488 
2545e1dd0a2fSth160488 		if (ldap_rc != LDAP_SUCCESS) {
2546e1dd0a2fSth160488 			free(digest_md5_name);
2547e1dd0a2fSth160488 			(void) snprintf(errstr, sizeof (errstr),
2548e1dd0a2fSth160488 			    gettext("openConnection: "
2549e1dd0a2fSth160488 			    "DIGEST-MD5 bind failed "
2550e1dd0a2fSth160488 			    "- unable to parse result"));
2551e1dd0a2fSth160488 			(void) ldap_unbind(ld);
2552e1dd0a2fSth160488 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2553e1dd0a2fSth160488 			    strdup(errstr), NS_LDAP_MEMORY);
2554e1dd0a2fSth160488 			return (NS_LDAP_INTERNAL);
2555e1dd0a2fSth160488 		}
2556e1dd0a2fSth160488 
2557e1dd0a2fSth160488 		/* process the password management info, if any */
2558e1dd0a2fSth160488 		ret_code = process_pwd_mgmt("sasl/DIGEST-MD5",
2559e1dd0a2fSth160488 		    errnum, controls, errmsg,
2560e1dd0a2fSth160488 		    errorp,
2561e1dd0a2fSth160488 		    fail_if_new_pwd_reqd,
2562e1dd0a2fSth160488 		    passwd_mgmt);
2563e1dd0a2fSth160488 
2564e1dd0a2fSth160488 		if (ret_code == NS_LDAP_INTERNAL) {
2565e1dd0a2fSth160488 			(void) ldap_unbind(ld);
2566e1dd0a2fSth160488 		}
2567e1dd0a2fSth160488 
2568e1dd0a2fSth160488 		free(digest_md5_name);
2569e1dd0a2fSth160488 		break;
2570e1dd0a2fSth160488 	case NS_LDAP_SASL_GSSAPI:
2571e1dd0a2fSth160488 		(void) memset(&sasl_param, 0,
2572e1dd0a2fSth160488 		    sizeof (ns_sasl_cb_param_t));
2573e1dd0a2fSth160488 		sasl_param.authid = NULL;
2574e1dd0a2fSth160488 		sasl_param.authzid = "";
2575e1dd0a2fSth160488 		(void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN,
2576e1dd0a2fSth160488 		    (void *)&min_ssf);
2577e1dd0a2fSth160488 		(void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX,
2578e1dd0a2fSth160488 		    (void *)&max_ssf);
2579e1dd0a2fSth160488 
2580e1dd0a2fSth160488 		ldap_rc = ldap_sasl_interactive_bind_s(
2581e1dd0a2fSth160488 		    ld, NULL, "GSSAPI",
2582e1dd0a2fSth160488 		    NULL, NULL, LDAP_SASL_INTERACTIVE,
2583e1dd0a2fSth160488 		    __s_api_sasl_bind_callback,
2584e1dd0a2fSth160488 		    &sasl_param);
2585e1dd0a2fSth160488 
2586e1dd0a2fSth160488 		if (ldap_rc != LDAP_SUCCESS) {
2587e1dd0a2fSth160488 			(void) snprintf(errstr, sizeof (errstr),
2588e1dd0a2fSth160488 			    gettext("openConnection: "
2589e1dd0a2fSth160488 			    "GSSAPI bind failed "
2590e1dd0a2fSth160488 			    "- %d %s"),
2591e1dd0a2fSth160488 			    ldap_rc,
2592e1dd0a2fSth160488 			    ldap_err2string(ldap_rc));
2593e1dd0a2fSth160488 			(void) ldap_unbind(ld);
2594e1dd0a2fSth160488 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2595e1dd0a2fSth160488 			    strdup(errstr), NS_LDAP_MEMORY);
2596e1dd0a2fSth160488 			return (NS_LDAP_INTERNAL);
2597e1dd0a2fSth160488 		}
2598e1dd0a2fSth160488 
2599e1dd0a2fSth160488 		break;
2600e1dd0a2fSth160488 	default:
2601e1dd0a2fSth160488 		(void) ldap_unbind(ld);
2602e1dd0a2fSth160488 		(void) sprintf(errstr,
2603e1dd0a2fSth160488 		    gettext("openConnection: unsupported SASL "
2604e1dd0a2fSth160488 		    "mechanism (%d)"), auth->auth.saslmech);
2605e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp,
2606e1dd0a2fSth160488 		    LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
2607e1dd0a2fSth160488 		    NS_LDAP_MEMORY);
2608e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2609e1dd0a2fSth160488 	}
2610e1dd0a2fSth160488 
2611e1dd0a2fSth160488 	return (ret_code);
2612e1dd0a2fSth160488 }
2613e1dd0a2fSth160488 
2614e1dd0a2fSth160488 /*
2615e1dd0a2fSth160488  * This function performs an LDAP Bind operation proceeding
2616e1dd0a2fSth160488  * from a type of the connection specified by auth->auth.type.
2617e1dd0a2fSth160488  *
2618e1dd0a2fSth160488  * INPUT:
2619e1dd0a2fSth160488  *     auth - a structure specified an authenticastion method and credentials,
2620e1dd0a2fSth160488  *     ld - a pointer returned by the createSession() function,
2621e1dd0a2fSth160488  *     timeoutSec - a timeout in seconds for the Bind operation,
2622e1dd0a2fSth160488  *     fail_if_new_pwd_reqd - a flag indicating that the call should fail
2623e1dd0a2fSth160488  *                            if a new password is required,
2624e1dd0a2fSth160488  *     passwd_mgmt - a flag indicating that the server supports
2625e1dd0a2fSth160488  *                   password management.
2626e1dd0a2fSth160488  *
2627e1dd0a2fSth160488  * OUTPUT:
2628e1dd0a2fSth160488  *     If an error accures, the function returns an NS error code
2629e1dd0a2fSth160488  *     and provides an additional info pointed by *errorp.
2630e1dd0a2fSth160488  */
2631e1dd0a2fSth160488 static
2632e1dd0a2fSth160488 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)2633e1dd0a2fSth160488 performBind(const ns_cred_t *auth,
2634e1dd0a2fSth160488 		LDAP *ld,
2635e1dd0a2fSth160488 		int timeoutSec,
2636e1dd0a2fSth160488 		ns_ldap_error_t **errorp,
2637e1dd0a2fSth160488 		int fail_if_new_pwd_reqd,
2638e1dd0a2fSth160488 		int passwd_mgmt)
2639e1dd0a2fSth160488 {
2640e1dd0a2fSth160488 	int	bindType;
2641e1dd0a2fSth160488 	char	errstr[MAXERROR];
2642e1dd0a2fSth160488 
2643e1dd0a2fSth160488 	ns_ldap_return_code (*binder)(const ns_cred_t *auth,
2644e1dd0a2fSth160488 	    LDAP *ld,
2645e1dd0a2fSth160488 	    int timeoutSec,
2646e1dd0a2fSth160488 	    ns_ldap_error_t **errorp,
2647e1dd0a2fSth160488 	    int fail_if_new_pwd_reqd,
2648e1dd0a2fSth160488 	    int passwd_mgmt) = NULL;
2649e1dd0a2fSth160488 
2650e1dd0a2fSth160488 	if (!ld) {
2651e1dd0a2fSth160488 		(void) sprintf(errstr,
2652e1dd0a2fSth160488 		    "performBind: LDAP session "
2653e1dd0a2fSth160488 		    "is not initialized.");
2654e1dd0a2fSth160488 		MKERROR(LOG_WARNING, *errorp,
2655e1dd0a2fSth160488 		    LDAP_AUTH_METHOD_NOT_SUPPORTED,
2656e1dd0a2fSth160488 		    strdup(errstr), NS_LDAP_MEMORY);
2657e1dd0a2fSth160488 		return (NS_LDAP_INTERNAL);
2658e1dd0a2fSth160488 	}
2659e1dd0a2fSth160488 
2660e1dd0a2fSth160488 	bindType = auth->auth.type == NS_LDAP_AUTH_TLS ?
2661e1dd0a2fSth160488 	    auth->auth.tlstype : auth->auth.type;
2662e1dd0a2fSth160488 
2663e1dd0a2fSth160488 	switch (bindType) {
2664e1dd0a2fSth160488 		case NS_LDAP_AUTH_NONE:
2665e1dd0a2fSth160488 #ifdef DEBUG
2666e1dd0a2fSth160488 		(void) fprintf(stderr, "tid= %d: +++Anonymous bind\n",
2667e1dd0a2fSth160488 		    thr_self());
2668e1dd0a2fSth160488 #endif /* DEBUG */
2669e1dd0a2fSth160488 			break;
2670e1dd0a2fSth160488 		case NS_LDAP_AUTH_SIMPLE:
2671e1dd0a2fSth160488 			binder = doSimpleBind;
2672e1dd0a2fSth160488 			break;
2673e1dd0a2fSth160488 		case NS_LDAP_AUTH_SASL:
2674e1dd0a2fSth160488 			binder = doSASLBind;
2675e1dd0a2fSth160488 			break;
2676e1dd0a2fSth160488 		default:
2677e1dd0a2fSth160488 			(void) sprintf(errstr,
2678e1dd0a2fSth160488 			    gettext("openConnection: unsupported "
2679e1dd0a2fSth160488 			    "authentication method "
2680e1dd0a2fSth160488 			    "(%d)"), bindType);
2681e1dd0a2fSth160488 			MKERROR(LOG_WARNING, *errorp,
2682e1dd0a2fSth160488 			    LDAP_AUTH_METHOD_NOT_SUPPORTED,
2683e1dd0a2fSth160488 			    strdup(errstr), NS_LDAP_MEMORY);
2684e1dd0a2fSth160488 			(void) ldap_unbind(ld);
2685e1dd0a2fSth160488 			return (NS_LDAP_INTERNAL);
2686e1dd0a2fSth160488 	}
2687e1dd0a2fSth160488 
2688e1dd0a2fSth160488 	if (binder != NULL) {
2689e1dd0a2fSth160488 		return (*binder)(auth,
2690e1dd0a2fSth160488 		    ld,
2691e1dd0a2fSth160488 		    timeoutSec,
2692e1dd0a2fSth160488 		    errorp,
2693e1dd0a2fSth160488 		    fail_if_new_pwd_reqd,
2694e1dd0a2fSth160488 		    passwd_mgmt);
2695e1dd0a2fSth160488 	}
2696e1dd0a2fSth160488 
2697e1dd0a2fSth160488 	return (NS_LDAP_SUCCESS);
26987c478bd9Sstevel@tonic-gate }
2699