1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdlib.h>
30*0Sstevel@tonic-gate #include <stdio.h>
31*0Sstevel@tonic-gate #include <errno.h>
32*0Sstevel@tonic-gate #include <string.h>
33*0Sstevel@tonic-gate #include <synch.h>
34*0Sstevel@tonic-gate #include <time.h>
35*0Sstevel@tonic-gate #include <libintl.h>
36*0Sstevel@tonic-gate #include <thread.h>
37*0Sstevel@tonic-gate #include <syslog.h>
38*0Sstevel@tonic-gate #include <sys/mman.h>
39*0Sstevel@tonic-gate #include <nsswitch.h>
40*0Sstevel@tonic-gate #include <nss_dbdefs.h>
41*0Sstevel@tonic-gate #include "solaris-priv.h"
42*0Sstevel@tonic-gate #include "ns_sldap.h"
43*0Sstevel@tonic-gate #include "ns_internal.h"
44*0Sstevel@tonic-gate #include "ns_cache_door.h"
45*0Sstevel@tonic-gate #include <sys/stat.h>
46*0Sstevel@tonic-gate #include <fcntl.h>
47*0Sstevel@tonic-gate #include <procfs.h>
48*0Sstevel@tonic-gate #include <unistd.h>
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate extern unsigned int _sleep(unsigned int);
51*0Sstevel@tonic-gate extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *,
52*0Sstevel@tonic-gate 		LDAPControl **, LDAPControl **);
53*0Sstevel@tonic-gate extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip);
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate static int openConnection(LDAP **, const char *, const ns_cred_t *,
56*0Sstevel@tonic-gate 		int, ns_ldap_error_t **, int, int);
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate static mutex_t	sessionPoolLock = DEFAULTMUTEX;
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate static Connection **sessionPool = NULL;
61*0Sstevel@tonic-gate static int sessionPoolSize = 0;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate static mutex_t	nscdLock = DEFAULTMUTEX;
65*0Sstevel@tonic-gate static int	nscdChecked = 0;
66*0Sstevel@tonic-gate static pid_t	checkedPid = -1;
67*0Sstevel@tonic-gate static int	isNscd = 0;
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate /*
71*0Sstevel@tonic-gate  * Check /proc/PID/psinfo to see if this process is nscd
72*0Sstevel@tonic-gate  * If it is, treat connection as NS_LDAP_KEEP_CONN, to reduce
73*0Sstevel@tonic-gate  * constant reconnects for many operations.
74*0Sstevel@tonic-gate  * A more complete solution is to develop true connection pooling.
75*0Sstevel@tonic-gate  * However, this is much better than a new connection for every request.
76*0Sstevel@tonic-gate  */
77*0Sstevel@tonic-gate static int
78*0Sstevel@tonic-gate nscd_proc()
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	pid_t		my_pid;
81*0Sstevel@tonic-gate 	psinfo_t	pinfo;
82*0Sstevel@tonic-gate 	char		fname[BUFSIZ];
83*0Sstevel@tonic-gate 	int		ret;
84*0Sstevel@tonic-gate 	int		fd;
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	/* Don't bother checking if this process isn't root. */
87*0Sstevel@tonic-gate 	/* It can't be nscd */
88*0Sstevel@tonic-gate 	if (getuid() != 0)
89*0Sstevel@tonic-gate 		return (0);
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	my_pid = getpid();
92*0Sstevel@tonic-gate 	if (nscdChecked && (my_pid == checkedPid)) {
93*0Sstevel@tonic-gate 		return (isNscd);
94*0Sstevel@tonic-gate 	}
95*0Sstevel@tonic-gate 	(void) mutex_lock(&nscdLock);
96*0Sstevel@tonic-gate 	if (nscdChecked && (my_pid == checkedPid)) {
97*0Sstevel@tonic-gate 		(void) mutex_unlock(&nscdLock);
98*0Sstevel@tonic-gate 		return (isNscd);
99*0Sstevel@tonic-gate 	}
100*0Sstevel@tonic-gate 	nscdChecked = 1;
101*0Sstevel@tonic-gate 	checkedPid = my_pid;
102*0Sstevel@tonic-gate 	isNscd = 0;
103*0Sstevel@tonic-gate 	if (snprintf(fname, BUFSIZ, "/proc/%d/psinfo", my_pid) != 0) {
104*0Sstevel@tonic-gate 		if ((fd = open(fname,  O_RDONLY)) > 0) {
105*0Sstevel@tonic-gate 			ret = read(fd, &pinfo, sizeof (psinfo_t));
106*0Sstevel@tonic-gate 			(void) close(fd);
107*0Sstevel@tonic-gate 			if (ret == sizeof (psinfo_t) &&
108*0Sstevel@tonic-gate 			    (strcmp(pinfo.pr_fname, "nscd") == 0)) {
109*0Sstevel@tonic-gate 				/* process runs as root and is named nscd */
110*0Sstevel@tonic-gate 				/* that's good enough for now */
111*0Sstevel@tonic-gate 				isNscd = 1;
112*0Sstevel@tonic-gate 			}
113*0Sstevel@tonic-gate 		}
114*0Sstevel@tonic-gate 	}
115*0Sstevel@tonic-gate 	(void) mutex_unlock(&nscdLock);
116*0Sstevel@tonic-gate 	return (isNscd);
117*0Sstevel@tonic-gate }
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /*
120*0Sstevel@tonic-gate  * This function requests a server from the cache manager through
121*0Sstevel@tonic-gate  * the door functionality
122*0Sstevel@tonic-gate  */
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate static int
125*0Sstevel@tonic-gate __s_api_requestServer(const char *request, const char *server,
126*0Sstevel@tonic-gate 	ns_server_info_t *ret, ns_ldap_error_t **error)
127*0Sstevel@tonic-gate {
128*0Sstevel@tonic-gate 	union {
129*0Sstevel@tonic-gate 		ldap_data_t	s_d;
130*0Sstevel@tonic-gate 		char		s_b[DOORBUFFERSIZE];
131*0Sstevel@tonic-gate 	} space;
132*0Sstevel@tonic-gate 	ldap_data_t	*sptr;
133*0Sstevel@tonic-gate 	int		ndata;
134*0Sstevel@tonic-gate 	int		adata;
135*0Sstevel@tonic-gate 	char		errstr[MAXERROR];
136*0Sstevel@tonic-gate 	const char	*ireq;
137*0Sstevel@tonic-gate 	char		*rbuf, *ptr, *rest;
138*0Sstevel@tonic-gate 	char		*dptr;
139*0Sstevel@tonic-gate 	char		**mptr, **mptr1, **cptr, **cptr1;
140*0Sstevel@tonic-gate 	int		mcnt, ccnt;
141*0Sstevel@tonic-gate 	char		**servers;
142*0Sstevel@tonic-gate 	int		rc;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	if (ret == NULL || error == NULL) {
145*0Sstevel@tonic-gate 		return (NS_LDAP_OP_FAILED);
146*0Sstevel@tonic-gate 	}
147*0Sstevel@tonic-gate 	(void) memset(ret, 0, sizeof (ns_server_info_t));
148*0Sstevel@tonic-gate 	*error = NULL;
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	if (request == NULL)
153*0Sstevel@tonic-gate 		ireq = NS_CACHE_NEW;
154*0Sstevel@tonic-gate 	else
155*0Sstevel@tonic-gate 		ireq = request;
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	adata = (sizeof (ldap_call_t) + strlen(ireq) +1);
158*0Sstevel@tonic-gate 	if (server != NULL) {
159*0Sstevel@tonic-gate 		adata += strlen(DOORLINESEP) + 1;
160*0Sstevel@tonic-gate 		adata += strlen(server) + 1;
161*0Sstevel@tonic-gate 	}
162*0Sstevel@tonic-gate 	ndata = sizeof (space);
163*0Sstevel@tonic-gate 	space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
164*0Sstevel@tonic-gate 	(void) strcpy(space.s_d.ldap_call.ldap_u.domainname, ireq);
165*0Sstevel@tonic-gate 	if (server != NULL) {
166*0Sstevel@tonic-gate 		(void) strcat(space.s_d.ldap_call.ldap_u.domainname,
167*0Sstevel@tonic-gate 			DOORLINESEP);
168*0Sstevel@tonic-gate 		(void) strcat(space.s_d.ldap_call.ldap_u.domainname, server);
169*0Sstevel@tonic-gate 	}
170*0Sstevel@tonic-gate 	sptr = &space.s_d;
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
173*0Sstevel@tonic-gate 	case SUCCESS:
174*0Sstevel@tonic-gate 		break;
175*0Sstevel@tonic-gate 	/* this case is for when the $mgr is not running, but ldapclient */
176*0Sstevel@tonic-gate 	/* is trying to initialize things */
177*0Sstevel@tonic-gate 	case NOSERVER:
178*0Sstevel@tonic-gate 		/* get first server from config list unavailable otherwise */
179*0Sstevel@tonic-gate 		servers = NULL;
180*0Sstevel@tonic-gate 		rc = __s_api_getServers(&servers, error);
181*0Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
182*0Sstevel@tonic-gate 			if (servers != NULL) {
183*0Sstevel@tonic-gate 				__s_api_free2dArray(servers);
184*0Sstevel@tonic-gate 				servers = NULL;
185*0Sstevel@tonic-gate 			}
186*0Sstevel@tonic-gate 			return (rc);
187*0Sstevel@tonic-gate 		}
188*0Sstevel@tonic-gate 		if (servers == NULL || servers[0] == NULL) {
189*0Sstevel@tonic-gate 			__s_api_free2dArray(servers);
190*0Sstevel@tonic-gate 			servers = NULL;
191*0Sstevel@tonic-gate 			(void) sprintf(errstr,
192*0Sstevel@tonic-gate 				gettext("No server found in configuration"));
193*0Sstevel@tonic-gate 			MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT,
194*0Sstevel@tonic-gate 				strdup(errstr), NULL);
195*0Sstevel@tonic-gate 			return (NS_LDAP_CONFIG);
196*0Sstevel@tonic-gate 		}
197*0Sstevel@tonic-gate 		ret->server = strdup(servers[0]);
198*0Sstevel@tonic-gate 		if (ret->server == NULL) {
199*0Sstevel@tonic-gate 			__s_api_free2dArray(servers);
200*0Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
201*0Sstevel@tonic-gate 		}
202*0Sstevel@tonic-gate 		ret->saslMechanisms = NULL;
203*0Sstevel@tonic-gate 		ret->controls = NULL;
204*0Sstevel@tonic-gate 		__s_api_free2dArray(servers);
205*0Sstevel@tonic-gate 		servers = NULL;
206*0Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
207*0Sstevel@tonic-gate 	case NOTFOUND:
208*0Sstevel@tonic-gate 	default:
209*0Sstevel@tonic-gate 		return (NS_LDAP_OP_FAILED);
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	/* copy info from door call return structure here */
213*0Sstevel@tonic-gate 	rbuf =  space.s_d.ldap_ret.ldap_u.config;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	/* Get the host */
216*0Sstevel@tonic-gate 	ptr = strtok_r(rbuf, DOORLINESEP, &rest);
217*0Sstevel@tonic-gate 	if (ptr == NULL) {
218*0Sstevel@tonic-gate 		(void) sprintf(errstr, gettext("No server returned from "
219*0Sstevel@tonic-gate 			"ldap_cachemgr"));
220*0Sstevel@tonic-gate 		MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
221*0Sstevel@tonic-gate 			strdup(errstr), NULL);
222*0Sstevel@tonic-gate 		return (NS_LDAP_OP_FAILED);
223*0Sstevel@tonic-gate 	}
224*0Sstevel@tonic-gate 	ret->server = strdup(ptr);
225*0Sstevel@tonic-gate 	if (ret->server == NULL) {
226*0Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	/* get the Supported Controls/SASL mechs */
230*0Sstevel@tonic-gate 	mptr = NULL;
231*0Sstevel@tonic-gate 	mcnt = 0;
232*0Sstevel@tonic-gate 	cptr = NULL;
233*0Sstevel@tonic-gate 	ccnt = 0;
234*0Sstevel@tonic-gate 	for (; ; ) {
235*0Sstevel@tonic-gate 		ptr = strtok_r(NULL, DOORLINESEP, &rest);
236*0Sstevel@tonic-gate 		if (ptr == NULL)
237*0Sstevel@tonic-gate 			break;
238*0Sstevel@tonic-gate 		if (strncasecmp(ptr, _SASLMECHANISM,
239*0Sstevel@tonic-gate 				_SASLMECHANISM_LEN) == 0) {
240*0Sstevel@tonic-gate 			dptr = strchr(ptr, '=');
241*0Sstevel@tonic-gate 			if (dptr == NULL)
242*0Sstevel@tonic-gate 				continue;
243*0Sstevel@tonic-gate 			dptr++;
244*0Sstevel@tonic-gate 			mptr1 = (char **)realloc((void *)mptr,
245*0Sstevel@tonic-gate 					sizeof (char *) * (mcnt+2));
246*0Sstevel@tonic-gate 			if (mptr1 == NULL) {
247*0Sstevel@tonic-gate 				__s_api_free2dArray(mptr);
248*0Sstevel@tonic-gate 				if (sptr != &space.s_d) {
249*0Sstevel@tonic-gate 				    (void) munmap((char *)sptr, ndata);
250*0Sstevel@tonic-gate 				}
251*0Sstevel@tonic-gate 				__s_api_free2dArray(cptr);
252*0Sstevel@tonic-gate 				free(ret->server);
253*0Sstevel@tonic-gate 				ret->server = NULL;
254*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
255*0Sstevel@tonic-gate 			}
256*0Sstevel@tonic-gate 			mptr = mptr1;
257*0Sstevel@tonic-gate 			mptr[mcnt] = strdup(dptr);
258*0Sstevel@tonic-gate 			if (mptr[mcnt] == NULL) {
259*0Sstevel@tonic-gate 				if (sptr != &space.s_d) {
260*0Sstevel@tonic-gate 				    (void) munmap((char *)sptr, ndata);
261*0Sstevel@tonic-gate 				}
262*0Sstevel@tonic-gate 				__s_api_free2dArray(cptr);
263*0Sstevel@tonic-gate 				cptr = NULL;
264*0Sstevel@tonic-gate 				__s_api_free2dArray(mptr);
265*0Sstevel@tonic-gate 				mptr = NULL;
266*0Sstevel@tonic-gate 				free(ret->server);
267*0Sstevel@tonic-gate 				ret->server = NULL;
268*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
269*0Sstevel@tonic-gate 			}
270*0Sstevel@tonic-gate 			mcnt++;
271*0Sstevel@tonic-gate 			mptr[mcnt] = NULL;
272*0Sstevel@tonic-gate 		}
273*0Sstevel@tonic-gate 		if (strncasecmp(ptr, _SUPPORTEDCONTROL,
274*0Sstevel@tonic-gate 			_SUPPORTEDCONTROL_LEN) == 0) {
275*0Sstevel@tonic-gate 			dptr = strchr(ptr, '=');
276*0Sstevel@tonic-gate 			if (dptr == NULL)
277*0Sstevel@tonic-gate 				continue;
278*0Sstevel@tonic-gate 			dptr++;
279*0Sstevel@tonic-gate 			cptr1 = (char **)realloc((void *)cptr,
280*0Sstevel@tonic-gate 					sizeof (char *) * (ccnt+2));
281*0Sstevel@tonic-gate 			if (cptr1 == NULL) {
282*0Sstevel@tonic-gate 				if (sptr != &space.s_d) {
283*0Sstevel@tonic-gate 				    (void) munmap((char *)sptr, ndata);
284*0Sstevel@tonic-gate 				}
285*0Sstevel@tonic-gate 				__s_api_free2dArray(cptr);
286*0Sstevel@tonic-gate 				__s_api_free2dArray(mptr);
287*0Sstevel@tonic-gate 				mptr = NULL;
288*0Sstevel@tonic-gate 				free(ret->server);
289*0Sstevel@tonic-gate 				ret->server = NULL;
290*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
291*0Sstevel@tonic-gate 			}
292*0Sstevel@tonic-gate 			cptr = cptr1;
293*0Sstevel@tonic-gate 			cptr[ccnt] = strdup(dptr);
294*0Sstevel@tonic-gate 			if (cptr[ccnt] == NULL) {
295*0Sstevel@tonic-gate 				if (sptr != &space.s_d) {
296*0Sstevel@tonic-gate 				    (void) munmap((char *)sptr, ndata);
297*0Sstevel@tonic-gate 				}
298*0Sstevel@tonic-gate 				__s_api_free2dArray(cptr);
299*0Sstevel@tonic-gate 				cptr = NULL;
300*0Sstevel@tonic-gate 				__s_api_free2dArray(mptr);
301*0Sstevel@tonic-gate 				mptr = NULL;
302*0Sstevel@tonic-gate 				free(ret->server);
303*0Sstevel@tonic-gate 				ret->server = NULL;
304*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
305*0Sstevel@tonic-gate 			}
306*0Sstevel@tonic-gate 			ccnt++;
307*0Sstevel@tonic-gate 			cptr[ccnt] = NULL;
308*0Sstevel@tonic-gate 		}
309*0Sstevel@tonic-gate 	}
310*0Sstevel@tonic-gate 	if (mptr != NULL) {
311*0Sstevel@tonic-gate 		ret->saslMechanisms = mptr;
312*0Sstevel@tonic-gate 	}
313*0Sstevel@tonic-gate 	if (cptr != NULL) {
314*0Sstevel@tonic-gate 		ret->controls = cptr;
315*0Sstevel@tonic-gate 	}
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	/* clean up door call */
319*0Sstevel@tonic-gate 	if (sptr != &space.s_d) {
320*0Sstevel@tonic-gate 		(void) munmap((char *)sptr, ndata);
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 	*error = NULL;
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate #ifdef DEBUG
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate /*
330*0Sstevel@tonic-gate  * printCred(): prints the credential structure
331*0Sstevel@tonic-gate  */
332*0Sstevel@tonic-gate static void
333*0Sstevel@tonic-gate printCred(FILE *fp, const ns_cred_t *cred)
334*0Sstevel@tonic-gate {
335*0Sstevel@tonic-gate 	if (fp == NULL) {
336*0Sstevel@tonic-gate 		(void) fprintf(fp, "printCred: fp is NULL\n");
337*0Sstevel@tonic-gate 		return;
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 	if (cred == NULL) {
340*0Sstevel@tonic-gate 		(void) fprintf(fp, "printCred: cred is NULL\n");
341*0Sstevel@tonic-gate 		return;
342*0Sstevel@tonic-gate 	}
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	(void) fprintf(fp, "AuthType=%d\n", cred->auth.type);
345*0Sstevel@tonic-gate 	(void) fprintf(fp, "TlsType=%d\n", cred->auth.tlstype);
346*0Sstevel@tonic-gate 	(void) fprintf(fp, "SaslMech=%d\n", cred->auth.saslmech);
347*0Sstevel@tonic-gate 	(void) fprintf(fp, "SaslOpt=%d\n", cred->auth.saslopt);
348*0Sstevel@tonic-gate 	if (cred->hostcertpath)
349*0Sstevel@tonic-gate 		(void) fprintf(fp, "hostCertPath=%s\n", cred->hostcertpath);
350*0Sstevel@tonic-gate 	if (cred->cred.unix_cred.userID)
351*0Sstevel@tonic-gate 		(void) fprintf(fp, "userID=%s\n", cred->cred.unix_cred.userID);
352*0Sstevel@tonic-gate 	if (cred->cred.unix_cred.passwd)
353*0Sstevel@tonic-gate 		(void) fprintf(fp, "passwd=%s\n", cred->cred.unix_cred.passwd);
354*0Sstevel@tonic-gate }
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate /*
357*0Sstevel@tonic-gate  * printConnection(): prints the connection structure
358*0Sstevel@tonic-gate  */
359*0Sstevel@tonic-gate static void
360*0Sstevel@tonic-gate printConnection(FILE *fp, Connection *con)
361*0Sstevel@tonic-gate {
362*0Sstevel@tonic-gate 	if (fp == NULL || con == NULL)
363*0Sstevel@tonic-gate 		return;
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	(void) fprintf(fp, "connectionID=%d\n", con->connectionId);
366*0Sstevel@tonic-gate 	(void) fprintf(fp, "usedBit=%d\n", con->usedBit);
367*0Sstevel@tonic-gate 	(void) fprintf(fp, "threadID=%d\n", con->threadID);
368*0Sstevel@tonic-gate 	if (con->serverAddr) {
369*0Sstevel@tonic-gate 		(void) fprintf(fp, "serverAddr=%s\n", con->serverAddr);
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate 	printCred(fp, con->auth);
372*0Sstevel@tonic-gate 	(void) fprintf(fp, "-----------------------------------------------\n");
373*0Sstevel@tonic-gate 	fflush(fp);
374*0Sstevel@tonic-gate }
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate #endif /* DEBUG */
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate /*
380*0Sstevel@tonic-gate  * addConnection(): inserts a connection in the connection list.
381*0Sstevel@tonic-gate  * It will also sets use bit and the thread Id for the thread
382*0Sstevel@tonic-gate  * using the connection for the first time.
383*0Sstevel@tonic-gate  * Returns: -1 = failure, new Connection ID = success
384*0Sstevel@tonic-gate  */
385*0Sstevel@tonic-gate static int
386*0Sstevel@tonic-gate addConnection(Connection *con)
387*0Sstevel@tonic-gate {
388*0Sstevel@tonic-gate 	int i;
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	if (!con)
391*0Sstevel@tonic-gate 		return (-1);
392*0Sstevel@tonic-gate #ifdef DEBUG
393*0Sstevel@tonic-gate 	(void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID);
394*0Sstevel@tonic-gate #endif /* DEBUG */
395*0Sstevel@tonic-gate 	(void) mutex_lock(&sessionPoolLock);
396*0Sstevel@tonic-gate 	if (sessionPool == NULL) {
397*0Sstevel@tonic-gate 		sessionPoolSize = SESSION_CACHE_INC;
398*0Sstevel@tonic-gate 		sessionPool = calloc(sessionPoolSize,
399*0Sstevel@tonic-gate 				sizeof (struct connection **));
400*0Sstevel@tonic-gate 		if (!sessionPool) {
401*0Sstevel@tonic-gate 			(void) mutex_unlock(&sessionPoolLock);
402*0Sstevel@tonic-gate 			return (-1);
403*0Sstevel@tonic-gate 		}
404*0Sstevel@tonic-gate #ifdef DEBUG
405*0Sstevel@tonic-gate 		(void) fprintf(stderr, "Initialized sessionPool\n");
406*0Sstevel@tonic-gate #endif /* DEBUG */
407*0Sstevel@tonic-gate 	}
408*0Sstevel@tonic-gate 	for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i)
409*0Sstevel@tonic-gate 		;
410*0Sstevel@tonic-gate 	if (i == sessionPoolSize) {
411*0Sstevel@tonic-gate 		/* run out of array, need to increase sessionPool */
412*0Sstevel@tonic-gate 		Connection **cl;
413*0Sstevel@tonic-gate 		cl = (Connection **) realloc(sessionPool,
414*0Sstevel@tonic-gate 			(sessionPoolSize + SESSION_CACHE_INC) *
415*0Sstevel@tonic-gate 			sizeof (Connection *));
416*0Sstevel@tonic-gate 		if (!cl) {
417*0Sstevel@tonic-gate 			(void) mutex_unlock(&sessionPoolLock);
418*0Sstevel@tonic-gate 			return (-1);
419*0Sstevel@tonic-gate 		}
420*0Sstevel@tonic-gate 		(void) memset(cl + sessionPoolSize, 0,
421*0Sstevel@tonic-gate 			SESSION_CACHE_INC * sizeof (struct connection *));
422*0Sstevel@tonic-gate 		sessionPool = cl;
423*0Sstevel@tonic-gate 		sessionPoolSize += SESSION_CACHE_INC;
424*0Sstevel@tonic-gate #ifdef DEBUG
425*0Sstevel@tonic-gate 		(void) fprintf(stderr, "Increased sessionPoolSize to: %d\n",
426*0Sstevel@tonic-gate 				sessionPoolSize);
427*0Sstevel@tonic-gate #endif /* DEBUG */
428*0Sstevel@tonic-gate 	}
429*0Sstevel@tonic-gate 	sessionPool[i] = con;
430*0Sstevel@tonic-gate 	con->usedBit = B_TRUE;
431*0Sstevel@tonic-gate 	(void) mutex_unlock(&sessionPoolLock);
432*0Sstevel@tonic-gate 	con->connectionId = i + CONID_OFFSET;
433*0Sstevel@tonic-gate #ifdef DEBUG
434*0Sstevel@tonic-gate 	(void) fprintf(stderr, "Connection added [%d]\n", i);
435*0Sstevel@tonic-gate 	printConnection(stderr, con);
436*0Sstevel@tonic-gate #endif /* DEBUG */
437*0Sstevel@tonic-gate 	return (i + CONID_OFFSET);
438*0Sstevel@tonic-gate }
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate /*
441*0Sstevel@tonic-gate  * See if the specified session matches a currently available
442*0Sstevel@tonic-gate  */
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate static int
445*0Sstevel@tonic-gate findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID,
446*0Sstevel@tonic-gate 	Connection **conp)
447*0Sstevel@tonic-gate {
448*0Sstevel@tonic-gate 	Connection *cp;
449*0Sstevel@tonic-gate 	int id;
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	if ((conp == NULL) || (auth == NULL) || cID < CONID_OFFSET)
452*0Sstevel@tonic-gate 		return (-1);
453*0Sstevel@tonic-gate 	*conp = NULL;
454*0Sstevel@tonic-gate 	if (sessionPool == NULL)
455*0Sstevel@tonic-gate 		return (-1);
456*0Sstevel@tonic-gate 	id = cID - CONID_OFFSET;
457*0Sstevel@tonic-gate 	if (id < 0 || id >= sessionPoolSize)
458*0Sstevel@tonic-gate 		return (-1);
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	(void) mutex_lock(&sessionPoolLock);
461*0Sstevel@tonic-gate 	if (sessionPool[id] == NULL) {
462*0Sstevel@tonic-gate 		(void) mutex_unlock(&sessionPoolLock);
463*0Sstevel@tonic-gate 		return (-1);
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 	cp = sessionPool[id];
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	/*
468*0Sstevel@tonic-gate 	 * Make sure the connection has the same type of authentication method
469*0Sstevel@tonic-gate 	 */
470*0Sstevel@tonic-gate 	if ((cp->usedBit) ||
471*0Sstevel@tonic-gate 	    (cp->auth->auth.type != auth->auth.type) ||
472*0Sstevel@tonic-gate 	    (cp->auth->auth.tlstype != auth->auth.tlstype) ||
473*0Sstevel@tonic-gate 	    (cp->auth->auth.saslmech != auth->auth.saslmech) ||
474*0Sstevel@tonic-gate 	    (cp->auth->auth.saslopt != auth->auth.saslopt)) {
475*0Sstevel@tonic-gate 		(void) mutex_unlock(&sessionPoolLock);
476*0Sstevel@tonic-gate 		return (-1);
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 	if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) &&
479*0Sstevel@tonic-gate 		((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) ||
480*0Sstevel@tonic-gate 		(cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) ||
481*0Sstevel@tonic-gate 		(cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) &&
482*0Sstevel@tonic-gate 		((cp->auth->cred.unix_cred.userID == NULL) ||
483*0Sstevel@tonic-gate 		(strcasecmp(cp->auth->cred.unix_cred.userID,
484*0Sstevel@tonic-gate 		auth->cred.unix_cred.userID) != 0))) {
485*0Sstevel@tonic-gate 		(void) mutex_unlock(&sessionPoolLock);
486*0Sstevel@tonic-gate 		return (-1);
487*0Sstevel@tonic-gate 	}
488*0Sstevel@tonic-gate 	/* An existing connection is found but it needs to be reset */
489*0Sstevel@tonic-gate 	if (flags & NS_LDAP_NEW_CONN) {
490*0Sstevel@tonic-gate 		(void) mutex_unlock(&sessionPoolLock);
491*0Sstevel@tonic-gate 		DropConnection(cID, 0);
492*0Sstevel@tonic-gate 		return (-1);
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 	/* found an available connection */
495*0Sstevel@tonic-gate 	cp->usedBit = B_TRUE;
496*0Sstevel@tonic-gate 	(void) mutex_unlock(&sessionPoolLock);
497*0Sstevel@tonic-gate 	cp->threadID = thr_self();
498*0Sstevel@tonic-gate 	*conp = cp;
499*0Sstevel@tonic-gate 	return (cID);
500*0Sstevel@tonic-gate }
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate /*
503*0Sstevel@tonic-gate  * findConnection(): find an available connection from the list
504*0Sstevel@tonic-gate  * that matches the criteria specified in Connection structure.
505*0Sstevel@tonic-gate  * If serverAddr is NULL, then find a connection to any server
506*0Sstevel@tonic-gate  * as long as it matches the rest of the parameters.
507*0Sstevel@tonic-gate  * Returns: -1 = failure, the Connection ID found = success.
508*0Sstevel@tonic-gate  */
509*0Sstevel@tonic-gate static int
510*0Sstevel@tonic-gate findConnection(const char *serverAddr, const ns_cred_t *auth, Connection **conp)
511*0Sstevel@tonic-gate {
512*0Sstevel@tonic-gate 	Connection *cp;
513*0Sstevel@tonic-gate 	int i;
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	if (auth == NULL || conp == NULL)
516*0Sstevel@tonic-gate 		return (-1);
517*0Sstevel@tonic-gate 	*conp = NULL;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate #ifdef DEBUG
520*0Sstevel@tonic-gate 	(void) fprintf(stderr, "Find connection\n");
521*0Sstevel@tonic-gate 	(void) fprintf(stderr, "Looking for ....\n");
522*0Sstevel@tonic-gate 	if (serverAddr && *serverAddr)
523*0Sstevel@tonic-gate 		(void) fprintf(stderr, "serverAddr=%s\n", serverAddr);
524*0Sstevel@tonic-gate 	else
525*0Sstevel@tonic-gate 		(void) fprintf(stderr, "serverAddr=NULL\n");
526*0Sstevel@tonic-gate 	printCred(stderr, auth);
527*0Sstevel@tonic-gate 	fflush(stderr);
528*0Sstevel@tonic-gate #endif /* DEBUG */
529*0Sstevel@tonic-gate 	if (sessionPool == NULL)
530*0Sstevel@tonic-gate 		return (-1);
531*0Sstevel@tonic-gate 	(void) mutex_lock(&sessionPoolLock);
532*0Sstevel@tonic-gate 	for (i = 0; i < sessionPoolSize; ++i) {
533*0Sstevel@tonic-gate 		if (sessionPool[i] == NULL)
534*0Sstevel@tonic-gate 			continue;
535*0Sstevel@tonic-gate 		cp = sessionPool[i];
536*0Sstevel@tonic-gate #ifdef DEBUG
537*0Sstevel@tonic-gate 		(void) fprintf(stderr, "checking connection [%d] ....\n", i);
538*0Sstevel@tonic-gate 		printConnection(stderr, cp);
539*0Sstevel@tonic-gate #endif /* DEBUG */
540*0Sstevel@tonic-gate 		if ((cp->usedBit) ||
541*0Sstevel@tonic-gate 		    (cp->auth->auth.type != auth->auth.type) ||
542*0Sstevel@tonic-gate 		    (cp->auth->auth.tlstype != auth->auth.tlstype) ||
543*0Sstevel@tonic-gate 		    (cp->auth->auth.saslmech != auth->auth.saslmech) ||
544*0Sstevel@tonic-gate 		    (cp->auth->auth.saslopt != auth->auth.saslopt) ||
545*0Sstevel@tonic-gate 		    (serverAddr && *serverAddr &&
546*0Sstevel@tonic-gate 		    (strcasecmp(serverAddr, cp->serverAddr) != 0)))
547*0Sstevel@tonic-gate 			continue;
548*0Sstevel@tonic-gate 		if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) &&
549*0Sstevel@tonic-gate 		    ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) ||
550*0Sstevel@tonic-gate 		    (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) ||
551*0Sstevel@tonic-gate 		    (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) &&
552*0Sstevel@tonic-gate 		    ((cp->auth->cred.unix_cred.userID == NULL) ||
553*0Sstevel@tonic-gate 		    (cp->auth->cred.unix_cred.passwd == NULL) ||
554*0Sstevel@tonic-gate 		    ((strcasecmp(cp->auth->cred.unix_cred.userID,
555*0Sstevel@tonic-gate 			    auth->cred.unix_cred.userID) != 0)) ||
556*0Sstevel@tonic-gate 		    ((strcmp(cp->auth->cred.unix_cred.passwd,
557*0Sstevel@tonic-gate 			    auth->cred.unix_cred.passwd) != 0))))
558*0Sstevel@tonic-gate 				continue;
559*0Sstevel@tonic-gate 		/* found an available connection */
560*0Sstevel@tonic-gate 		cp->usedBit = B_TRUE;
561*0Sstevel@tonic-gate 		(void) mutex_unlock(&sessionPoolLock);
562*0Sstevel@tonic-gate 		cp->threadID = thr_self();
563*0Sstevel@tonic-gate 		*conp = cp;
564*0Sstevel@tonic-gate #ifdef DEBUG
565*0Sstevel@tonic-gate 		(void) fprintf(stderr, "Connection found cID=%d\n", i);
566*0Sstevel@tonic-gate 		fflush(stderr);
567*0Sstevel@tonic-gate #endif /* DEBUG */
568*0Sstevel@tonic-gate 		return (i + CONID_OFFSET);
569*0Sstevel@tonic-gate 	}
570*0Sstevel@tonic-gate 	(void) mutex_unlock(&sessionPoolLock);
571*0Sstevel@tonic-gate 	return (-1);
572*0Sstevel@tonic-gate }
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate /*
575*0Sstevel@tonic-gate  * Free a Connection structure
576*0Sstevel@tonic-gate  */
577*0Sstevel@tonic-gate static void
578*0Sstevel@tonic-gate freeConnection(Connection *con)
579*0Sstevel@tonic-gate {
580*0Sstevel@tonic-gate 	if (con == NULL)
581*0Sstevel@tonic-gate 		return;
582*0Sstevel@tonic-gate 	if (con->serverAddr)
583*0Sstevel@tonic-gate 		free(con->serverAddr);
584*0Sstevel@tonic-gate 	if (con->auth)
585*0Sstevel@tonic-gate 		(void) __ns_ldap_freeCred(&(con->auth));
586*0Sstevel@tonic-gate 	if (con->saslMechanisms) {
587*0Sstevel@tonic-gate 		__s_api_free2dArray(con->saslMechanisms);
588*0Sstevel@tonic-gate 	}
589*0Sstevel@tonic-gate 	if (con->controls) {
590*0Sstevel@tonic-gate 		__s_api_free2dArray(con->controls);
591*0Sstevel@tonic-gate 	}
592*0Sstevel@tonic-gate 	free(con);
593*0Sstevel@tonic-gate }
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate /*
596*0Sstevel@tonic-gate  * Find a connection matching the passed in criteria.  If an open
597*0Sstevel@tonic-gate  * connection with that criteria exists use it, otherwise open a
598*0Sstevel@tonic-gate  * new connection.
599*0Sstevel@tonic-gate  * Success: returns the pointer to the Connection structure
600*0Sstevel@tonic-gate  * Failure: returns NULL, error code and message should be in errorp
601*0Sstevel@tonic-gate  */
602*0Sstevel@tonic-gate static int
603*0Sstevel@tonic-gate makeConnection(Connection **conp, const char *serverAddr,
604*0Sstevel@tonic-gate 	const ns_cred_t *auth, ConnectionID *cID, int timeoutSec,
605*0Sstevel@tonic-gate 	ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd)
606*0Sstevel@tonic-gate {
607*0Sstevel@tonic-gate 	Connection *con = NULL;
608*0Sstevel@tonic-gate 	ConnectionID id;
609*0Sstevel@tonic-gate 	char errmsg[MAXERROR];
610*0Sstevel@tonic-gate 	int rc, exit_rc = NS_LDAP_SUCCESS;
611*0Sstevel@tonic-gate 	ns_server_info_t sinfo;
612*0Sstevel@tonic-gate 	char *hReq, *host = NULL;
613*0Sstevel@tonic-gate 	LDAP *ld = NULL;
614*0Sstevel@tonic-gate 	int passwd_mgmt = 0;
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	if (conp == NULL || errorp == NULL || auth == NULL)
617*0Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
618*0Sstevel@tonic-gate 	*errorp = NULL;
619*0Sstevel@tonic-gate 	*conp = NULL;
620*0Sstevel@tonic-gate 	sinfo.server = NULL;
621*0Sstevel@tonic-gate 	sinfo.controls = NULL;
622*0Sstevel@tonic-gate 	sinfo.saslMechanisms = NULL;
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	if ((id = findConnection(serverAddr, auth, &con)) != -1) {
625*0Sstevel@tonic-gate 		/* connection found in cache */
626*0Sstevel@tonic-gate #ifdef DEBUG
627*0Sstevel@tonic-gate 		(void) fprintf(stderr, "connection found in cache %d\n", id);
628*0Sstevel@tonic-gate 		fflush(stderr);
629*0Sstevel@tonic-gate #endif /* DEBUG */
630*0Sstevel@tonic-gate 		*cID = id;
631*0Sstevel@tonic-gate 		*conp = con;
632*0Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
633*0Sstevel@tonic-gate 	}
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 	if (serverAddr) {
636*0Sstevel@tonic-gate 		rc = openConnection(&ld, serverAddr, auth, timeoutSec, errorp,
637*0Sstevel@tonic-gate 				fail_if_new_pwd_reqd, passwd_mgmt);
638*0Sstevel@tonic-gate 		if (rc == NS_LDAP_SUCCESS || rc ==
639*0Sstevel@tonic-gate 				NS_LDAP_SUCCESS_WITH_INFO) {
640*0Sstevel@tonic-gate 			exit_rc = rc;
641*0Sstevel@tonic-gate 			rc = __s_api_requestServer(NS_CACHE_NEW, serverAddr,
642*0Sstevel@tonic-gate 				&sinfo, errorp);
643*0Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS || sinfo.server == NULL) {
644*0Sstevel@tonic-gate 				(void) snprintf(errmsg, sizeof (errmsg),
645*0Sstevel@tonic-gate 				gettext("makeConnection: unable to get "
646*0Sstevel@tonic-gate 				"server information for %s"), serverAddr);
647*0Sstevel@tonic-gate 				syslog(LOG_ERR, "libsldap: %s", errmsg);
648*0Sstevel@tonic-gate 				return (NS_LDAP_OP_FAILED);
649*0Sstevel@tonic-gate 			}
650*0Sstevel@tonic-gate 			goto create_con;
651*0Sstevel@tonic-gate 		} else {
652*0Sstevel@tonic-gate 			return (rc);
653*0Sstevel@tonic-gate 		}
654*0Sstevel@tonic-gate 	}
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	/* No cached connection, create one */
657*0Sstevel@tonic-gate 	for (; ; ) {
658*0Sstevel@tonic-gate 		if (host == NULL)
659*0Sstevel@tonic-gate 			hReq = NS_CACHE_NEW;
660*0Sstevel@tonic-gate 		else
661*0Sstevel@tonic-gate 			hReq = NS_CACHE_NEXT;
662*0Sstevel@tonic-gate 		rc = __s_api_requestServer(hReq, host, &sinfo, errorp);
663*0Sstevel@tonic-gate 		if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) ||
664*0Sstevel@tonic-gate 			(host && (strcasecmp(host, sinfo.server) == 0))) {
665*0Sstevel@tonic-gate 			/* Log the error */
666*0Sstevel@tonic-gate 			if (*errorp) {
667*0Sstevel@tonic-gate 				(void) snprintf(errmsg, sizeof (errmsg),
668*0Sstevel@tonic-gate 				"%s: (%s)", gettext("makeConnection: "
669*0Sstevel@tonic-gate 				"unable to make LDAP connection, "
670*0Sstevel@tonic-gate 				"request for a server failed"),
671*0Sstevel@tonic-gate 				    (*errorp)->message);
672*0Sstevel@tonic-gate 				syslog(LOG_ERR, "libsldap: %s", errmsg);
673*0Sstevel@tonic-gate 			}
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 			if (sinfo.server)
676*0Sstevel@tonic-gate 				free(sinfo.server);
677*0Sstevel@tonic-gate 			__s_api_free2dArray(sinfo.saslMechanisms);
678*0Sstevel@tonic-gate 			__s_api_free2dArray(sinfo.controls);
679*0Sstevel@tonic-gate 			if (host)
680*0Sstevel@tonic-gate 				free(host);
681*0Sstevel@tonic-gate 			return (NS_LDAP_OP_FAILED);
682*0Sstevel@tonic-gate 		}
683*0Sstevel@tonic-gate 		if (host)
684*0Sstevel@tonic-gate 			free(host);
685*0Sstevel@tonic-gate 		host = strdup(sinfo.server);
686*0Sstevel@tonic-gate 		if (host == NULL) {
687*0Sstevel@tonic-gate 			free(sinfo.server);
688*0Sstevel@tonic-gate 			__s_api_free2dArray(sinfo.saslMechanisms);
689*0Sstevel@tonic-gate 			__s_api_free2dArray(sinfo.controls);
690*0Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
691*0Sstevel@tonic-gate 		}
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 		/* check if server supports password management */
694*0Sstevel@tonic-gate 		passwd_mgmt = __s_api_contain_passwd_control_oid(
695*0Sstevel@tonic-gate 			sinfo.controls);
696*0Sstevel@tonic-gate 		/* make the connection */
697*0Sstevel@tonic-gate 		rc = openConnection(&ld, host, auth, timeoutSec, errorp,
698*0Sstevel@tonic-gate 				fail_if_new_pwd_reqd, passwd_mgmt);
699*0Sstevel@tonic-gate 		/* if success, go to create connection structure */
700*0Sstevel@tonic-gate 		if (rc == NS_LDAP_SUCCESS ||
701*0Sstevel@tonic-gate 				rc == NS_LDAP_SUCCESS_WITH_INFO) {
702*0Sstevel@tonic-gate 			exit_rc = rc;
703*0Sstevel@tonic-gate 			break;
704*0Sstevel@tonic-gate 		}
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 		/*
707*0Sstevel@tonic-gate 		 * If not able to reach the server, inform the ldap
708*0Sstevel@tonic-gate 		 * cache manager that the server should be removed
709*0Sstevel@tonic-gate 		 * from its server list. Thus, the manager will not
710*0Sstevel@tonic-gate 		 * return this server on the next get-server request
711*0Sstevel@tonic-gate 		 * and will also reduce the server list refresh TTL,
712*0Sstevel@tonic-gate 		 * so that it will find out sooner when the server
713*0Sstevel@tonic-gate 		 * is up again.
714*0Sstevel@tonic-gate 		 */
715*0Sstevel@tonic-gate 		if (rc == NS_LDAP_INTERNAL && *errorp != NULL) {
716*0Sstevel@tonic-gate 			if ((*errorp)->status == LDAP_CONNECT_ERROR ||
717*0Sstevel@tonic-gate 				(*errorp)->status == LDAP_SERVER_DOWN)
718*0Sstevel@tonic-gate 				__s_api_removeServer(host);
719*0Sstevel@tonic-gate 		}
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 		/* else, cleanup and go for the next server */
722*0Sstevel@tonic-gate 		if (sinfo.server) {
723*0Sstevel@tonic-gate 			free(sinfo.server);
724*0Sstevel@tonic-gate 			sinfo.server = NULL;
725*0Sstevel@tonic-gate 		}
726*0Sstevel@tonic-gate 		__s_api_free2dArray(sinfo.saslMechanisms);
727*0Sstevel@tonic-gate 		sinfo.saslMechanisms = NULL;
728*0Sstevel@tonic-gate 		__s_api_free2dArray(sinfo.controls);
729*0Sstevel@tonic-gate 		sinfo.controls = NULL;
730*0Sstevel@tonic-gate 		if (*errorp) {
731*0Sstevel@tonic-gate 			/*
732*0Sstevel@tonic-gate 			 * If openConnection() failed due to
733*0Sstevel@tonic-gate 			 * password policy, or invalid credential,
734*0Sstevel@tonic-gate 			 * keep *errorp and exit
735*0Sstevel@tonic-gate 			 */
736*0Sstevel@tonic-gate 			if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD ||
737*0Sstevel@tonic-gate 			    (*errorp)->status == LDAP_INVALID_CREDENTIALS) {
738*0Sstevel@tonic-gate 				free(host);
739*0Sstevel@tonic-gate 				return (rc);
740*0Sstevel@tonic-gate 			} else {
741*0Sstevel@tonic-gate 				(void) __ns_ldap_freeError(errorp);
742*0Sstevel@tonic-gate 				*errorp = NULL;
743*0Sstevel@tonic-gate 			}
744*0Sstevel@tonic-gate 		}
745*0Sstevel@tonic-gate 	}
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate create_con:
748*0Sstevel@tonic-gate 	/* we have created ld, setup con structure */
749*0Sstevel@tonic-gate 	if (host)
750*0Sstevel@tonic-gate 		free(host);
751*0Sstevel@tonic-gate 	if ((con = calloc(1, sizeof (Connection))) == NULL) {
752*0Sstevel@tonic-gate 		if (sinfo.server)
753*0Sstevel@tonic-gate 			free(sinfo.server);
754*0Sstevel@tonic-gate 		__s_api_free2dArray(sinfo.saslMechanisms);
755*0Sstevel@tonic-gate 		__s_api_free2dArray(sinfo.controls);
756*0Sstevel@tonic-gate 		/*
757*0Sstevel@tonic-gate 		 * If password control attached in **errorp,
758*0Sstevel@tonic-gate 		 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
759*0Sstevel@tonic-gate 		 * free the error structure
760*0Sstevel@tonic-gate 		 */
761*0Sstevel@tonic-gate 		if (*errorp) {
762*0Sstevel@tonic-gate 			(void) __ns_ldap_freeError(errorp);
763*0Sstevel@tonic-gate 			*errorp = NULL;
764*0Sstevel@tonic-gate 		}
765*0Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
766*0Sstevel@tonic-gate 	}
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	con->serverAddr = sinfo.server;
769*0Sstevel@tonic-gate 	con->saslMechanisms = sinfo.saslMechanisms;
770*0Sstevel@tonic-gate 	con->controls = sinfo.controls;
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	con->auth = __ns_ldap_dupAuth(auth);
773*0Sstevel@tonic-gate 	if (con->auth == NULL) {
774*0Sstevel@tonic-gate 		free(con);
775*0Sstevel@tonic-gate 		/*
776*0Sstevel@tonic-gate 		 * If password control attached in **errorp,
777*0Sstevel@tonic-gate 		 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
778*0Sstevel@tonic-gate 		 * free the error structure
779*0Sstevel@tonic-gate 		 */
780*0Sstevel@tonic-gate 		if (*errorp) {
781*0Sstevel@tonic-gate 			(void) __ns_ldap_freeError(errorp);
782*0Sstevel@tonic-gate 			*errorp = NULL;
783*0Sstevel@tonic-gate 		}
784*0Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
785*0Sstevel@tonic-gate 	}
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	con->threadID = thr_self();
788*0Sstevel@tonic-gate 	con->ld = ld;
789*0Sstevel@tonic-gate 	if ((id = addConnection(con)) == -1) {
790*0Sstevel@tonic-gate 		freeConnection(con);
791*0Sstevel@tonic-gate 		/*
792*0Sstevel@tonic-gate 		 * If password control attached in **errorp,
793*0Sstevel@tonic-gate 		 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
794*0Sstevel@tonic-gate 		 * free the error structure
795*0Sstevel@tonic-gate 		 */
796*0Sstevel@tonic-gate 		if (*errorp) {
797*0Sstevel@tonic-gate 			(void) __ns_ldap_freeError(errorp);
798*0Sstevel@tonic-gate 			*errorp = NULL;
799*0Sstevel@tonic-gate 		}
800*0Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
801*0Sstevel@tonic-gate 	}
802*0Sstevel@tonic-gate #ifdef DEBUG
803*0Sstevel@tonic-gate 	(void) fprintf(stderr, "connection added into cache %d\n", id);
804*0Sstevel@tonic-gate 	fflush(stderr);
805*0Sstevel@tonic-gate #endif /* DEBUG */
806*0Sstevel@tonic-gate 	*cID = id;
807*0Sstevel@tonic-gate 	*conp = con;
808*0Sstevel@tonic-gate 	return (exit_rc);
809*0Sstevel@tonic-gate }
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate /*
812*0Sstevel@tonic-gate  * Return the specified connection to the pool.  If necessary
813*0Sstevel@tonic-gate  * delete the connection.
814*0Sstevel@tonic-gate  */
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate static void
817*0Sstevel@tonic-gate _DropConnection(ConnectionID cID, int flag, int fini)
818*0Sstevel@tonic-gate {
819*0Sstevel@tonic-gate 	Connection *cp;
820*0Sstevel@tonic-gate 	int id;
821*0Sstevel@tonic-gate 	int use_mutex = !fini;
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	id = cID - CONID_OFFSET;
824*0Sstevel@tonic-gate 	if (id < 0 || id >= sessionPoolSize)
825*0Sstevel@tonic-gate 		return;
826*0Sstevel@tonic-gate #ifdef DEBUG
827*0Sstevel@tonic-gate 	(void) fprintf(stderr,
828*0Sstevel@tonic-gate 		"Dropping connection cID=%d flag=0x%x\n", cID, flag);
829*0Sstevel@tonic-gate 	fflush(stderr);
830*0Sstevel@tonic-gate #endif /* DEBUG */
831*0Sstevel@tonic-gate 	if (use_mutex)
832*0Sstevel@tonic-gate 		(void) mutex_lock(&sessionPoolLock);
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 	cp = sessionPool[id];
835*0Sstevel@tonic-gate 	/* sanity check before removing */
836*0Sstevel@tonic-gate 	if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) {
837*0Sstevel@tonic-gate 		if (use_mutex)
838*0Sstevel@tonic-gate 			(void) mutex_unlock(&sessionPoolLock);
839*0Sstevel@tonic-gate 		return;
840*0Sstevel@tonic-gate 	}
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	if (!fini &&
843*0Sstevel@tonic-gate 		((flag & NS_LDAP_NEW_CONN) == 0) &&
844*0Sstevel@tonic-gate 		((flag & NS_LDAP_KEEP_CONN) || nscd_proc())) {
845*0Sstevel@tonic-gate 		/* release Connection (keep alive) */
846*0Sstevel@tonic-gate 		cp->usedBit = B_FALSE;
847*0Sstevel@tonic-gate 		cp->threadID = 0;	/* unmark the threadID */
848*0Sstevel@tonic-gate 		if (use_mutex)
849*0Sstevel@tonic-gate 			(void) mutex_unlock(&sessionPoolLock);
850*0Sstevel@tonic-gate 	} else {
851*0Sstevel@tonic-gate 		/* delete Connection (disconnect) */
852*0Sstevel@tonic-gate 		sessionPool[id] = NULL;
853*0Sstevel@tonic-gate 		if (use_mutex)
854*0Sstevel@tonic-gate 			(void) mutex_unlock(&sessionPoolLock);
855*0Sstevel@tonic-gate 		(void) ldap_unbind(cp->ld);
856*0Sstevel@tonic-gate 		freeConnection(cp);
857*0Sstevel@tonic-gate 	}
858*0Sstevel@tonic-gate }
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate void
861*0Sstevel@tonic-gate DropConnection(ConnectionID cID, int flag)
862*0Sstevel@tonic-gate {
863*0Sstevel@tonic-gate 	_DropConnection(cID, flag, 0);
864*0Sstevel@tonic-gate }
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate /*
867*0Sstevel@tonic-gate  * This routine is called after a bind operation is
868*0Sstevel@tonic-gate  * done in openConnection() to process the password
869*0Sstevel@tonic-gate  * management information, if any.
870*0Sstevel@tonic-gate  *
871*0Sstevel@tonic-gate  * Input:
872*0Sstevel@tonic-gate  *   bind_type: "simple" or "sasl/DIGEST-MD5"
873*0Sstevel@tonic-gate  *   ldaprc   : ldap rc from the ldap bind operation
874*0Sstevel@tonic-gate  *   controls : controls returned by the server
875*0Sstevel@tonic-gate  *   errmsg   : error message from the server
876*0Sstevel@tonic-gate  *   fail_if_new_pwd_reqd:
877*0Sstevel@tonic-gate  *              flag indicating if connection should be open
878*0Sstevel@tonic-gate  *              when password needs to change immediately
879*0Sstevel@tonic-gate  *   passwd_mgmt:
880*0Sstevel@tonic-gate  *              flag indicating if server supports password
881*0Sstevel@tonic-gate  *              policy/management
882*0Sstevel@tonic-gate  *
883*0Sstevel@tonic-gate  * Output     : ns_ldap_error structure, which may contain
884*0Sstevel@tonic-gate  *              password status and number of seconds until
885*0Sstevel@tonic-gate  *              expired
886*0Sstevel@tonic-gate  *
887*0Sstevel@tonic-gate  * return rc:
888*0Sstevel@tonic-gate  * NS_LDAP_EXTERNAL: error, connection should not open
889*0Sstevel@tonic-gate  * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached
890*0Sstevel@tonic-gate  * NS_LDAP_SUCCESS: OK to open connection
891*0Sstevel@tonic-gate  *
892*0Sstevel@tonic-gate  */
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate static int
895*0Sstevel@tonic-gate process_pwd_mgmt(char *bind_type, int ldaprc,
896*0Sstevel@tonic-gate 		LDAPControl **controls,
897*0Sstevel@tonic-gate 		char *errmsg, ns_ldap_error_t **errorp,
898*0Sstevel@tonic-gate 		int fail_if_new_pwd_reqd,
899*0Sstevel@tonic-gate 		int passwd_mgmt)
900*0Sstevel@tonic-gate {
901*0Sstevel@tonic-gate 	char		errstr[MAXERROR];
902*0Sstevel@tonic-gate 	LDAPControl	**ctrl = NULL;
903*0Sstevel@tonic-gate 	int		exit_rc;
904*0Sstevel@tonic-gate 	ns_ldap_passwd_status_t	pwd_status = NS_PASSWD_GOOD;
905*0Sstevel@tonic-gate 	int		sec_until_exp = 0;
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	/*
908*0Sstevel@tonic-gate 	 * errmsg may be an empty string,
909*0Sstevel@tonic-gate 	 * even if ldaprc is LDAP_SUCCESS,
910*0Sstevel@tonic-gate 	 * free the empty string if that's the case
911*0Sstevel@tonic-gate 	 */
912*0Sstevel@tonic-gate 	if (errmsg &&
913*0Sstevel@tonic-gate 		(*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) {
914*0Sstevel@tonic-gate 		ldap_memfree(errmsg);
915*0Sstevel@tonic-gate 		errmsg = NULL;
916*0Sstevel@tonic-gate 	}
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 	if (ldaprc != LDAP_SUCCESS) {
919*0Sstevel@tonic-gate 		/*
920*0Sstevel@tonic-gate 		 * try to map ldap rc and error message to
921*0Sstevel@tonic-gate 		 * a password status
922*0Sstevel@tonic-gate 		 */
923*0Sstevel@tonic-gate 		if (errmsg) {
924*0Sstevel@tonic-gate 			if (passwd_mgmt)
925*0Sstevel@tonic-gate 				pwd_status =
926*0Sstevel@tonic-gate 					__s_api_set_passwd_status(
927*0Sstevel@tonic-gate 					ldaprc, errmsg);
928*0Sstevel@tonic-gate 			ldap_memfree(errmsg);
929*0Sstevel@tonic-gate 		}
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 		(void) snprintf(errstr, sizeof (errstr),
932*0Sstevel@tonic-gate 			gettext("openConnection: "
933*0Sstevel@tonic-gate 			"%s bind failed "
934*0Sstevel@tonic-gate 			"- %s"), bind_type, ldap_err2string(ldaprc));
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate 		if (pwd_status != NS_PASSWD_GOOD) {
937*0Sstevel@tonic-gate 			MKERROR_PWD_MGMT(*errorp,
938*0Sstevel@tonic-gate 				ldaprc, strdup(errstr),
939*0Sstevel@tonic-gate 				pwd_status, 0, NULL);
940*0Sstevel@tonic-gate 		} else {
941*0Sstevel@tonic-gate 			MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr),
942*0Sstevel@tonic-gate 				NULL);
943*0Sstevel@tonic-gate 		}
944*0Sstevel@tonic-gate 		if (controls)
945*0Sstevel@tonic-gate 			ldap_controls_free(controls);
946*0Sstevel@tonic-gate 
947*0Sstevel@tonic-gate 		return (NS_LDAP_INTERNAL);
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	/*
951*0Sstevel@tonic-gate 	 * ldaprc is LDAP_SUCCESS,
952*0Sstevel@tonic-gate 	 * process the password management controls, if any
953*0Sstevel@tonic-gate 	 */
954*0Sstevel@tonic-gate 	exit_rc = NS_LDAP_SUCCESS;
955*0Sstevel@tonic-gate 	if (controls && passwd_mgmt) {
956*0Sstevel@tonic-gate 		/*
957*0Sstevel@tonic-gate 		 * The control with the OID
958*0Sstevel@tonic-gate 		 * 2.16.840.1.113730.3.4.4 (or
959*0Sstevel@tonic-gate 		 * LDAP_CONTROL_PWEXPIRED, as defined
960*0Sstevel@tonic-gate 		 * in the ldap.h header file) is the
961*0Sstevel@tonic-gate 		 * expired password control.
962*0Sstevel@tonic-gate 		 *
963*0Sstevel@tonic-gate 		 * This control is used if the server
964*0Sstevel@tonic-gate 		 * is configured to require users to
965*0Sstevel@tonic-gate 		 * change their passwords when first
966*0Sstevel@tonic-gate 		 * logging in and whenever the
967*0Sstevel@tonic-gate 		 * passwords are reset.
968*0Sstevel@tonic-gate 		 *
969*0Sstevel@tonic-gate 		 * If the user is logging in for the
970*0Sstevel@tonic-gate 		 * first time or if the user's
971*0Sstevel@tonic-gate 		 * password has been reset, the
972*0Sstevel@tonic-gate 		 * server sends this control to
973*0Sstevel@tonic-gate 		 * indicate that the client needs to
974*0Sstevel@tonic-gate 		 * change the password immediately.
975*0Sstevel@tonic-gate 		 *
976*0Sstevel@tonic-gate 		 * At this point, the only operation
977*0Sstevel@tonic-gate 		 * that the client can perform is to
978*0Sstevel@tonic-gate 		 * change the user's password. If the
979*0Sstevel@tonic-gate 		 * client requests any other LDAP
980*0Sstevel@tonic-gate 		 * operation, the server sends back
981*0Sstevel@tonic-gate 		 * an LDAP_UNWILLING_TO_PERFORM
982*0Sstevel@tonic-gate 		 * result code with an expired
983*0Sstevel@tonic-gate 		 * password control.
984*0Sstevel@tonic-gate 		 *
985*0Sstevel@tonic-gate 		 * The control with the OID
986*0Sstevel@tonic-gate 		 * 2.16.840.1.113730.3.4.5 (or
987*0Sstevel@tonic-gate 		 * LDAP_CONTROL_PWEXPIRING, as
988*0Sstevel@tonic-gate 		 * defined in the ldap.h header file)
989*0Sstevel@tonic-gate 		 * is the password expiration warning
990*0Sstevel@tonic-gate 		 * control.
991*0Sstevel@tonic-gate 		 *
992*0Sstevel@tonic-gate 		 * This control is used if the server
993*0Sstevel@tonic-gate 		 * is configured to expire user
994*0Sstevel@tonic-gate 		 * passwords after a certain amount
995*0Sstevel@tonic-gate 		 * of time.
996*0Sstevel@tonic-gate 		 *
997*0Sstevel@tonic-gate 		 * The server sends this control back
998*0Sstevel@tonic-gate 		 * to the client if the client binds
999*0Sstevel@tonic-gate 		 * using a password that will soon
1000*0Sstevel@tonic-gate 		 * expire.  The ldctl_value field of
1001*0Sstevel@tonic-gate 		 * the LDAPControl structure
1002*0Sstevel@tonic-gate 		 * specifies the number of seconds
1003*0Sstevel@tonic-gate 		 * before the password will expire.
1004*0Sstevel@tonic-gate 		 */
1005*0Sstevel@tonic-gate 		for (ctrl = controls; *ctrl; ctrl++) {
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate 			if (strcmp((*ctrl)->ldctl_oid,
1008*0Sstevel@tonic-gate 				LDAP_CONTROL_PWEXPIRED) == 0) {
1009*0Sstevel@tonic-gate 				/*
1010*0Sstevel@tonic-gate 				 * if the caller wants this bind
1011*0Sstevel@tonic-gate 				 * to fail, set up the error info.
1012*0Sstevel@tonic-gate 				 * If call to this function is
1013*0Sstevel@tonic-gate 				 * for searching the LDAP directory,
1014*0Sstevel@tonic-gate 				 * e.g., __ns_ldap_list(),
1015*0Sstevel@tonic-gate 				 * there's really no sense to
1016*0Sstevel@tonic-gate 				 * let a connection open and
1017*0Sstevel@tonic-gate 				 * then fail immediately afterward
1018*0Sstevel@tonic-gate 				 * on the LDAP search operation with
1019*0Sstevel@tonic-gate 				 * the LDAP_UNWILLING_TO_PERFORM rc
1020*0Sstevel@tonic-gate 				 */
1021*0Sstevel@tonic-gate 				pwd_status =
1022*0Sstevel@tonic-gate 					NS_PASSWD_CHANGE_NEEDED;
1023*0Sstevel@tonic-gate 				if (fail_if_new_pwd_reqd) {
1024*0Sstevel@tonic-gate 					(void) snprintf(errstr,
1025*0Sstevel@tonic-gate 						sizeof (errstr),
1026*0Sstevel@tonic-gate 						gettext(
1027*0Sstevel@tonic-gate 						"openConnection: "
1028*0Sstevel@tonic-gate 						"%s bind "
1029*0Sstevel@tonic-gate 						"failed "
1030*0Sstevel@tonic-gate 						"- password "
1031*0Sstevel@tonic-gate 						"expired. It "
1032*0Sstevel@tonic-gate 						" needs to change "
1033*0Sstevel@tonic-gate 						"immediately!"),
1034*0Sstevel@tonic-gate 						bind_type);
1035*0Sstevel@tonic-gate 					MKERROR_PWD_MGMT(*errorp,
1036*0Sstevel@tonic-gate 						LDAP_SUCCESS,
1037*0Sstevel@tonic-gate 						strdup(errstr),
1038*0Sstevel@tonic-gate 						pwd_status,
1039*0Sstevel@tonic-gate 						0,
1040*0Sstevel@tonic-gate 						NULL);
1041*0Sstevel@tonic-gate 					exit_rc = NS_LDAP_INTERNAL;
1042*0Sstevel@tonic-gate 				} else {
1043*0Sstevel@tonic-gate 					MKERROR_PWD_MGMT(*errorp,
1044*0Sstevel@tonic-gate 						LDAP_SUCCESS,
1045*0Sstevel@tonic-gate 						NULL,
1046*0Sstevel@tonic-gate 						pwd_status,
1047*0Sstevel@tonic-gate 						0,
1048*0Sstevel@tonic-gate 						NULL);
1049*0Sstevel@tonic-gate 					exit_rc =
1050*0Sstevel@tonic-gate 					NS_LDAP_SUCCESS_WITH_INFO;
1051*0Sstevel@tonic-gate 				}
1052*0Sstevel@tonic-gate 				break;
1053*0Sstevel@tonic-gate 			} else if (strcmp((*ctrl)->ldctl_oid,
1054*0Sstevel@tonic-gate 				LDAP_CONTROL_PWEXPIRING) == 0) {
1055*0Sstevel@tonic-gate 				pwd_status =
1056*0Sstevel@tonic-gate 					NS_PASSWD_ABOUT_TO_EXPIRE;
1057*0Sstevel@tonic-gate 				if ((*ctrl)->
1058*0Sstevel@tonic-gate 					ldctl_value.bv_len > 0 &&
1059*0Sstevel@tonic-gate 					(*ctrl)->
1060*0Sstevel@tonic-gate 						ldctl_value.bv_val)
1061*0Sstevel@tonic-gate 					sec_until_exp =
1062*0Sstevel@tonic-gate 						atoi((*ctrl)->
1063*0Sstevel@tonic-gate 						ldctl_value.bv_val);
1064*0Sstevel@tonic-gate 				MKERROR_PWD_MGMT(*errorp,
1065*0Sstevel@tonic-gate 					LDAP_SUCCESS,
1066*0Sstevel@tonic-gate 					NULL,
1067*0Sstevel@tonic-gate 					pwd_status,
1068*0Sstevel@tonic-gate 					sec_until_exp,
1069*0Sstevel@tonic-gate 					NULL);
1070*0Sstevel@tonic-gate 				exit_rc =
1071*0Sstevel@tonic-gate 					NS_LDAP_SUCCESS_WITH_INFO;
1072*0Sstevel@tonic-gate 				break;
1073*0Sstevel@tonic-gate 			}
1074*0Sstevel@tonic-gate 		}
1075*0Sstevel@tonic-gate 	}
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate 	if (controls)
1078*0Sstevel@tonic-gate 		ldap_controls_free(controls);
1079*0Sstevel@tonic-gate 
1080*0Sstevel@tonic-gate 	return (exit_rc);
1081*0Sstevel@tonic-gate }
1082*0Sstevel@tonic-gate 
1083*0Sstevel@tonic-gate static int
1084*0Sstevel@tonic-gate ldap_in_hosts_switch()
1085*0Sstevel@tonic-gate {
1086*0Sstevel@tonic-gate 	enum __nsw_parse_err		pserr;
1087*0Sstevel@tonic-gate 	struct __nsw_switchconfig	*conf;
1088*0Sstevel@tonic-gate 	struct __nsw_lookup		*lkp;
1089*0Sstevel@tonic-gate 	const char			*name;
1090*0Sstevel@tonic-gate 	int				found = 0;
1091*0Sstevel@tonic-gate 
1092*0Sstevel@tonic-gate 	conf = __nsw_getconfig("hosts", &pserr);
1093*0Sstevel@tonic-gate 	if (conf == NULL) {
1094*0Sstevel@tonic-gate 		return (-1);
1095*0Sstevel@tonic-gate 	}
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate 	/* check for skip and count other backends */
1098*0Sstevel@tonic-gate 	for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
1099*0Sstevel@tonic-gate 		name = lkp->service_name;
1100*0Sstevel@tonic-gate 		if (strcmp(name, "ldap") == 0) {
1101*0Sstevel@tonic-gate 			found = 1;
1102*0Sstevel@tonic-gate 			break;
1103*0Sstevel@tonic-gate 		}
1104*0Sstevel@tonic-gate 	}
1105*0Sstevel@tonic-gate 	__nsw_freeconfig(conf);
1106*0Sstevel@tonic-gate 	return (found);
1107*0Sstevel@tonic-gate }
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate static int
1110*0Sstevel@tonic-gate openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
1111*0Sstevel@tonic-gate 	int timeoutSec, ns_ldap_error_t **errorp,
1112*0Sstevel@tonic-gate 	int fail_if_new_pwd_reqd, int passwd_mgmt)
1113*0Sstevel@tonic-gate {
1114*0Sstevel@tonic-gate 	LDAP		*ld = NULL;
1115*0Sstevel@tonic-gate 	char		*binddn, *passwd;
1116*0Sstevel@tonic-gate 	char		*digest_md5_name;
1117*0Sstevel@tonic-gate 	const char	*s;
1118*0Sstevel@tonic-gate 	int		ldapVersion = LDAP_VERSION3;
1119*0Sstevel@tonic-gate 	int		derefOption = LDAP_DEREF_ALWAYS;
1120*0Sstevel@tonic-gate 	int		zero = 0;
1121*0Sstevel@tonic-gate 	int		rc;
1122*0Sstevel@tonic-gate 	char		errstr[MAXERROR];
1123*0Sstevel@tonic-gate 	int		errnum = 0;
1124*0Sstevel@tonic-gate 	LDAPMessage	*resultMsg;
1125*0Sstevel@tonic-gate 	int		msgId;
1126*0Sstevel@tonic-gate 	int		useSSL = 0;
1127*0Sstevel@tonic-gate 	struct timeval	tv;
1128*0Sstevel@tonic-gate 	AuthType_t	bindType;
1129*0Sstevel@tonic-gate 	int		timeoutMilliSec = timeoutSec * 1000;
1130*0Sstevel@tonic-gate 	struct berval	cred;
1131*0Sstevel@tonic-gate 	char		*sslServerAddr;
1132*0Sstevel@tonic-gate 	char		*s1;
1133*0Sstevel@tonic-gate 	char		*errmsg;
1134*0Sstevel@tonic-gate 	LDAPControl	**controls;
1135*0Sstevel@tonic-gate 	int		pwd_rc;
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate 	*errorp = NULL;
1138*0Sstevel@tonic-gate 	*ldp = NULL;
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 	switch (auth->auth.type) {
1141*0Sstevel@tonic-gate 		case NS_LDAP_AUTH_NONE:
1142*0Sstevel@tonic-gate 		case NS_LDAP_AUTH_SIMPLE:
1143*0Sstevel@tonic-gate 		case NS_LDAP_AUTH_SASL:
1144*0Sstevel@tonic-gate 			bindType = auth->auth.type;
1145*0Sstevel@tonic-gate 			break;
1146*0Sstevel@tonic-gate 		case NS_LDAP_AUTH_TLS:
1147*0Sstevel@tonic-gate 			useSSL = 1;
1148*0Sstevel@tonic-gate 			switch (auth->auth.tlstype) {
1149*0Sstevel@tonic-gate 				case NS_LDAP_TLS_NONE:
1150*0Sstevel@tonic-gate 					bindType = NS_LDAP_AUTH_NONE;
1151*0Sstevel@tonic-gate 					break;
1152*0Sstevel@tonic-gate 				case NS_LDAP_TLS_SIMPLE:
1153*0Sstevel@tonic-gate 					bindType = NS_LDAP_AUTH_SIMPLE;
1154*0Sstevel@tonic-gate 					break;
1155*0Sstevel@tonic-gate 				case NS_LDAP_TLS_SASL:
1156*0Sstevel@tonic-gate 					bindType = NS_LDAP_AUTH_SASL;
1157*0Sstevel@tonic-gate 					break;
1158*0Sstevel@tonic-gate 				default:
1159*0Sstevel@tonic-gate 					(void) sprintf(errstr,
1160*0Sstevel@tonic-gate 					gettext("openConnection: unsupported "
1161*0Sstevel@tonic-gate 						"TLS authentication method "
1162*0Sstevel@tonic-gate 						"(%d)"), auth->auth.tlstype);
1163*0Sstevel@tonic-gate 					MKERROR(LOG_WARNING, *errorp,
1164*0Sstevel@tonic-gate 						LDAP_AUTH_METHOD_NOT_SUPPORTED,
1165*0Sstevel@tonic-gate 						strdup(errstr), NULL);
1166*0Sstevel@tonic-gate 					return (NS_LDAP_INTERNAL);
1167*0Sstevel@tonic-gate 			}
1168*0Sstevel@tonic-gate 			break;
1169*0Sstevel@tonic-gate 		default:
1170*0Sstevel@tonic-gate 			(void) sprintf(errstr,
1171*0Sstevel@tonic-gate 				gettext("openConnection: unsupported "
1172*0Sstevel@tonic-gate 				"authentication method (%d)"), auth->auth.type);
1173*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp,
1174*0Sstevel@tonic-gate 				LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
1175*0Sstevel@tonic-gate 				NULL);
1176*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1177*0Sstevel@tonic-gate 	}
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate 	if (useSSL) {
1180*0Sstevel@tonic-gate 		const char	*hostcertpath;
1181*0Sstevel@tonic-gate 		char		*alloc_hcp = NULL;
1182*0Sstevel@tonic-gate #ifdef DEBUG
1183*0Sstevel@tonic-gate 		(void) fprintf(stderr, "+++TLS transport\n");
1184*0Sstevel@tonic-gate #endif /* DEBUG */
1185*0Sstevel@tonic-gate 		hostcertpath = auth->hostcertpath;
1186*0Sstevel@tonic-gate 		if (hostcertpath == NULL) {
1187*0Sstevel@tonic-gate 			alloc_hcp = __s_get_hostcertpath();
1188*0Sstevel@tonic-gate 			hostcertpath = alloc_hcp;
1189*0Sstevel@tonic-gate 		}
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 		if (hostcertpath == NULL)
1192*0Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate 		if ((rc = ldapssl_client_init(hostcertpath, NULL)) < 0) {
1195*0Sstevel@tonic-gate 			if (alloc_hcp)
1196*0Sstevel@tonic-gate 				free(alloc_hcp);
1197*0Sstevel@tonic-gate 			(void) snprintf(errstr, sizeof (errstr),
1198*0Sstevel@tonic-gate 				gettext("openConnection: failed to initialize "
1199*0Sstevel@tonic-gate 				"TLS security (%s)"),
1200*0Sstevel@tonic-gate 				ldapssl_err2string(rc));
1201*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
1202*0Sstevel@tonic-gate 				strdup(errstr), NULL);
1203*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1204*0Sstevel@tonic-gate 		}
1205*0Sstevel@tonic-gate 		if (alloc_hcp)
1206*0Sstevel@tonic-gate 			free(alloc_hcp);
1207*0Sstevel@tonic-gate 
1208*0Sstevel@tonic-gate 		/* determine if the host name contains a port number */
1209*0Sstevel@tonic-gate 		s = strchr(serverAddr, ']');	/* skip over ipv6 addr */
1210*0Sstevel@tonic-gate 		if (s == NULL)
1211*0Sstevel@tonic-gate 			s = serverAddr;
1212*0Sstevel@tonic-gate 		s = strchr(s, ':');
1213*0Sstevel@tonic-gate 		if (s != NULL) {
1214*0Sstevel@tonic-gate 			/*
1215*0Sstevel@tonic-gate 			 * If we do get a port number, we will try stripping
1216*0Sstevel@tonic-gate 			 * it. At present, referrals will always have a
1217*0Sstevel@tonic-gate 			 * port number.
1218*0Sstevel@tonic-gate 			 */
1219*0Sstevel@tonic-gate 			sslServerAddr = strdup(serverAddr);
1220*0Sstevel@tonic-gate 			if (sslServerAddr == NULL)
1221*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
1222*0Sstevel@tonic-gate 			s1 = strrchr(sslServerAddr, ':');
1223*0Sstevel@tonic-gate 			if (s1 != NULL)
1224*0Sstevel@tonic-gate 				*s1 = '\0';
1225*0Sstevel@tonic-gate 			(void) snprintf(errstr, sizeof (errstr),
1226*0Sstevel@tonic-gate 			    gettext("openConnection: cannot use tls with %s. "
1227*0Sstevel@tonic-gate 				"Trying %s"),
1228*0Sstevel@tonic-gate 				serverAddr, sslServerAddr);
1229*0Sstevel@tonic-gate 			syslog(LOG_ERR, "libsldap: %s", errstr);
1230*0Sstevel@tonic-gate 		} else
1231*0Sstevel@tonic-gate 			sslServerAddr = (char *)serverAddr;
1232*0Sstevel@tonic-gate 
1233*0Sstevel@tonic-gate 		ld = ldapssl_init(sslServerAddr, LDAPS_PORT, 1);
1234*0Sstevel@tonic-gate 
1235*0Sstevel@tonic-gate 		if (sslServerAddr != serverAddr)
1236*0Sstevel@tonic-gate 			free(sslServerAddr);
1237*0Sstevel@tonic-gate 
1238*0Sstevel@tonic-gate 		if (ld == NULL ||
1239*0Sstevel@tonic-gate 		    ldapssl_install_gethostbyaddr(ld, "ldap") != 0) {
1240*0Sstevel@tonic-gate 			(void) snprintf(errstr, sizeof (errstr),
1241*0Sstevel@tonic-gate 				gettext("openConnection: failed to connect "
1242*0Sstevel@tonic-gate 				"using TLS (%s)"), strerror(errno));
1243*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
1244*0Sstevel@tonic-gate 				strdup(errstr), NULL);
1245*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1246*0Sstevel@tonic-gate 		}
1247*0Sstevel@tonic-gate 	} else {
1248*0Sstevel@tonic-gate #ifdef DEBUG
1249*0Sstevel@tonic-gate 		(void) fprintf(stderr, "+++Unsecure transport\n");
1250*0Sstevel@tonic-gate #endif /* DEBUG */
1251*0Sstevel@tonic-gate 			/* Warning message IF cannot connect to host(s) */
1252*0Sstevel@tonic-gate 		if ((ld = ldap_init((char *)serverAddr, LDAP_PORT)) == NULL) {
1253*0Sstevel@tonic-gate 			char *p = strerror(errno);
1254*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
1255*0Sstevel@tonic-gate 				strdup(p), NULL);
1256*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1257*0Sstevel@tonic-gate 		} else {
1258*0Sstevel@tonic-gate 			/* check and avoid gethostname recursion */
1259*0Sstevel@tonic-gate 			if (ldap_in_hosts_switch() > 0 &&
1260*0Sstevel@tonic-gate 				! __s_api_isipv4((char *)serverAddr) &&
1261*0Sstevel@tonic-gate 				! __s_api_isipv6((char *)serverAddr)) {
1262*0Sstevel@tonic-gate 				/* host: ldap - found, attempt to recover */
1263*0Sstevel@tonic-gate 				if (ldap_set_option(ld, LDAP_X_OPT_DNS_SKIPDB,
1264*0Sstevel@tonic-gate 						    "ldap") != 0) {
1265*0Sstevel@tonic-gate 					(void) snprintf(errstr, sizeof (errstr),
1266*0Sstevel@tonic-gate 						gettext("openConnection: "
1267*0Sstevel@tonic-gate 						"unrecoverable gethostname "
1268*0Sstevel@tonic-gate 						"recursion detected "
1269*0Sstevel@tonic-gate 						"in /etc/nsswitch.conf"));
1270*0Sstevel@tonic-gate 					MKERROR(LOG_WARNING, *errorp,
1271*0Sstevel@tonic-gate 						LDAP_CONNECT_ERROR,
1272*0Sstevel@tonic-gate 						strdup(errstr), NULL);
1273*0Sstevel@tonic-gate 					(void) ldap_unbind(ld);
1274*0Sstevel@tonic-gate 					return (NS_LDAP_INTERNAL);
1275*0Sstevel@tonic-gate 				}
1276*0Sstevel@tonic-gate 			}
1277*0Sstevel@tonic-gate 		}
1278*0Sstevel@tonic-gate 	}
1279*0Sstevel@tonic-gate 
1280*0Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion);
1281*0Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
1282*0Sstevel@tonic-gate 	/*
1283*0Sstevel@tonic-gate 	 * set LDAP_OPT_REFERRALS to OFF.
1284*0Sstevel@tonic-gate 	 * This library will handle the referral itself
1285*0Sstevel@tonic-gate 	 * based on API flags or configuration file
1286*0Sstevel@tonic-gate 	 * specification. If this option is not set
1287*0Sstevel@tonic-gate 	 * to OFF, libldap will never pass the
1288*0Sstevel@tonic-gate 	 * referral info up to this library
1289*0Sstevel@tonic-gate 	 */
1290*0Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1291*0Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero);
1292*0Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero);
1293*0Sstevel@tonic-gate 	/* setup TCP/IP connect timeout */
1294*0Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT,
1295*0Sstevel@tonic-gate 							&timeoutMilliSec);
1296*0Sstevel@tonic-gate 	/* retry if LDAP I/O was interrupted */
1297*0Sstevel@tonic-gate 	(void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate 	switch (bindType) {
1300*0Sstevel@tonic-gate 	case NS_LDAP_AUTH_NONE:
1301*0Sstevel@tonic-gate #ifdef DEBUG
1302*0Sstevel@tonic-gate 		(void) fprintf(stderr, "+++Anonymous bind\n");
1303*0Sstevel@tonic-gate #endif /* DEBUG */
1304*0Sstevel@tonic-gate 		break;
1305*0Sstevel@tonic-gate 	case NS_LDAP_AUTH_SIMPLE:
1306*0Sstevel@tonic-gate 		binddn = auth->cred.unix_cred.userID;
1307*0Sstevel@tonic-gate 		passwd = auth->cred.unix_cred.passwd;
1308*0Sstevel@tonic-gate 		if (passwd == NULL || *passwd == '\0' ||
1309*0Sstevel@tonic-gate 		    binddn == NULL || *binddn == '\0') {
1310*0Sstevel@tonic-gate 			(void) sprintf(errstr, gettext("openConnection: "
1311*0Sstevel@tonic-gate 				"missing credentials for Simple bind"));
1312*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS,
1313*0Sstevel@tonic-gate 				strdup(errstr), NULL);
1314*0Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1315*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1316*0Sstevel@tonic-gate 		}
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate #ifdef DEBUG
1319*0Sstevel@tonic-gate 		(void) fprintf(stderr, "+++Simple bind\n");
1320*0Sstevel@tonic-gate #endif /* DEBUG */
1321*0Sstevel@tonic-gate 		msgId = ldap_simple_bind(ld, binddn, passwd);
1322*0Sstevel@tonic-gate 
1323*0Sstevel@tonic-gate 		if (msgId == -1) {
1324*0Sstevel@tonic-gate 			(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
1325*0Sstevel@tonic-gate 				(void *)&errnum);
1326*0Sstevel@tonic-gate 			(void) snprintf(errstr, sizeof (errstr),
1327*0Sstevel@tonic-gate 				gettext("openConnection: simple bind failed "
1328*0Sstevel@tonic-gate 				"- %s"), ldap_err2string(errnum));
1329*0Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1330*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
1331*0Sstevel@tonic-gate 				NULL);
1332*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1333*0Sstevel@tonic-gate 		}
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 		tv.tv_sec = timeoutSec;
1336*0Sstevel@tonic-gate 		tv.tv_usec = 0;
1337*0Sstevel@tonic-gate 		rc = ldap_result(ld, msgId, 0, &tv, &resultMsg);
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 		if ((rc == -1) || (rc == 0)) {
1340*0Sstevel@tonic-gate 			(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
1341*0Sstevel@tonic-gate 				(void *)&errnum);
1342*0Sstevel@tonic-gate 			(void) snprintf(errstr, sizeof (errstr),
1343*0Sstevel@tonic-gate 				gettext("openConnection: simple bind failed "
1344*0Sstevel@tonic-gate 				"- %s"), ldap_err2string(errnum));
1345*0Sstevel@tonic-gate 			(void) ldap_msgfree(resultMsg);
1346*0Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1347*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
1348*0Sstevel@tonic-gate 				NULL);
1349*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1350*0Sstevel@tonic-gate 		}
1351*0Sstevel@tonic-gate 
1352*0Sstevel@tonic-gate 		/*
1353*0Sstevel@tonic-gate 		 * get ldaprc, controls, and error msg
1354*0Sstevel@tonic-gate 		 */
1355*0Sstevel@tonic-gate 		rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
1356*0Sstevel@tonic-gate 				&errmsg, NULL, &controls, 1);
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate 		if (rc != LDAP_SUCCESS) {
1359*0Sstevel@tonic-gate 			(void) snprintf(errstr, sizeof (errstr),
1360*0Sstevel@tonic-gate 				gettext("openConnection: simple bind failed "
1361*0Sstevel@tonic-gate 				"- unable to parse result"));
1362*0Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1363*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
1364*0Sstevel@tonic-gate 					strdup(errstr), NULL);
1365*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1366*0Sstevel@tonic-gate 		}
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate 		/* process the password management info, if any */
1369*0Sstevel@tonic-gate 		pwd_rc = process_pwd_mgmt("simple",
1370*0Sstevel@tonic-gate 					errnum, controls, errmsg,
1371*0Sstevel@tonic-gate 					errorp,
1372*0Sstevel@tonic-gate 					fail_if_new_pwd_reqd,
1373*0Sstevel@tonic-gate 					passwd_mgmt);
1374*0Sstevel@tonic-gate 
1375*0Sstevel@tonic-gate 		if (pwd_rc == NS_LDAP_INTERNAL) {
1376*0Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1377*0Sstevel@tonic-gate 			return (pwd_rc);
1378*0Sstevel@tonic-gate 		}
1379*0Sstevel@tonic-gate 
1380*0Sstevel@tonic-gate 		if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) {
1381*0Sstevel@tonic-gate 			*ldp = ld;
1382*0Sstevel@tonic-gate 			return (pwd_rc);
1383*0Sstevel@tonic-gate 		}
1384*0Sstevel@tonic-gate 
1385*0Sstevel@tonic-gate 		break;
1386*0Sstevel@tonic-gate 	case NS_LDAP_AUTH_SASL:
1387*0Sstevel@tonic-gate 		/* We don't support any sasl options yet */
1388*0Sstevel@tonic-gate 		if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE) {
1389*0Sstevel@tonic-gate 			(void) sprintf(errstr,
1390*0Sstevel@tonic-gate 				gettext("openConnection: SASL options are "
1391*0Sstevel@tonic-gate 				"not supported (%d)"), auth->auth.saslopt);
1392*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp,
1393*0Sstevel@tonic-gate 				LDAP_AUTH_METHOD_NOT_SUPPORTED,
1394*0Sstevel@tonic-gate 				strdup(errstr), NULL);
1395*0Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1396*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1397*0Sstevel@tonic-gate 		}
1398*0Sstevel@tonic-gate 		binddn = auth->cred.unix_cred.userID;
1399*0Sstevel@tonic-gate 		passwd = auth->cred.unix_cred.passwd;
1400*0Sstevel@tonic-gate 		if (passwd == NULL || *passwd == '\0' ||
1401*0Sstevel@tonic-gate 		    binddn == NULL || *binddn == '\0') {
1402*0Sstevel@tonic-gate 			(void) sprintf(errstr,
1403*0Sstevel@tonic-gate 				gettext("openConnection: missing credentials "
1404*0Sstevel@tonic-gate 				"for SASL bind"));
1405*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS,
1406*0Sstevel@tonic-gate 				strdup(errstr), NULL);
1407*0Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1408*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1409*0Sstevel@tonic-gate 		}
1410*0Sstevel@tonic-gate 		cred.bv_val = passwd;
1411*0Sstevel@tonic-gate 		cred.bv_len = strlen(passwd);
1412*0Sstevel@tonic-gate 
1413*0Sstevel@tonic-gate 		switch (auth->auth.saslmech) {
1414*0Sstevel@tonic-gate 		case NS_LDAP_SASL_CRAM_MD5:
1415*0Sstevel@tonic-gate 			/*
1416*0Sstevel@tonic-gate 			 * NOTE: if iDS changes to support cram_md5,
1417*0Sstevel@tonic-gate 			 * please add password management code here.
1418*0Sstevel@tonic-gate 			 * Since ldap_sasl_cram_md5_bind_s does not
1419*0Sstevel@tonic-gate 			 * return anything that could be used to
1420*0Sstevel@tonic-gate 			 * extract the ldap rc/errmsg/control to
1421*0Sstevel@tonic-gate 			 * determine if bind failed due to password
1422*0Sstevel@tonic-gate 			 * policy, a new cram_md5_bind API will need
1423*0Sstevel@tonic-gate 			 * to be introduced. See
1424*0Sstevel@tonic-gate 			 * ldap_x_sasl_digest_md5_bind() and case
1425*0Sstevel@tonic-gate 			 * NS_LDAP_SASL_DIGEST_MD5 below for details.
1426*0Sstevel@tonic-gate 			 */
1427*0Sstevel@tonic-gate 			if ((rc = ldap_sasl_cram_md5_bind_s(ld, binddn,
1428*0Sstevel@tonic-gate 				&cred, NULL, NULL)) != LDAP_SUCCESS) {
1429*0Sstevel@tonic-gate 				(void) ldap_get_option(ld,
1430*0Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
1431*0Sstevel@tonic-gate 				(void) snprintf(errstr, sizeof (errstr),
1432*0Sstevel@tonic-gate 					gettext("openConnection: "
1433*0Sstevel@tonic-gate 					"sasl/CRAM-MD5 bind failed - %s"),
1434*0Sstevel@tonic-gate 					ldap_err2string(errnum));
1435*0Sstevel@tonic-gate 				MKERROR(LOG_WARNING, *errorp, errnum,
1436*0Sstevel@tonic-gate 					strdup(errstr), NULL);
1437*0Sstevel@tonic-gate 				(void) ldap_unbind(ld);
1438*0Sstevel@tonic-gate 				return (NS_LDAP_INTERNAL);
1439*0Sstevel@tonic-gate 			}
1440*0Sstevel@tonic-gate 			break;
1441*0Sstevel@tonic-gate 		case NS_LDAP_SASL_DIGEST_MD5:
1442*0Sstevel@tonic-gate 			digest_md5_name = malloc(strlen(binddn) + 5);
1443*0Sstevel@tonic-gate 			/* 5 = strlen("dn: ") + 1 */
1444*0Sstevel@tonic-gate 			if (digest_md5_name == NULL) {
1445*0Sstevel@tonic-gate 				(void) ldap_unbind(ld);
1446*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
1447*0Sstevel@tonic-gate 			}
1448*0Sstevel@tonic-gate 			(void) strcpy(digest_md5_name, "dn: ");
1449*0Sstevel@tonic-gate 			(void) strcat(digest_md5_name, binddn);
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 			tv.tv_sec = timeoutSec;
1452*0Sstevel@tonic-gate 			tv.tv_usec = 0;
1453*0Sstevel@tonic-gate 			rc = ldap_x_sasl_digest_md5_bind(ld,
1454*0Sstevel@tonic-gate 				digest_md5_name, &cred, NULL, NULL,
1455*0Sstevel@tonic-gate 				&tv, &resultMsg);
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate 			if (resultMsg == NULL) {
1458*0Sstevel@tonic-gate 				free(digest_md5_name);
1459*0Sstevel@tonic-gate 				(void) ldap_get_option(ld,
1460*0Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
1461*0Sstevel@tonic-gate 				(void) snprintf(errstr, sizeof (errstr),
1462*0Sstevel@tonic-gate 					gettext("openConnection: "
1463*0Sstevel@tonic-gate 					"DIGEST-MD5 bind failed - %s"),
1464*0Sstevel@tonic-gate 					ldap_err2string(errnum));
1465*0Sstevel@tonic-gate 				(void) ldap_unbind(ld);
1466*0Sstevel@tonic-gate 				MKERROR(LOG_WARNING, *errorp, errnum,
1467*0Sstevel@tonic-gate 						strdup(errstr), NULL);
1468*0Sstevel@tonic-gate 				return (NS_LDAP_INTERNAL);
1469*0Sstevel@tonic-gate 			}
1470*0Sstevel@tonic-gate 
1471*0Sstevel@tonic-gate 			/*
1472*0Sstevel@tonic-gate 			 * get ldaprc, controls, and error msg
1473*0Sstevel@tonic-gate 			 */
1474*0Sstevel@tonic-gate 			rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
1475*0Sstevel@tonic-gate 				&errmsg, NULL, &controls, 1);
1476*0Sstevel@tonic-gate 
1477*0Sstevel@tonic-gate 			if (rc != LDAP_SUCCESS) {
1478*0Sstevel@tonic-gate 				free(digest_md5_name);
1479*0Sstevel@tonic-gate 				(void) snprintf(errstr, sizeof (errstr),
1480*0Sstevel@tonic-gate 					gettext("openConnection: "
1481*0Sstevel@tonic-gate 					"DIGEST-MD5 bind failed "
1482*0Sstevel@tonic-gate 					"- unable to parse result"));
1483*0Sstevel@tonic-gate 				(void) ldap_unbind(ld);
1484*0Sstevel@tonic-gate 				MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
1485*0Sstevel@tonic-gate 						strdup(errstr), NULL);
1486*0Sstevel@tonic-gate 				return (NS_LDAP_INTERNAL);
1487*0Sstevel@tonic-gate 			}
1488*0Sstevel@tonic-gate 
1489*0Sstevel@tonic-gate 			/* process the password management info, if any */
1490*0Sstevel@tonic-gate 			pwd_rc = process_pwd_mgmt("sasl/DIGEST-MD5",
1491*0Sstevel@tonic-gate 						errnum, controls, errmsg,
1492*0Sstevel@tonic-gate 						errorp,
1493*0Sstevel@tonic-gate 						fail_if_new_pwd_reqd,
1494*0Sstevel@tonic-gate 						passwd_mgmt);
1495*0Sstevel@tonic-gate 
1496*0Sstevel@tonic-gate 			if (pwd_rc == NS_LDAP_INTERNAL) {
1497*0Sstevel@tonic-gate 				free(digest_md5_name);
1498*0Sstevel@tonic-gate 				(void) ldap_unbind(ld);
1499*0Sstevel@tonic-gate 				return (pwd_rc);
1500*0Sstevel@tonic-gate 			}
1501*0Sstevel@tonic-gate 
1502*0Sstevel@tonic-gate 			if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) {
1503*0Sstevel@tonic-gate 				*ldp = ld;
1504*0Sstevel@tonic-gate 				return (pwd_rc);
1505*0Sstevel@tonic-gate 			}
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 			free(digest_md5_name);
1508*0Sstevel@tonic-gate 			break;
1509*0Sstevel@tonic-gate 		default:
1510*0Sstevel@tonic-gate 			(void) ldap_unbind(ld);
1511*0Sstevel@tonic-gate 			(void) sprintf(errstr,
1512*0Sstevel@tonic-gate 				gettext("openConnection: unsupported SASL "
1513*0Sstevel@tonic-gate 				"mechanism (%d)"), auth->auth.saslmech);
1514*0Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp,
1515*0Sstevel@tonic-gate 				LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
1516*0Sstevel@tonic-gate 				NULL);
1517*0Sstevel@tonic-gate 			return (NS_LDAP_INTERNAL);
1518*0Sstevel@tonic-gate 		}
1519*0Sstevel@tonic-gate 	}
1520*0Sstevel@tonic-gate 
1521*0Sstevel@tonic-gate 	*ldp = ld;
1522*0Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
1523*0Sstevel@tonic-gate }
1524*0Sstevel@tonic-gate 
1525*0Sstevel@tonic-gate /*
1526*0Sstevel@tonic-gate  * FUNCTION:	__s_api_getDefaultAuth
1527*0Sstevel@tonic-gate  *
1528*0Sstevel@tonic-gate  *	Constructs a credential for authentication using the config module.
1529*0Sstevel@tonic-gate  *
1530*0Sstevel@tonic-gate  * RETURN VALUES:
1531*0Sstevel@tonic-gate  *
1532*0Sstevel@tonic-gate  * NS_LDAP_SUCCESS	If successful
1533*0Sstevel@tonic-gate  * NS_LDAP_CONFIG	If there are any config errors.
1534*0Sstevel@tonic-gate  * NS_LDAP_MEMORY	Memory errors.
1535*0Sstevel@tonic-gate  * NS_LDAP_OP_FAILED	If there are no more authentication methods so can
1536*0Sstevel@tonic-gate  *			not build a new authp.
1537*0Sstevel@tonic-gate  * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the
1538*0Sstevel@tonic-gate  *			necessary fields of a cred for a given auth method
1539*0Sstevel@tonic-gate  *			are not provided.
1540*0Sstevel@tonic-gate  * INPUT:
1541*0Sstevel@tonic-gate  *
1542*0Sstevel@tonic-gate  * cLevel	Currently requested credential level to be tried
1543*0Sstevel@tonic-gate  *
1544*0Sstevel@tonic-gate  * aMethod	Currently requested authentication method to be tried
1545*0Sstevel@tonic-gate  *
1546*0Sstevel@tonic-gate  * OUTPUT:
1547*0Sstevel@tonic-gate  *
1548*0Sstevel@tonic-gate  * authp		authentication method to use.
1549*0Sstevel@tonic-gate  */
1550*0Sstevel@tonic-gate static int
1551*0Sstevel@tonic-gate __s_api_getDefaultAuth(
1552*0Sstevel@tonic-gate 	int	*cLevel,
1553*0Sstevel@tonic-gate 	ns_auth_t *aMethod,
1554*0Sstevel@tonic-gate 	ns_cred_t **authp)
1555*0Sstevel@tonic-gate {
1556*0Sstevel@tonic-gate 	void		**paramVal = NULL;
1557*0Sstevel@tonic-gate 	char		*modparamVal = NULL;
1558*0Sstevel@tonic-gate 	int		getUid = 0;
1559*0Sstevel@tonic-gate 	int		getPasswd = 0;
1560*0Sstevel@tonic-gate 	int		getCertpath = 0;
1561*0Sstevel@tonic-gate 	int		rc = 0;
1562*0Sstevel@tonic-gate 	ns_ldap_error_t	*errorp = NULL;
1563*0Sstevel@tonic-gate 
1564*0Sstevel@tonic-gate #ifdef DEBUG
1565*0Sstevel@tonic-gate 	(void) fprintf(stderr, "__s_api_getDefaultAuth START\n");
1566*0Sstevel@tonic-gate #endif
1567*0Sstevel@tonic-gate 
1568*0Sstevel@tonic-gate 	if (aMethod == NULL) {
1569*0Sstevel@tonic-gate 		/* Require an Auth */
1570*0Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
1571*0Sstevel@tonic-gate 
1572*0Sstevel@tonic-gate 	}
1573*0Sstevel@tonic-gate 
1574*0Sstevel@tonic-gate 	/*
1575*0Sstevel@tonic-gate 	 * Do not differentiate between (proxy/self) at this time, but
1576*0Sstevel@tonic-gate 	 * reject self credential levels at this time
1577*0Sstevel@tonic-gate 	 */
1578*0Sstevel@tonic-gate 	if (cLevel && *cLevel == NS_LDAP_CRED_SELF)
1579*0Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
1580*0Sstevel@tonic-gate 
1581*0Sstevel@tonic-gate 	*authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
1582*0Sstevel@tonic-gate 	if ((*authp) == NULL)
1583*0Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate 	(*authp)->auth = *aMethod;
1586*0Sstevel@tonic-gate 
1587*0Sstevel@tonic-gate 	switch (aMethod->type) {
1588*0Sstevel@tonic-gate 		case NS_LDAP_AUTH_NONE:
1589*0Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
1590*0Sstevel@tonic-gate 		case NS_LDAP_AUTH_SIMPLE:
1591*0Sstevel@tonic-gate 			getUid++;
1592*0Sstevel@tonic-gate 			getPasswd++;
1593*0Sstevel@tonic-gate 			break;
1594*0Sstevel@tonic-gate 		case NS_LDAP_AUTH_SASL:
1595*0Sstevel@tonic-gate 			if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
1596*0Sstevel@tonic-gate 			    (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) {
1597*0Sstevel@tonic-gate 				getUid++;
1598*0Sstevel@tonic-gate 				getPasswd++;
1599*0Sstevel@tonic-gate 			} else {
1600*0Sstevel@tonic-gate 				(void) __ns_ldap_freeCred(authp);
1601*0Sstevel@tonic-gate 				*authp = NULL;
1602*0Sstevel@tonic-gate 				return (NS_LDAP_INVALID_PARAM);
1603*0Sstevel@tonic-gate 			}
1604*0Sstevel@tonic-gate 			break;
1605*0Sstevel@tonic-gate 		case NS_LDAP_AUTH_TLS:
1606*0Sstevel@tonic-gate 			if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) ||
1607*0Sstevel@tonic-gate 			    ((aMethod->tlstype == NS_LDAP_TLS_SASL) &&
1608*0Sstevel@tonic-gate 			    ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
1609*0Sstevel@tonic-gate 			    (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) {
1610*0Sstevel@tonic-gate 				getUid++;
1611*0Sstevel@tonic-gate 				getPasswd++;
1612*0Sstevel@tonic-gate 				getCertpath++;
1613*0Sstevel@tonic-gate 			} else if (aMethod->tlstype == NS_LDAP_TLS_NONE) {
1614*0Sstevel@tonic-gate 				getCertpath++;
1615*0Sstevel@tonic-gate 			} else {
1616*0Sstevel@tonic-gate 				(void) __ns_ldap_freeCred(authp);
1617*0Sstevel@tonic-gate 				*authp = NULL;
1618*0Sstevel@tonic-gate 				return (NS_LDAP_INVALID_PARAM);
1619*0Sstevel@tonic-gate 			}
1620*0Sstevel@tonic-gate 			break;
1621*0Sstevel@tonic-gate 	}
1622*0Sstevel@tonic-gate 
1623*0Sstevel@tonic-gate 	if (getUid) {
1624*0Sstevel@tonic-gate 		paramVal = NULL;
1625*0Sstevel@tonic-gate 		if ((rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P,
1626*0Sstevel@tonic-gate 			&paramVal, &errorp)) != NS_LDAP_SUCCESS) {
1627*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1628*0Sstevel@tonic-gate 			(void) __ns_ldap_freeError(&errorp);
1629*0Sstevel@tonic-gate 			*authp = NULL;
1630*0Sstevel@tonic-gate 			return (rc);
1631*0Sstevel@tonic-gate 		}
1632*0Sstevel@tonic-gate 
1633*0Sstevel@tonic-gate 		if (paramVal == NULL || *paramVal == NULL) {
1634*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1635*0Sstevel@tonic-gate 			*authp = NULL;
1636*0Sstevel@tonic-gate 			return (NS_LDAP_INVALID_PARAM);
1637*0Sstevel@tonic-gate 		}
1638*0Sstevel@tonic-gate 
1639*0Sstevel@tonic-gate 		(*authp)->cred.unix_cred.userID = strdup((char *)*paramVal);
1640*0Sstevel@tonic-gate 		(void) __ns_ldap_freeParam(&paramVal);
1641*0Sstevel@tonic-gate 		if ((*authp)->cred.unix_cred.userID == NULL) {
1642*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1643*0Sstevel@tonic-gate 			*authp = NULL;
1644*0Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
1645*0Sstevel@tonic-gate 		}
1646*0Sstevel@tonic-gate 	}
1647*0Sstevel@tonic-gate 	if (getPasswd) {
1648*0Sstevel@tonic-gate 		paramVal = NULL;
1649*0Sstevel@tonic-gate 		if ((rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P,
1650*0Sstevel@tonic-gate 			&paramVal, &errorp)) != NS_LDAP_SUCCESS) {
1651*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1652*0Sstevel@tonic-gate 			(void) __ns_ldap_freeError(&errorp);
1653*0Sstevel@tonic-gate 			*authp = NULL;
1654*0Sstevel@tonic-gate 			return (rc);
1655*0Sstevel@tonic-gate 		}
1656*0Sstevel@tonic-gate 
1657*0Sstevel@tonic-gate 		if (paramVal == NULL || *paramVal == NULL) {
1658*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1659*0Sstevel@tonic-gate 			*authp = NULL;
1660*0Sstevel@tonic-gate 			return (NS_LDAP_INVALID_PARAM);
1661*0Sstevel@tonic-gate 		}
1662*0Sstevel@tonic-gate 
1663*0Sstevel@tonic-gate 		modparamVal = dvalue((char *)*paramVal);
1664*0Sstevel@tonic-gate 		(void) __ns_ldap_freeParam(&paramVal);
1665*0Sstevel@tonic-gate 		if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) {
1666*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1667*0Sstevel@tonic-gate 			if (modparamVal != NULL)
1668*0Sstevel@tonic-gate 				free(modparamVal);
1669*0Sstevel@tonic-gate 			*authp = NULL;
1670*0Sstevel@tonic-gate 			return (NS_LDAP_INVALID_PARAM);
1671*0Sstevel@tonic-gate 		}
1672*0Sstevel@tonic-gate 
1673*0Sstevel@tonic-gate 		(*authp)->cred.unix_cred.passwd = modparamVal;
1674*0Sstevel@tonic-gate 	}
1675*0Sstevel@tonic-gate 	if (getCertpath) {
1676*0Sstevel@tonic-gate 		paramVal = NULL;
1677*0Sstevel@tonic-gate 		if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
1678*0Sstevel@tonic-gate 			&paramVal, &errorp)) != NS_LDAP_SUCCESS) {
1679*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1680*0Sstevel@tonic-gate 			(void) __ns_ldap_freeError(&errorp);
1681*0Sstevel@tonic-gate 			*authp = NULL;
1682*0Sstevel@tonic-gate 			return (rc);
1683*0Sstevel@tonic-gate 		}
1684*0Sstevel@tonic-gate 
1685*0Sstevel@tonic-gate 		if (paramVal == NULL || *paramVal == NULL) {
1686*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1687*0Sstevel@tonic-gate 			*authp = NULL;
1688*0Sstevel@tonic-gate 			return (NS_LDAP_INVALID_PARAM);
1689*0Sstevel@tonic-gate 		}
1690*0Sstevel@tonic-gate 
1691*0Sstevel@tonic-gate 		(*authp)->hostcertpath = strdup((char *)*paramVal);
1692*0Sstevel@tonic-gate 		(void) __ns_ldap_freeParam(&paramVal);
1693*0Sstevel@tonic-gate 		if ((*authp)->hostcertpath == NULL) {
1694*0Sstevel@tonic-gate 			(void) __ns_ldap_freeCred(authp);
1695*0Sstevel@tonic-gate 			*authp = NULL;
1696*0Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
1697*0Sstevel@tonic-gate 		}
1698*0Sstevel@tonic-gate 	}
1699*0Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
1700*0Sstevel@tonic-gate }
1701*0Sstevel@tonic-gate 
1702*0Sstevel@tonic-gate /*
1703*0Sstevel@tonic-gate  * FUNCTION:	__s_api_getConnection
1704*0Sstevel@tonic-gate  *
1705*0Sstevel@tonic-gate  *	Bind to the specified server or one from the server
1706*0Sstevel@tonic-gate  *	list and return the pointer.
1707*0Sstevel@tonic-gate  *
1708*0Sstevel@tonic-gate  *	This function can rebind or not (NS_LDAP_HARD), it can require a
1709*0Sstevel@tonic-gate  *	credential or bind anonymously
1710*0Sstevel@tonic-gate  *
1711*0Sstevel@tonic-gate  *	This function follows the DUA configuration schema algorithm
1712*0Sstevel@tonic-gate  *
1713*0Sstevel@tonic-gate  * RETURN VALUES:
1714*0Sstevel@tonic-gate  *
1715*0Sstevel@tonic-gate  * NS_LDAP_SUCCESS	A connection was made successfully.
1716*0Sstevel@tonic-gate  * NS_LDAP_SUCCESS_WITH_INFO
1717*0Sstevel@tonic-gate  * 			A connection was made successfully, but with
1718*0Sstevel@tonic-gate  *			password management info in *errorp
1719*0Sstevel@tonic-gate  * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function.
1720*0Sstevel@tonic-gate  * NS_LDAP_CONFIG	If there are any config errors.
1721*0Sstevel@tonic-gate  * NS_LDAP_MEMORY	Memory errors.
1722*0Sstevel@tonic-gate  * NS_LDAP_INTERNAL	If there was a ldap error.
1723*0Sstevel@tonic-gate  *
1724*0Sstevel@tonic-gate  * INPUT:
1725*0Sstevel@tonic-gate  *
1726*0Sstevel@tonic-gate  * server	Bind to this LDAP server only
1727*0Sstevel@tonic-gate  * flags	If NS_LDAP_HARD is set function will not return until it has
1728*0Sstevel@tonic-gate  *		a connection unless there is a authentication problem.
1729*0Sstevel@tonic-gate  *		If NS_LDAP_NEW_CONN is set the function must force a new
1730*0Sstevel@tonic-gate  *              connection to be created
1731*0Sstevel@tonic-gate  *		If NS_LDAP_KEEP_CONN is set the connection is to be kept open
1732*0Sstevel@tonic-gate  * auth		Credentials for bind. This could be NULL in which case
1733*0Sstevel@tonic-gate  *		a default cred built from the config module is used.
1734*0Sstevel@tonic-gate  * sessionId	cookie that points to a previous session
1735*0Sstevel@tonic-gate  * fail_if_new_pwd_reqd
1736*0Sstevel@tonic-gate  *		a flag indicating this function should fail if the passwd
1737*0Sstevel@tonic-gate  *		in auth needs to change immediately
1738*0Sstevel@tonic-gate  *
1739*0Sstevel@tonic-gate  * OUTPUT:
1740*0Sstevel@tonic-gate  *
1741*0Sstevel@tonic-gate  * session	pointer to a session with connection information
1742*0Sstevel@tonic-gate  * errorp	Set if there are any INTERNAL, or CONFIG error.
1743*0Sstevel@tonic-gate  */
1744*0Sstevel@tonic-gate int
1745*0Sstevel@tonic-gate __s_api_getConnection(
1746*0Sstevel@tonic-gate 	const char *server,
1747*0Sstevel@tonic-gate 	const int flags,
1748*0Sstevel@tonic-gate 	const ns_cred_t *cred,		/* credentials for bind */
1749*0Sstevel@tonic-gate 	ConnectionID *sessionId,
1750*0Sstevel@tonic-gate 	Connection **session,
1751*0Sstevel@tonic-gate 	ns_ldap_error_t **errorp,
1752*0Sstevel@tonic-gate 	int fail_if_new_pwd_reqd)
1753*0Sstevel@tonic-gate {
1754*0Sstevel@tonic-gate 	char		errmsg[MAXERROR];
1755*0Sstevel@tonic-gate 	ns_auth_t	**aMethod = NULL;
1756*0Sstevel@tonic-gate 	ns_auth_t	**aNext = NULL;
1757*0Sstevel@tonic-gate 	int		**cLevel = NULL;
1758*0Sstevel@tonic-gate 	int		**cNext = NULL;
1759*0Sstevel@tonic-gate 	int		timeoutSec = NS_DEFAULT_BIND_TIMEOUT;
1760*0Sstevel@tonic-gate 	int		rc;
1761*0Sstevel@tonic-gate 	Connection	*con = NULL;
1762*0Sstevel@tonic-gate 	int		sec = 1;
1763*0Sstevel@tonic-gate 	ns_cred_t 	*authp = NULL;
1764*0Sstevel@tonic-gate 	ns_cred_t	anon;
1765*0Sstevel@tonic-gate 	int		version = NS_LDAP_V2;
1766*0Sstevel@tonic-gate 	void		**paramVal = NULL;
1767*0Sstevel@tonic-gate 
1768*0Sstevel@tonic-gate 	if ((session == NULL) || (sessionId == NULL)) {
1769*0Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
1770*0Sstevel@tonic-gate 	}
1771*0Sstevel@tonic-gate 	*session = NULL;
1772*0Sstevel@tonic-gate 
1773*0Sstevel@tonic-gate 	/* if we already have a session id try to reuse connection */
1774*0Sstevel@tonic-gate 	if (*sessionId > 0) {
1775*0Sstevel@tonic-gate 		rc = findConnectionById(flags, cred, *sessionId, &con);
1776*0Sstevel@tonic-gate 		if (rc == *sessionId && con) {
1777*0Sstevel@tonic-gate 			*session = con;
1778*0Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
1779*0Sstevel@tonic-gate 		}
1780*0Sstevel@tonic-gate 		*sessionId = 0;
1781*0Sstevel@tonic-gate 	}
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate 	/* get profile version number */
1784*0Sstevel@tonic-gate 	if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P,
1785*0Sstevel@tonic-gate 			&paramVal, errorp)) != NS_LDAP_SUCCESS)
1786*0Sstevel@tonic-gate 		return (rc);
1787*0Sstevel@tonic-gate 	if (paramVal == NULL) {
1788*0Sstevel@tonic-gate 		(void) sprintf(errmsg, gettext("getConnection: no file "
1789*0Sstevel@tonic-gate 			"version"));
1790*0Sstevel@tonic-gate 		MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg),
1791*0Sstevel@tonic-gate 			NS_LDAP_CONFIG);
1792*0Sstevel@tonic-gate 		return (NS_LDAP_CONFIG);
1793*0Sstevel@tonic-gate 	}
1794*0Sstevel@tonic-gate 	if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0)
1795*0Sstevel@tonic-gate 		version = NS_LDAP_V1;
1796*0Sstevel@tonic-gate 	(void) __ns_ldap_freeParam((void ***)&paramVal);
1797*0Sstevel@tonic-gate 
1798*0Sstevel@tonic-gate 	/* Get the bind timeout value */
1799*0Sstevel@tonic-gate 	(void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, &paramVal, errorp);
1800*0Sstevel@tonic-gate 	if (paramVal != NULL && *paramVal != NULL) {
1801*0Sstevel@tonic-gate 		timeoutSec = **((int **)paramVal);
1802*0Sstevel@tonic-gate 		(void) __ns_ldap_freeParam(&paramVal);
1803*0Sstevel@tonic-gate 	}
1804*0Sstevel@tonic-gate 	if (*errorp)
1805*0Sstevel@tonic-gate 		(void) __ns_ldap_freeError(errorp);
1806*0Sstevel@tonic-gate 
1807*0Sstevel@tonic-gate 	if (cred == NULL) {
1808*0Sstevel@tonic-gate 		/* Get the authentication method list */
1809*0Sstevel@tonic-gate 		if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P,
1810*0Sstevel@tonic-gate 			(void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS)
1811*0Sstevel@tonic-gate 			return (rc);
1812*0Sstevel@tonic-gate 		if (aMethod == NULL) {
1813*0Sstevel@tonic-gate 			aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *));
1814*0Sstevel@tonic-gate 			if (aMethod == NULL)
1815*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
1816*0Sstevel@tonic-gate 			aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t));
1817*0Sstevel@tonic-gate 			if (aMethod[0] == NULL) {
1818*0Sstevel@tonic-gate 				free(aMethod);
1819*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
1820*0Sstevel@tonic-gate 			}
1821*0Sstevel@tonic-gate 			if (version == NS_LDAP_V1)
1822*0Sstevel@tonic-gate 				(aMethod[0])->type = NS_LDAP_AUTH_SIMPLE;
1823*0Sstevel@tonic-gate 			else {
1824*0Sstevel@tonic-gate 				(aMethod[0])->type = NS_LDAP_AUTH_SASL;
1825*0Sstevel@tonic-gate 				(aMethod[0])->saslmech =
1826*0Sstevel@tonic-gate 					NS_LDAP_SASL_DIGEST_MD5;
1827*0Sstevel@tonic-gate 				(aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE;
1828*0Sstevel@tonic-gate 			}
1829*0Sstevel@tonic-gate 		}
1830*0Sstevel@tonic-gate 
1831*0Sstevel@tonic-gate 		/* Get the credential level list */
1832*0Sstevel@tonic-gate 		if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
1833*0Sstevel@tonic-gate 			(void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) {
1834*0Sstevel@tonic-gate 			(void) __ns_ldap_freeParam((void ***)&aMethod);
1835*0Sstevel@tonic-gate 			return (rc);
1836*0Sstevel@tonic-gate 		}
1837*0Sstevel@tonic-gate 		if (cLevel == NULL) {
1838*0Sstevel@tonic-gate 			cLevel = (int **)calloc(2, sizeof (int *));
1839*0Sstevel@tonic-gate 			if (cLevel == NULL)
1840*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
1841*0Sstevel@tonic-gate 			cLevel[0] = (int *)calloc(1, sizeof (int));
1842*0Sstevel@tonic-gate 			if (cLevel[0] == NULL)
1843*0Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
1844*0Sstevel@tonic-gate 			if (version == NS_LDAP_V1)
1845*0Sstevel@tonic-gate 				*(cLevel[0]) = NS_LDAP_CRED_PROXY;
1846*0Sstevel@tonic-gate 			else
1847*0Sstevel@tonic-gate 				*(cLevel[0]) = NS_LDAP_CRED_ANON;
1848*0Sstevel@tonic-gate 		}
1849*0Sstevel@tonic-gate 	}
1850*0Sstevel@tonic-gate 
1851*0Sstevel@tonic-gate 	/* setup the anon credential for anonymous connection */
1852*0Sstevel@tonic-gate 	(void) memset(&anon, 0, sizeof (ns_cred_t));
1853*0Sstevel@tonic-gate 	anon.auth.type = NS_LDAP_AUTH_NONE;
1854*0Sstevel@tonic-gate 
1855*0Sstevel@tonic-gate 	for (; ; ) {
1856*0Sstevel@tonic-gate 		if (cred != NULL) {
1857*0Sstevel@tonic-gate 			/* using specified auth method */
1858*0Sstevel@tonic-gate 			rc = makeConnection(&con, server, cred,
1859*0Sstevel@tonic-gate 				sessionId, timeoutSec, errorp,
1860*0Sstevel@tonic-gate 				fail_if_new_pwd_reqd);
1861*0Sstevel@tonic-gate 			if (rc == NS_LDAP_SUCCESS ||
1862*0Sstevel@tonic-gate 				rc == NS_LDAP_SUCCESS_WITH_INFO) {
1863*0Sstevel@tonic-gate 				*session = con;
1864*0Sstevel@tonic-gate 				break;
1865*0Sstevel@tonic-gate 			}
1866*0Sstevel@tonic-gate 		} else {
1867*0Sstevel@tonic-gate 			/* for every cred level */
1868*0Sstevel@tonic-gate 			for (cNext = cLevel; *cNext != NULL; cNext++) {
1869*0Sstevel@tonic-gate 				if (**cNext == NS_LDAP_CRED_ANON) {
1870*0Sstevel@tonic-gate 					/* make connection anonymously */
1871*0Sstevel@tonic-gate 					rc = makeConnection(&con, server, &anon,
1872*0Sstevel@tonic-gate 						sessionId, timeoutSec, errorp,
1873*0Sstevel@tonic-gate 						fail_if_new_pwd_reqd);
1874*0Sstevel@tonic-gate 					if (rc == NS_LDAP_SUCCESS ||
1875*0Sstevel@tonic-gate 						rc ==
1876*0Sstevel@tonic-gate 						NS_LDAP_SUCCESS_WITH_INFO) {
1877*0Sstevel@tonic-gate 						*session = con;
1878*0Sstevel@tonic-gate 						goto done;
1879*0Sstevel@tonic-gate 					}
1880*0Sstevel@tonic-gate 					continue;
1881*0Sstevel@tonic-gate 				}
1882*0Sstevel@tonic-gate 				/* for each cred level */
1883*0Sstevel@tonic-gate 				for (aNext = aMethod; *aNext != NULL; aNext++) {
1884*0Sstevel@tonic-gate 					/* make connection and authenticate */
1885*0Sstevel@tonic-gate 					/* with default credentials */
1886*0Sstevel@tonic-gate 					authp = NULL;
1887*0Sstevel@tonic-gate 					rc = __s_api_getDefaultAuth(*cNext,
1888*0Sstevel@tonic-gate 						*aNext, &authp);
1889*0Sstevel@tonic-gate 					if (rc != NS_LDAP_SUCCESS) {
1890*0Sstevel@tonic-gate 						continue;
1891*0Sstevel@tonic-gate 					}
1892*0Sstevel@tonic-gate 					rc = makeConnection(&con, server, authp,
1893*0Sstevel@tonic-gate 						sessionId, timeoutSec, errorp,
1894*0Sstevel@tonic-gate 						fail_if_new_pwd_reqd);
1895*0Sstevel@tonic-gate 					(void) __ns_ldap_freeCred(&authp);
1896*0Sstevel@tonic-gate 					if (rc == NS_LDAP_SUCCESS ||
1897*0Sstevel@tonic-gate 						rc ==
1898*0Sstevel@tonic-gate 						NS_LDAP_SUCCESS_WITH_INFO) {
1899*0Sstevel@tonic-gate 						*session = con;
1900*0Sstevel@tonic-gate 						goto done;
1901*0Sstevel@tonic-gate 					}
1902*0Sstevel@tonic-gate 				}
1903*0Sstevel@tonic-gate 			}
1904*0Sstevel@tonic-gate 		}
1905*0Sstevel@tonic-gate 		if (flags & NS_LDAP_HARD) {
1906*0Sstevel@tonic-gate 			if (sec < LDAPMAXHARDLOOKUPTIME)
1907*0Sstevel@tonic-gate 				sec *= 2;
1908*0Sstevel@tonic-gate 			_sleep(sec);
1909*0Sstevel@tonic-gate 		} else {
1910*0Sstevel@tonic-gate 			break;
1911*0Sstevel@tonic-gate 		}
1912*0Sstevel@tonic-gate 	}
1913*0Sstevel@tonic-gate 
1914*0Sstevel@tonic-gate done:
1915*0Sstevel@tonic-gate 	(void) __ns_ldap_freeParam((void ***)&aMethod);
1916*0Sstevel@tonic-gate 	(void) __ns_ldap_freeParam((void ***)&cLevel);
1917*0Sstevel@tonic-gate 	return (rc);
1918*0Sstevel@tonic-gate }
1919*0Sstevel@tonic-gate 
1920*0Sstevel@tonic-gate #pragma fini(_free_sessionPool)
1921*0Sstevel@tonic-gate static void
1922*0Sstevel@tonic-gate _free_sessionPool()
1923*0Sstevel@tonic-gate {
1924*0Sstevel@tonic-gate 	int id;
1925*0Sstevel@tonic-gate 
1926*0Sstevel@tonic-gate 	(void) mutex_lock(&sessionPoolLock);
1927*0Sstevel@tonic-gate 	if (sessionPool != NULL) {
1928*0Sstevel@tonic-gate 		for (id = 0; id < sessionPoolSize; id++)
1929*0Sstevel@tonic-gate 			_DropConnection(id + CONID_OFFSET, 0, 1);
1930*0Sstevel@tonic-gate 		free(sessionPool);
1931*0Sstevel@tonic-gate 		sessionPool = NULL;
1932*0Sstevel@tonic-gate 		sessionPoolSize = 0;
1933*0Sstevel@tonic-gate 	}
1934*0Sstevel@tonic-gate 	(void) mutex_unlock(&sessionPoolLock);
1935*0Sstevel@tonic-gate }
1936