1*e1dd0a2fSth /*
2*e1dd0a2fSth  * CDDL HEADER START
3*e1dd0a2fSth  *
4*e1dd0a2fSth  * The contents of this file are subject to the terms of the
5*e1dd0a2fSth  * Common Development and Distribution License (the "License").
6*e1dd0a2fSth  * You may not use this file except in compliance with the License.
7*e1dd0a2fSth  *
8*e1dd0a2fSth  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*e1dd0a2fSth  * or http://www.opensolaris.org/os/licensing.
10*e1dd0a2fSth  * See the License for the specific language governing permissions
11*e1dd0a2fSth  * and limitations under the License.
12*e1dd0a2fSth  *
13*e1dd0a2fSth  * When distributing Covered Code, include this CDDL HEADER in each
14*e1dd0a2fSth  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*e1dd0a2fSth  * If applicable, add the following below this CDDL HEADER, with the
16*e1dd0a2fSth  * fields enclosed by brackets "[]" replaced with your own identifying
17*e1dd0a2fSth  * information: Portions Copyright [yyyy] [name of copyright owner]
18*e1dd0a2fSth  *
19*e1dd0a2fSth  * CDDL HEADER END
20*e1dd0a2fSth  */
21*e1dd0a2fSth /*
22*e1dd0a2fSth  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*e1dd0a2fSth  * Use is subject to license terms.
24*e1dd0a2fSth  */
25*e1dd0a2fSth 
26*e1dd0a2fSth #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*e1dd0a2fSth 
28*e1dd0a2fSth #define	__STANDALONE_MODULE__
29*e1dd0a2fSth 
30*e1dd0a2fSth #include <stdio.h>
31*e1dd0a2fSth #include <sys/types.h>
32*e1dd0a2fSth #include <stdlib.h>
33*e1dd0a2fSth #include <libintl.h>
34*e1dd0a2fSth #include <string.h>
35*e1dd0a2fSth #include <ctype.h>
36*e1dd0a2fSth 
37*e1dd0a2fSth #include <sys/stat.h>
38*e1dd0a2fSth #include <fcntl.h>
39*e1dd0a2fSth #include <unistd.h>
40*e1dd0a2fSth #include <syslog.h>
41*e1dd0a2fSth #include <locale.h>
42*e1dd0a2fSth #include <errno.h>
43*e1dd0a2fSth #include <sys/time.h>
44*e1dd0a2fSth 
45*e1dd0a2fSth #include <arpa/inet.h>
46*e1dd0a2fSth #include <netdb.h>
47*e1dd0a2fSth #include <strings.h>
48*e1dd0a2fSth 
49*e1dd0a2fSth #include <thread.h>
50*e1dd0a2fSth 
51*e1dd0a2fSth #include <nsswitch.h>
52*e1dd0a2fSth #include <nss_dbdefs.h>
53*e1dd0a2fSth #include <nss.h>
54*e1dd0a2fSth 
55*e1dd0a2fSth #include "ns_cache_door.h"
56*e1dd0a2fSth #include "ns_internal.h"
57*e1dd0a2fSth 
58*e1dd0a2fSth typedef enum {
59*e1dd0a2fSth 	INFO_SERVER_JUST_INITED	= -1,
60*e1dd0a2fSth 	INFO_SERVER_UNKNOWN	= 0,
61*e1dd0a2fSth 	INFO_SERVER_CONNECTING	= 1,
62*e1dd0a2fSth 	INFO_SERVER_UP		= 2,
63*e1dd0a2fSth 	INFO_SERVER_ERROR 	= 3,
64*e1dd0a2fSth 	INFO_SERVER_REMOVED	= 4
65*e1dd0a2fSth } dir_server_status_t;
66*e1dd0a2fSth 
67*e1dd0a2fSth typedef enum {
68*e1dd0a2fSth 	INFO_STATUS_NEW   	= 2,
69*e1dd0a2fSth 	INFO_STATUS_OLD		= 3
70*e1dd0a2fSth } dir_server_info_t;
71*e1dd0a2fSth 
72*e1dd0a2fSth typedef struct dir_server {
73*e1dd0a2fSth 	char			*ip;
74*e1dd0a2fSth 	char			**controls;
75*e1dd0a2fSth 	char			**saslMech;
76*e1dd0a2fSth 	dir_server_status_t	status;
77*e1dd0a2fSth 	mutex_t			updateStatus;
78*e1dd0a2fSth 	dir_server_info_t	info;
79*e1dd0a2fSth } dir_server_t;
80*e1dd0a2fSth 
81*e1dd0a2fSth typedef struct dir_server_list {
82*e1dd0a2fSth 	dir_server_t	**nsServers;
83*e1dd0a2fSth 
84*e1dd0a2fSth 	rwlock_t	listDestroyLock;
85*e1dd0a2fSth } dir_server_list_t;
86*e1dd0a2fSth 
87*e1dd0a2fSth struct {
88*e1dd0a2fSth 	/* The local list of the directory servers' root DSEs. */
89*e1dd0a2fSth 	dir_server_list_t	*list;
90*e1dd0a2fSth 	/* The flag indicating if libsldap is in the 'Standalone' mode. */
91*e1dd0a2fSth 	int			standalone;
92*e1dd0a2fSth 	/*
93*e1dd0a2fSth 	 * The mutex ensuring that only one thread performs
94*e1dd0a2fSth 	 * the initialization of the list.
95*e1dd0a2fSth 	 */
96*e1dd0a2fSth 	mutex_t			listReplaceLock;
97*e1dd0a2fSth 	/*
98*e1dd0a2fSth 	 * A flag indicating that a particular thread is
99*e1dd0a2fSth 	 * in the 'ldap_cachemgr' mode. It is stored by thread as
100*e1dd0a2fSth 	 * a thread specific data.
101*e1dd0a2fSth 	 */
102*e1dd0a2fSth 	const int		initFlag;
103*e1dd0a2fSth 	/*
104*e1dd0a2fSth 	 * A thread specific key storing
105*e1dd0a2fSth 	 * the the 'ldap_cachemgr' mode indicator.
106*e1dd0a2fSth 	 */
107*e1dd0a2fSth 	thread_key_t		standaloneInitKey;
108*e1dd0a2fSth } dir_servers = {NULL, 0, DEFAULTMUTEX, '1'};
109*e1dd0a2fSth 
110*e1dd0a2fSth typedef struct switchDatabase {
111*e1dd0a2fSth 	char *conf;
112*e1dd0a2fSth 	uint32_t alloced;
113*e1dd0a2fSth } switch_database_t;
114*e1dd0a2fSth 
115*e1dd0a2fSth static thread_key_t switchConfigKey;
116*e1dd0a2fSth 
117*e1dd0a2fSth #pragma init(createStandaloneKey)
118*e1dd0a2fSth 
119*e1dd0a2fSth #define	DONT_INCLUDE_ATTR_NAMES	0
120*e1dd0a2fSth #define	INCLUDE_ATTR_NAMES	1
121*e1dd0a2fSth #define	IS_PROFILE		1
122*e1dd0a2fSth #define	NOT_PROFILE		0
123*e1dd0a2fSth /* INET6_ADDRSTRLEN + ":" + <5-digit port> + some round-up */
124*e1dd0a2fSth #define	MAX_HOSTADDR_LEN (INET6_ADDRSTRLEN + 6 + 12)
125*e1dd0a2fSth 
126*e1dd0a2fSth static
127*e1dd0a2fSth void
128*e1dd0a2fSth switch_conf_disposer(void *data)
129*e1dd0a2fSth {
130*e1dd0a2fSth 	switch_database_t *localData = (switch_database_t *)data;
131*e1dd0a2fSth 
132*e1dd0a2fSth 	free(localData->conf);
133*e1dd0a2fSth 	free(localData);
134*e1dd0a2fSth }
135*e1dd0a2fSth 
136*e1dd0a2fSth /*
137*e1dd0a2fSth  * This function initializes an indication that a thread obtaining a root DSE
138*e1dd0a2fSth  * will be switched to the 'ldap_cachemgr' mode. Within the thread libsldap
139*e1dd0a2fSth  * will not invoke the __s_api_requestServer function. Instead, the library
140*e1dd0a2fSth  * will establish a connection to the server specified by
141*e1dd0a2fSth  * the __ns_ldap_getRootDSE function.
142*e1dd0a2fSth  * Since  ldap_cachmgr can obtain a DUAProfile and root DSEs at the same time
143*e1dd0a2fSth  * and we do not want to affect a thread obtaining a DUAProfile,
144*e1dd0a2fSth  * the 'ldap_cachemgr' mode is thread private.
145*e1dd0a2fSth  * In addition, this function creates a key holding temporary configuration
146*e1dd0a2fSth  * for the "hosts" and "ipnodes" databases which is used by the "SKIPDB"
147*e1dd0a2fSth  * mechanism (__s_api_ip2hostname() & _s_api_hostname2ip()).
148*e1dd0a2fSth  */
149*e1dd0a2fSth static
150*e1dd0a2fSth void
151*e1dd0a2fSth createStandaloneKey()
152*e1dd0a2fSth {
153*e1dd0a2fSth 	if (thr_keycreate(&dir_servers.standaloneInitKey, NULL) != 0) {
154*e1dd0a2fSth 		syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
155*e1dd0a2fSth 		"key needed for sharing ldap connections"));
156*e1dd0a2fSth 	}
157*e1dd0a2fSth 	if (thr_keycreate(&switchConfigKey, switch_conf_disposer) != 0) {
158*e1dd0a2fSth 		syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
159*e1dd0a2fSth 		    "key containing current nsswitch configuration"));
160*e1dd0a2fSth 	}
161*e1dd0a2fSth }
162*e1dd0a2fSth 
163*e1dd0a2fSth /*
164*e1dd0a2fSth  * This function sets the 'ldap_cachemgr' mode indication.
165*e1dd0a2fSth  */
166*e1dd0a2fSth void
167*e1dd0a2fSth __s_api_setInitMode()
168*e1dd0a2fSth {
169*e1dd0a2fSth 	(void) thr_setspecific(dir_servers.standaloneInitKey,
170*e1dd0a2fSth 	    (void *) &dir_servers.initFlag);
171*e1dd0a2fSth }
172*e1dd0a2fSth 
173*e1dd0a2fSth /*
174*e1dd0a2fSth  * This function unset the 'ldap_cachemgr' mode indication.
175*e1dd0a2fSth  */
176*e1dd0a2fSth void
177*e1dd0a2fSth __s_api_unsetInitMode()
178*e1dd0a2fSth {
179*e1dd0a2fSth 	(void) thr_setspecific(dir_servers.standaloneInitKey, NULL);
180*e1dd0a2fSth }
181*e1dd0a2fSth 
182*e1dd0a2fSth /*
183*e1dd0a2fSth  * This function checks if the 'ldap_cachemgr' mode indication is set.
184*e1dd0a2fSth  */
185*e1dd0a2fSth int
186*e1dd0a2fSth __s_api_isInitializing() {
187*e1dd0a2fSth 	int *flag = NULL;
188*e1dd0a2fSth 
189*e1dd0a2fSth 	(void) thr_getspecific(dir_servers.standaloneInitKey, (void **) &flag);
190*e1dd0a2fSth 
191*e1dd0a2fSth 	return (flag != NULL && *flag == dir_servers.initFlag);
192*e1dd0a2fSth }
193*e1dd0a2fSth 
194*e1dd0a2fSth /*
195*e1dd0a2fSth  * This function checks if the process runs in the 'Standalone' mode.
196*e1dd0a2fSth  * In this mode libsldap will check the local, process private list of root DSEs
197*e1dd0a2fSth  * instead of requesting them via a door call to ldap_cachemgr.
198*e1dd0a2fSth  */
199*e1dd0a2fSth int
200*e1dd0a2fSth __s_api_isStandalone()
201*e1dd0a2fSth {
202*e1dd0a2fSth 	int	mode;
203*e1dd0a2fSth 
204*e1dd0a2fSth 	(void) mutex_lock(&dir_servers.listReplaceLock);
205*e1dd0a2fSth 	mode = dir_servers.standalone;
206*e1dd0a2fSth 	(void) mutex_unlock(&dir_servers.listReplaceLock);
207*e1dd0a2fSth 
208*e1dd0a2fSth 	return (mode);
209*e1dd0a2fSth }
210*e1dd0a2fSth 
211*e1dd0a2fSth 
212*e1dd0a2fSth static
213*e1dd0a2fSth int
214*e1dd0a2fSth remove_ldap(char *dst, char *src, int dst_buf_len)
215*e1dd0a2fSth {
216*e1dd0a2fSth 	int i = 0;
217*e1dd0a2fSth 
218*e1dd0a2fSth 	if (strlen(src) >= dst_buf_len)
219*e1dd0a2fSth 		return (0);
220*e1dd0a2fSth 
221*e1dd0a2fSth 	while (*src != '\0') {
222*e1dd0a2fSth 		/* Copy up to one space from source. */
223*e1dd0a2fSth 		if (isspace(*src)) {
224*e1dd0a2fSth 			dst[i++] = *src;
225*e1dd0a2fSth 			while (isspace(*src))
226*e1dd0a2fSth 				src++;
227*e1dd0a2fSth 		}
228*e1dd0a2fSth 
229*e1dd0a2fSth 		/* If not "ldap", just copy. */
230*e1dd0a2fSth 		if (strncmp(src, "ldap", 4) != 0) {
231*e1dd0a2fSth 			while (!isspace(*src)) {
232*e1dd0a2fSth 				dst[i++] = *src++;
233*e1dd0a2fSth 				/* At the end of string? */
234*e1dd0a2fSth 				if (dst[i-1] == '\0')
235*e1dd0a2fSth 					return (1);
236*e1dd0a2fSth 			}
237*e1dd0a2fSth 			/* Copy up to one space from source. */
238*e1dd0a2fSth 			if (isspace(*src)) {
239*e1dd0a2fSth 				dst[i++] = *src;
240*e1dd0a2fSth 				while (isspace(*src))
241*e1dd0a2fSth 					src++;
242*e1dd0a2fSth 			}
243*e1dd0a2fSth 			/* Copy also the criteria section */
244*e1dd0a2fSth 			if (*src == '[')
245*e1dd0a2fSth 				while (*src != ']') {
246*e1dd0a2fSth 					dst[i++] = *src++;
247*e1dd0a2fSth 					/* Shouln't happen if format is right */
248*e1dd0a2fSth 					if (dst[i-1] == '\0')
249*e1dd0a2fSth 						return (1);
250*e1dd0a2fSth 				}
251*e1dd0a2fSth 		}
252*e1dd0a2fSth 
253*e1dd0a2fSth 		/* If next part is ldap, skip over it ... */
254*e1dd0a2fSth 		if (strncmp(src, "ldap", 4) == 0) {
255*e1dd0a2fSth 			if (isspace(*(src+4)) || *(src+4) == '\0') {
256*e1dd0a2fSth 				src += 4;
257*e1dd0a2fSth 				while (isspace(*src))
258*e1dd0a2fSth 					src++;
259*e1dd0a2fSth 				if (*src == '[') {
260*e1dd0a2fSth 					while (*src++ != ']') {
261*e1dd0a2fSth 						/*
262*e1dd0a2fSth 						 * See comment above about
263*e1dd0a2fSth 						 * correct format.
264*e1dd0a2fSth 						 */
265*e1dd0a2fSth 						if (*src == '\0') {
266*e1dd0a2fSth 							dst[i++] = '\0';
267*e1dd0a2fSth 							return (1);
268*e1dd0a2fSth 						}
269*e1dd0a2fSth 					}
270*e1dd0a2fSth 				}
271*e1dd0a2fSth 				while (isspace(*src))
272*e1dd0a2fSth 					src++;
273*e1dd0a2fSth 			}
274*e1dd0a2fSth 		}
275*e1dd0a2fSth 		if (*src == '\0')
276*e1dd0a2fSth 			dst[i++] = '\0';
277*e1dd0a2fSth 	}
278*e1dd0a2fSth 
279*e1dd0a2fSth 	return (1);
280*e1dd0a2fSth }
281*e1dd0a2fSth 
282*e1dd0a2fSth static
283*e1dd0a2fSth char *
284*e1dd0a2fSth get_db(const char *db_name)
285*e1dd0a2fSth {
286*e1dd0a2fSth 	char			*ptr;
287*e1dd0a2fSth 	switch_database_t	*hostService = NULL;
288*e1dd0a2fSth 	FILE			*fp = fopen(__NSW_CONFIG_FILE, "rF");
289*e1dd0a2fSth 	char			*linep, line[NSS_BUFSIZ];
290*e1dd0a2fSth 
291*e1dd0a2fSth 	if (fp == NULL) {
292*e1dd0a2fSth 		syslog(LOG_WARNING, gettext("libsldap: can not read %s"),
293*e1dd0a2fSth 		    __NSW_CONFIG_FILE);
294*e1dd0a2fSth 		return (NULL);
295*e1dd0a2fSth 	}
296*e1dd0a2fSth 
297*e1dd0a2fSth 	while ((linep = fgets(line, NSS_BUFSIZ, fp)) != NULL) {
298*e1dd0a2fSth 		while (isspace(*linep)) {
299*e1dd0a2fSth 			++linep;
300*e1dd0a2fSth 		}
301*e1dd0a2fSth 		if (*linep == '#') {
302*e1dd0a2fSth 			continue;
303*e1dd0a2fSth 		}
304*e1dd0a2fSth 		if (strncmp(linep, db_name, strlen(db_name)) != 0) {
305*e1dd0a2fSth 			continue;
306*e1dd0a2fSth 		}
307*e1dd0a2fSth 		if ((linep = strchr(linep, ':')) != NULL) {
308*e1dd0a2fSth 			if (linep[strlen(linep) - 1] == '\n') {
309*e1dd0a2fSth 				linep[strlen(linep) - 1] = '\0';
310*e1dd0a2fSth 			}
311*e1dd0a2fSth 
312*e1dd0a2fSth 			while (isspace(*++linep))
313*e1dd0a2fSth 				;
314*e1dd0a2fSth 
315*e1dd0a2fSth 			if ((ptr = strchr(linep, '#')) != NULL) {
316*e1dd0a2fSth 				while (--ptr >= linep && isspace(*ptr))
317*e1dd0a2fSth 					;
318*e1dd0a2fSth 				*(ptr + 1) = '\0';
319*e1dd0a2fSth 			}
320*e1dd0a2fSth 
321*e1dd0a2fSth 			if (strlen(linep) == 0) {
322*e1dd0a2fSth 				continue;
323*e1dd0a2fSth 			}
324*e1dd0a2fSth 			break;
325*e1dd0a2fSth 		}
326*e1dd0a2fSth 	}
327*e1dd0a2fSth 
328*e1dd0a2fSth 	(void) fclose(fp);
329*e1dd0a2fSth 
330*e1dd0a2fSth 	if (linep == NULL) {
331*e1dd0a2fSth 		syslog(LOG_WARNING,
332*e1dd0a2fSth 		    gettext("libsldap: the %s database "
333*e1dd0a2fSth 		    "is missing from %s"),
334*e1dd0a2fSth 		    db_name,
335*e1dd0a2fSth 		    __NSW_CONFIG_FILE);
336*e1dd0a2fSth 		return (NULL);
337*e1dd0a2fSth 	}
338*e1dd0a2fSth 
339*e1dd0a2fSth 	(void) thr_getspecific(switchConfigKey, (void **) &hostService);
340*e1dd0a2fSth 	if (hostService == NULL) {
341*e1dd0a2fSth 		hostService = calloc(1, sizeof (switch_database_t));
342*e1dd0a2fSth 		if (hostService == NULL) {
343*e1dd0a2fSth 			return (NULL);
344*e1dd0a2fSth 		}
345*e1dd0a2fSth 		(void) thr_setspecific(switchConfigKey, hostService);
346*e1dd0a2fSth 	}
347*e1dd0a2fSth 
348*e1dd0a2fSth 	/*
349*e1dd0a2fSth 	 * In a long-living process threads can perform several
350*e1dd0a2fSth 	 * getXbyY requests. And the windows between those requests
351*e1dd0a2fSth 	 * can be long. The nsswitch configuration can change from time
352*e1dd0a2fSth 	 * to time. So instead of allocating/freeing memory every time
353*e1dd0a2fSth 	 * the API is called, reallocate memory only when the current
354*e1dd0a2fSth 	 * configuration for the database being used is longer than
355*e1dd0a2fSth 	 * the previous one.
356*e1dd0a2fSth 	 */
357*e1dd0a2fSth 	if (strlen(linep) >= hostService->alloced) {
358*e1dd0a2fSth 		ptr = (char *)realloc((void *)hostService->conf,
359*e1dd0a2fSth 		    strlen(linep) + 1);
360*e1dd0a2fSth 		if (ptr == NULL) {
361*e1dd0a2fSth 			free((void *)hostService->conf);
362*e1dd0a2fSth 			hostService->conf = NULL;
363*e1dd0a2fSth 			hostService->alloced = 0;
364*e1dd0a2fSth 			return (NULL);
365*e1dd0a2fSth 		}
366*e1dd0a2fSth 		bzero(ptr, strlen(linep) + 1);
367*e1dd0a2fSth 		hostService->conf = ptr;
368*e1dd0a2fSth 		hostService->alloced = strlen(linep) + 1;
369*e1dd0a2fSth 	}
370*e1dd0a2fSth 
371*e1dd0a2fSth 	if (remove_ldap(hostService->conf, linep, hostService->alloced))
372*e1dd0a2fSth 		return (hostService->conf);
373*e1dd0a2fSth 	else
374*e1dd0a2fSth 		return (NULL);
375*e1dd0a2fSth }
376*e1dd0a2fSth 
377*e1dd0a2fSth static
378*e1dd0a2fSth void
379*e1dd0a2fSth _initf_ipnodes(nss_db_params_t *p)
380*e1dd0a2fSth {
381*e1dd0a2fSth 	char *services = get_db("ipnodes");
382*e1dd0a2fSth 
383*e1dd0a2fSth 	p->name = NSS_DBNAM_IPNODES;
384*e1dd0a2fSth 	p->flags |= NSS_USE_DEFAULT_CONFIG;
385*e1dd0a2fSth 	p->default_config = services == NULL ? "" : services;
386*e1dd0a2fSth }
387*e1dd0a2fSth 
388*e1dd0a2fSth static
389*e1dd0a2fSth void
390*e1dd0a2fSth _initf_hosts(nss_db_params_t *p)
391*e1dd0a2fSth {
392*e1dd0a2fSth 	char *services = get_db("hosts");
393*e1dd0a2fSth 
394*e1dd0a2fSth 	p->name = NSS_DBNAM_HOSTS;
395*e1dd0a2fSth 	p->flags |= NSS_USE_DEFAULT_CONFIG;
396*e1dd0a2fSth 	p->default_config = services == NULL ? "" : services;
397*e1dd0a2fSth }
398*e1dd0a2fSth 
399*e1dd0a2fSth /*
400*e1dd0a2fSth  * This function is an analog of the standard gethostbyaddr_r()
401*e1dd0a2fSth  * function with an exception that it removes the 'ldap' back-end
402*e1dd0a2fSth  * (if any) from the host/ipnodes nsswitch's databases and then
403*e1dd0a2fSth  * looks up using remaining back-ends.
404*e1dd0a2fSth  */
405*e1dd0a2fSth static
406*e1dd0a2fSth struct hostent *
407*e1dd0a2fSth _filter_gethostbyaddr_r(const char *addr, int len, int type,
408*e1dd0a2fSth 	struct hostent *result, char *buffer, int buflen,
409*e1dd0a2fSth 	int *h_errnop)
410*e1dd0a2fSth {
411*e1dd0a2fSth 	DEFINE_NSS_DB_ROOT(db_root_hosts);
412*e1dd0a2fSth 	DEFINE_NSS_DB_ROOT(db_root_ipnodes);
413*e1dd0a2fSth 	nss_XbyY_args_t arg;
414*e1dd0a2fSth 	nss_status_t    res;
415*e1dd0a2fSth 	int		(*str2ent)();
416*e1dd0a2fSth 	void		(*nss_initf)();
417*e1dd0a2fSth 	nss_db_root_t	*nss_db_root;
418*e1dd0a2fSth 	int		dbop;
419*e1dd0a2fSth 
420*e1dd0a2fSth 	switch (type) {
421*e1dd0a2fSth 	case AF_INET:
422*e1dd0a2fSth 		str2ent		= str2hostent;
423*e1dd0a2fSth 		nss_initf	= _initf_hosts;
424*e1dd0a2fSth 		nss_db_root	= &db_root_hosts;
425*e1dd0a2fSth 		dbop		= NSS_DBOP_HOSTS_BYADDR;
426*e1dd0a2fSth 		break;
427*e1dd0a2fSth 	case AF_INET6:
428*e1dd0a2fSth 		str2ent		= str2hostent6;
429*e1dd0a2fSth 		nss_initf	= _initf_ipnodes;
430*e1dd0a2fSth 		nss_db_root	= &db_root_ipnodes;
431*e1dd0a2fSth 		dbop		= NSS_DBOP_IPNODES_BYADDR;
432*e1dd0a2fSth 	default:
433*e1dd0a2fSth 		return (NULL);
434*e1dd0a2fSth 	}
435*e1dd0a2fSth 
436*e1dd0a2fSth 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent);
437*e1dd0a2fSth 
438*e1dd0a2fSth 	arg.key.hostaddr.addr	= addr;
439*e1dd0a2fSth 	arg.key.hostaddr.len	= len;
440*e1dd0a2fSth 	arg.key.hostaddr.type	= type;
441*e1dd0a2fSth 	arg.stayopen		= 0;
442*e1dd0a2fSth 	arg.h_errno		= NETDB_SUCCESS;
443*e1dd0a2fSth 
444*e1dd0a2fSth 	res = nss_search(nss_db_root, nss_initf, dbop, &arg);
445*e1dd0a2fSth 	arg.status = res;
446*e1dd0a2fSth 	*h_errnop = arg.h_errno;
447*e1dd0a2fSth 	return (struct hostent *)NSS_XbyY_FINI(&arg);
448*e1dd0a2fSth }
449*e1dd0a2fSth 
450*e1dd0a2fSth /*
451*e1dd0a2fSth  * This routine is an analog of gethostbyaddr_r().
452*e1dd0a2fSth  * But in addition __s_api_hostname2ip() performs the "LDAP SKIPDB" activity
453*e1dd0a2fSth  * prior to querying the name services.
454*e1dd0a2fSth  * If the buffer is not big enough to accommodate a returning data,
455*e1dd0a2fSth  * NULL is returned and h_errnop is set to TRY_AGAIN.
456*e1dd0a2fSth  */
457*e1dd0a2fSth struct hostent *
458*e1dd0a2fSth __s_api_hostname2ip(const char *name,
459*e1dd0a2fSth 	struct hostent *result, char *buffer, int buflen,
460*e1dd0a2fSth 	int *h_errnop)
461*e1dd0a2fSth {
462*e1dd0a2fSth 	DEFINE_NSS_DB_ROOT(db_root_ipnodes);
463*e1dd0a2fSth 	DEFINE_NSS_DB_ROOT(db_root_hosts);
464*e1dd0a2fSth 	nss_XbyY_args_t	arg;
465*e1dd0a2fSth 	nss_status_t	res;
466*e1dd0a2fSth 	struct in_addr	addr;
467*e1dd0a2fSth 	struct in6_addr	addr6;
468*e1dd0a2fSth 
469*e1dd0a2fSth 	if (inet_pton(AF_INET, name, &addr) > 0) {
470*e1dd0a2fSth 		if (buflen < strlen(name) + 1 +
471*e1dd0a2fSth 		    sizeof (char *) * 2 + /* The h_aliases member */
472*e1dd0a2fSth 		    sizeof (struct in_addr) +
473*e1dd0a2fSth 		    sizeof (struct in_addr *) * 2) {
474*e1dd0a2fSth 			*h_errnop = TRY_AGAIN;
475*e1dd0a2fSth 			return (NULL);
476*e1dd0a2fSth 		}
477*e1dd0a2fSth 
478*e1dd0a2fSth 		result->h_addrtype = AF_INET;
479*e1dd0a2fSth 		result->h_length = sizeof (struct in_addr);
480*e1dd0a2fSth 		(void) strncpy(buffer, name, buflen);
481*e1dd0a2fSth 
482*e1dd0a2fSth 		result->h_addr_list = (char **)ROUND_UP(
483*e1dd0a2fSth 		    buffer + strlen(name) + 1,
484*e1dd0a2fSth 		    sizeof (char *));
485*e1dd0a2fSth 		result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
486*e1dd0a2fSth 		    sizeof (char *));
487*e1dd0a2fSth 		result->h_aliases[0] = buffer;
488*e1dd0a2fSth 		result->h_aliases[1] = NULL;
489*e1dd0a2fSth 		bcopy(&addr,
490*e1dd0a2fSth 		    buffer + buflen - sizeof (struct in_addr),
491*e1dd0a2fSth 		    sizeof (struct in_addr));
492*e1dd0a2fSth 		result->h_addr_list[0] = buffer + buflen -
493*e1dd0a2fSth 		    sizeof (struct in_addr);
494*e1dd0a2fSth 		result->h_addr_list[1] = NULL;
495*e1dd0a2fSth 		result->h_aliases = result->h_addr_list;
496*e1dd0a2fSth 		result->h_name = buffer;
497*e1dd0a2fSth 
498*e1dd0a2fSth 		*h_errnop = NETDB_SUCCESS;
499*e1dd0a2fSth 		return (result);
500*e1dd0a2fSth 	}
501*e1dd0a2fSth 	if (inet_pton(AF_INET6, name, &addr6) > 0) {
502*e1dd0a2fSth 		if (buflen < strlen(name) + 1 +
503*e1dd0a2fSth 		    sizeof (char *) * 2 + /* The h_aliases member */
504*e1dd0a2fSth 		    sizeof (struct in6_addr) +
505*e1dd0a2fSth 		    sizeof (struct in6_addr *) * 2) {
506*e1dd0a2fSth 			*h_errnop = TRY_AGAIN;
507*e1dd0a2fSth 			return (NULL);
508*e1dd0a2fSth 		}
509*e1dd0a2fSth 
510*e1dd0a2fSth 		result->h_addrtype = AF_INET6;
511*e1dd0a2fSth 		result->h_length = sizeof (struct in6_addr);
512*e1dd0a2fSth 		(void) strncpy(buffer, name, buflen);
513*e1dd0a2fSth 
514*e1dd0a2fSth 		result->h_addr_list = (char **)ROUND_UP(
515*e1dd0a2fSth 		    buffer + strlen(name) + 1,
516*e1dd0a2fSth 		    sizeof (char *));
517*e1dd0a2fSth 		result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
518*e1dd0a2fSth 		    sizeof (char *));
519*e1dd0a2fSth 		result->h_aliases[0] = buffer;
520*e1dd0a2fSth 		result->h_aliases[1] = NULL;
521*e1dd0a2fSth 		bcopy(&addr6,
522*e1dd0a2fSth 		    buffer + buflen - sizeof (struct in6_addr),
523*e1dd0a2fSth 		    sizeof (struct in6_addr));
524*e1dd0a2fSth 		result->h_addr_list[0] = buffer + buflen -
525*e1dd0a2fSth 		    sizeof (struct in6_addr);
526*e1dd0a2fSth 		result->h_addr_list[1] = NULL;
527*e1dd0a2fSth 		result->h_aliases = result->h_addr_list;
528*e1dd0a2fSth 		result->h_name = buffer;
529*e1dd0a2fSth 
530*e1dd0a2fSth 		*h_errnop = NETDB_SUCCESS;
531*e1dd0a2fSth 		return (result);
532*e1dd0a2fSth 	}
533*e1dd0a2fSth 
534*e1dd0a2fSth 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
535*e1dd0a2fSth 
536*e1dd0a2fSth 	arg.key.name = name;
537*e1dd0a2fSth 	arg.stayopen = 0;
538*e1dd0a2fSth 	arg.h_errno = NETDB_SUCCESS;
539*e1dd0a2fSth 
540*e1dd0a2fSth 	res = nss_search(&db_root_ipnodes, _initf_ipnodes,
541*e1dd0a2fSth 	    NSS_DBOP_IPNODES_BYNAME, &arg);
542*e1dd0a2fSth 	if (res == NSS_NOTFOUND || res == NSS_UNAVAIL) {
543*e1dd0a2fSth 		arg.h_errno = NETDB_SUCCESS;
544*e1dd0a2fSth 		res = nss_search(&db_root_hosts, _initf_hosts,
545*e1dd0a2fSth 		    NSS_DBOP_HOSTS_BYNAME, &arg);
546*e1dd0a2fSth 	}
547*e1dd0a2fSth 	arg.status = res;
548*e1dd0a2fSth 	*h_errnop = arg.h_errno;
549*e1dd0a2fSth 	return ((struct hostent *)NSS_XbyY_FINI(&arg));
550*e1dd0a2fSth }
551*e1dd0a2fSth 
552*e1dd0a2fSth /*
553*e1dd0a2fSth  * Convert an IP to a host name.
554*e1dd0a2fSth  */
555*e1dd0a2fSth ns_ldap_return_code
556*e1dd0a2fSth __s_api_ip2hostname(char *ipaddr, char **hostname) {
557*e1dd0a2fSth 	struct in_addr	in;
558*e1dd0a2fSth 	struct in6_addr	in6;
559*e1dd0a2fSth 	struct hostent	*hp = NULL, hostEnt;
560*e1dd0a2fSth 	char		buffer[NSS_BUFLEN_HOSTS];
561*e1dd0a2fSth 	int		buflen = NSS_BUFLEN_HOSTS;
562*e1dd0a2fSth 	char		*start = NULL,
563*e1dd0a2fSth 			*end = NULL,
564*e1dd0a2fSth 			delim = '\0';
565*e1dd0a2fSth 	char		*port = NULL,
566*e1dd0a2fSth 			*addr = NULL;
567*e1dd0a2fSth 	int		errorNum = 0,
568*e1dd0a2fSth 			len = 0;
569*e1dd0a2fSth 
570*e1dd0a2fSth 	if (ipaddr == NULL || hostname == NULL)
571*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
572*e1dd0a2fSth 	*hostname = NULL;
573*e1dd0a2fSth 	if ((addr = strdup(ipaddr)) == NULL)
574*e1dd0a2fSth 		return (NS_LDAP_MEMORY);
575*e1dd0a2fSth 
576*e1dd0a2fSth 	if (addr[0] == '[') {
577*e1dd0a2fSth 		/*
578*e1dd0a2fSth 		 * Assume it's [ipv6]:port
579*e1dd0a2fSth 		 * Extract ipv6 IP
580*e1dd0a2fSth 		 */
581*e1dd0a2fSth 		start = &addr[1];
582*e1dd0a2fSth 		if ((end = strchr(addr, ']')) != NULL) {
583*e1dd0a2fSth 			*end = '\0';
584*e1dd0a2fSth 			delim = ']';
585*e1dd0a2fSth 			if (*(end + 1) == ':')
586*e1dd0a2fSth 				/* extract port */
587*e1dd0a2fSth 				port = end + 2;
588*e1dd0a2fSth 		} else {
589*e1dd0a2fSth 			free(addr);
590*e1dd0a2fSth 			return (NS_LDAP_INVALID_PARAM);
591*e1dd0a2fSth 		}
592*e1dd0a2fSth 	} else if ((end = strchr(addr, ':')) != NULL) {
593*e1dd0a2fSth 		/* assume it's ipv4:port */
594*e1dd0a2fSth 		*end = '\0';
595*e1dd0a2fSth 		delim = ':';
596*e1dd0a2fSth 		start = addr;
597*e1dd0a2fSth 		port = end + 1;
598*e1dd0a2fSth 	} else
599*e1dd0a2fSth 		/* No port */
600*e1dd0a2fSth 		start = addr;
601*e1dd0a2fSth 
602*e1dd0a2fSth 
603*e1dd0a2fSth 	if (inet_pton(AF_INET, start, &in) == 1) {
604*e1dd0a2fSth 		/* IPv4 */
605*e1dd0a2fSth 		hp = _filter_gethostbyaddr_r((char *)&in,
606*e1dd0a2fSth 		    sizeof (in.s_addr),
607*e1dd0a2fSth 		    AF_INET,
608*e1dd0a2fSth 		    &hostEnt,
609*e1dd0a2fSth 		    buffer,
610*e1dd0a2fSth 		    buflen,
611*e1dd0a2fSth 		    &errorNum);
612*e1dd0a2fSth 		if (hp && hp->h_name) {
613*e1dd0a2fSth 			/* hostname + '\0' */
614*e1dd0a2fSth 			len = strlen(hp->h_name) + 1;
615*e1dd0a2fSth 			if (port)
616*e1dd0a2fSth 				/* ':' + port */
617*e1dd0a2fSth 				len += strlen(port) + 1;
618*e1dd0a2fSth 			if ((*hostname = malloc(len)) == NULL) {
619*e1dd0a2fSth 				free(addr);
620*e1dd0a2fSth 				return (NS_LDAP_MEMORY);
621*e1dd0a2fSth 			}
622*e1dd0a2fSth 
623*e1dd0a2fSth 			if (port)
624*e1dd0a2fSth 				(void) snprintf(*hostname, len, "%s:%s",
625*e1dd0a2fSth 						hp->h_name, port);
626*e1dd0a2fSth 			else
627*e1dd0a2fSth 				(void) strlcpy(*hostname, hp->h_name, len);
628*e1dd0a2fSth 
629*e1dd0a2fSth 			free(addr);
630*e1dd0a2fSth 			return (NS_LDAP_SUCCESS);
631*e1dd0a2fSth 		} else {
632*e1dd0a2fSth 			free(addr);
633*e1dd0a2fSth 			return (NS_LDAP_NOTFOUND);
634*e1dd0a2fSth 		}
635*e1dd0a2fSth 	} else if (inet_pton(AF_INET6, start, &in6) == 1) {
636*e1dd0a2fSth 		/* IPv6 */
637*e1dd0a2fSth 		hp = _filter_gethostbyaddr_r((char *)&in6,
638*e1dd0a2fSth 		    sizeof (in6.s6_addr),
639*e1dd0a2fSth 		    AF_INET6,
640*e1dd0a2fSth 		    &hostEnt,
641*e1dd0a2fSth 		    buffer,
642*e1dd0a2fSth 		    buflen,
643*e1dd0a2fSth 		    &errorNum);
644*e1dd0a2fSth 		if (hp && hp->h_name) {
645*e1dd0a2fSth 			/* hostname + '\0' */
646*e1dd0a2fSth 			len = strlen(hp->h_name) + 1;
647*e1dd0a2fSth 			if (port)
648*e1dd0a2fSth 				/* ':' + port */
649*e1dd0a2fSth 				len += strlen(port) + 1;
650*e1dd0a2fSth 			if ((*hostname = malloc(len)) == NULL) {
651*e1dd0a2fSth 				free(addr);
652*e1dd0a2fSth 				return (NS_LDAP_MEMORY);
653*e1dd0a2fSth 			}
654*e1dd0a2fSth 
655*e1dd0a2fSth 			if (port)
656*e1dd0a2fSth 				(void) snprintf(*hostname, len, "%s:%s",
657*e1dd0a2fSth 						hp->h_name, port);
658*e1dd0a2fSth 			else
659*e1dd0a2fSth 				(void) strlcpy(*hostname, hp->h_name, len);
660*e1dd0a2fSth 
661*e1dd0a2fSth 			free(addr);
662*e1dd0a2fSth 			return (NS_LDAP_SUCCESS);
663*e1dd0a2fSth 		} else {
664*e1dd0a2fSth 			free(addr);
665*e1dd0a2fSth 			return (NS_LDAP_NOTFOUND);
666*e1dd0a2fSth 		}
667*e1dd0a2fSth 	} else {
668*e1dd0a2fSth 		/*
669*e1dd0a2fSth 		 * A hostname
670*e1dd0a2fSth 		 * Return it as is
671*e1dd0a2fSth 		 */
672*e1dd0a2fSth 		if (end)
673*e1dd0a2fSth 			*end = delim;
674*e1dd0a2fSth 		*hostname = addr;
675*e1dd0a2fSth 		return (NS_LDAP_SUCCESS);
676*e1dd0a2fSth 	}
677*e1dd0a2fSth }
678*e1dd0a2fSth 
679*e1dd0a2fSth /*
680*e1dd0a2fSth  * This function obtains data returned by an LDAP search request and puts it
681*e1dd0a2fSth  * in a string in the ldap_cachmgr(1) door call format.
682*e1dd0a2fSth  *
683*e1dd0a2fSth  * INPUT:
684*e1dd0a2fSth  *     ld - a pointer to an LDAP structure used for a search operation,
685*e1dd0a2fSth  *     result_msg - a pointer to an LDAPMessage returned by the search,
686*e1dd0a2fSth  *     include_names - if set to INCLUDE_ATTR_NAMES, the output buffer will
687*e1dd0a2fSth  *                     contain attribute names.
688*e1dd0a2fSth  *                     Otherwise, only values will be return.
689*e1dd0a2fSth  *
690*e1dd0a2fSth  * OUTPUT:
691*e1dd0a2fSth  *      a buffer containing server info in the following format:
692*e1dd0a2fSth  *         [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
693*e1dd0a2fSth  *      Should be free'ed by the caller.
694*e1dd0a2fSth  */
695*e1dd0a2fSth static
696*e1dd0a2fSth ns_ldap_return_code
697*e1dd0a2fSth convert_to_door_line(LDAP* ld,
698*e1dd0a2fSth 		LDAPMessage *result_msg,
699*e1dd0a2fSth 		int include_names,
700*e1dd0a2fSth 		int is_profile,
701*e1dd0a2fSth 		char **door_line)
702*e1dd0a2fSth {
703*e1dd0a2fSth 	uint32_t	total_length = 0, attr_len = 0, i;
704*e1dd0a2fSth 	LDAPMessage	*e;
705*e1dd0a2fSth 	char		*a, **vals;
706*e1dd0a2fSth 	BerElement	*ber;
707*e1dd0a2fSth 	int		seen_objectclass = 0, rewind = 0;
708*e1dd0a2fSth 
709*e1dd0a2fSth 	if (!door_line) {
710*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
711*e1dd0a2fSth 	}
712*e1dd0a2fSth 	*door_line = NULL;
713*e1dd0a2fSth 
714*e1dd0a2fSth 	if ((e = ldap_first_entry(ld, result_msg)) == NULL) {
715*e1dd0a2fSth 		return (NS_LDAP_NOTFOUND);
716*e1dd0a2fSth 	}
717*e1dd0a2fSth 
718*e1dd0a2fSth 	/* calculate length of received data */
719*e1dd0a2fSth 	for (a = ldap_first_attribute(ld, e, &ber);
720*e1dd0a2fSth 	    a != NULL;
721*e1dd0a2fSth 	    a = ldap_next_attribute(ld, e, ber)) {
722*e1dd0a2fSth 
723*e1dd0a2fSth 		if ((vals = ldap_get_values(ld, e, a)) != NULL) {
724*e1dd0a2fSth 			for (i = 0; vals[i] != NULL; i++) {
725*e1dd0a2fSth 				total_length += (include_names ?
726*e1dd0a2fSth 				    strlen(a) : 0) +
727*e1dd0a2fSth 				    strlen(vals[i]) +
728*e1dd0a2fSth 				    strlen(DOORLINESEP) +1;
729*e1dd0a2fSth 			}
730*e1dd0a2fSth 			ldap_value_free(vals);
731*e1dd0a2fSth 		}
732*e1dd0a2fSth 		ldap_memfree(a);
733*e1dd0a2fSth 	}
734*e1dd0a2fSth 	if (ber != NULL) {
735*e1dd0a2fSth 		ber_free(ber, 0);
736*e1dd0a2fSth 	}
737*e1dd0a2fSth 
738*e1dd0a2fSth 	if (total_length == 0) {
739*e1dd0a2fSth 		return (NS_LDAP_NOTFOUND);
740*e1dd0a2fSth 	}
741*e1dd0a2fSth 
742*e1dd0a2fSth 	/* copy the data */
743*e1dd0a2fSth 	/* add 1 for the last '\0' */
744*e1dd0a2fSth 	*door_line  = (char *)malloc(total_length + 1);
745*e1dd0a2fSth 	if (*door_line == NULL) {
746*e1dd0a2fSth 		return (NS_LDAP_MEMORY);
747*e1dd0a2fSth 	}
748*e1dd0a2fSth 
749*e1dd0a2fSth 	/* make it an empty string first */
750*e1dd0a2fSth 	**door_line = '\0';
751*e1dd0a2fSth 	a = ldap_first_attribute(ld, e, &ber);
752*e1dd0a2fSth 	while (a != NULL) {
753*e1dd0a2fSth 		if (is_profile) {
754*e1dd0a2fSth 			/*
755*e1dd0a2fSth 			 * If we're processing DUAConfigProfile, we need to make
756*e1dd0a2fSth 			 * sure we put objectclass attribute first.
757*e1dd0a2fSth 			 * __s_api_create_config_door_str depends on that.
758*e1dd0a2fSth 			 */
759*e1dd0a2fSth 			if (seen_objectclass) {
760*e1dd0a2fSth 				if (strcasecmp(a, "objectclass") == 0) {
761*e1dd0a2fSth 					/* Skip objectclass now. */
762*e1dd0a2fSth 					a = ldap_next_attribute(ld, e, ber);
763*e1dd0a2fSth 					continue;
764*e1dd0a2fSth 				}
765*e1dd0a2fSth 			} else {
766*e1dd0a2fSth 				if (strcasecmp(a, "objectclass") == 0) {
767*e1dd0a2fSth 					seen_objectclass = 1;
768*e1dd0a2fSth 					rewind = 1;
769*e1dd0a2fSth 				} else {
770*e1dd0a2fSth 					/* Skip all but objectclass first. */
771*e1dd0a2fSth 					a = ldap_next_attribute(ld, e, ber);
772*e1dd0a2fSth 					continue;
773*e1dd0a2fSth 				}
774*e1dd0a2fSth 			}
775*e1dd0a2fSth 		}
776*e1dd0a2fSth 
777*e1dd0a2fSth 		if ((vals = ldap_get_values(ld, e, a)) != NULL) {
778*e1dd0a2fSth 			for (i = 0; vals[i] != NULL; i++) {
779*e1dd0a2fSth 				if (include_names) {
780*e1dd0a2fSth 					attr_len += strlen(a);
781*e1dd0a2fSth 				}
782*e1dd0a2fSth 				attr_len += strlen(vals[i]) +
783*e1dd0a2fSth 				    strlen(DOORLINESEP) + 2;
784*e1dd0a2fSth 				if (include_names) {
785*e1dd0a2fSth 					(void) snprintf(*door_line +
786*e1dd0a2fSth 					    strlen(*door_line),
787*e1dd0a2fSth 					    attr_len,
788*e1dd0a2fSth 					    "%s=%s%s",
789*e1dd0a2fSth 					    a, vals[i],
790*e1dd0a2fSth 					    DOORLINESEP);
791*e1dd0a2fSth 				} else {
792*e1dd0a2fSth 					(void) snprintf(*door_line +
793*e1dd0a2fSth 					    strlen(*door_line),
794*e1dd0a2fSth 					    attr_len,
795*e1dd0a2fSth 					    "%s%s",
796*e1dd0a2fSth 					    vals[i],
797*e1dd0a2fSth 					    DOORLINESEP);
798*e1dd0a2fSth 				}
799*e1dd0a2fSth 			}
800*e1dd0a2fSth 			ldap_value_free(vals);
801*e1dd0a2fSth 		}
802*e1dd0a2fSth 		ldap_memfree(a);
803*e1dd0a2fSth 
804*e1dd0a2fSth 		/* Rewind */
805*e1dd0a2fSth 		if (rewind) {
806*e1dd0a2fSth 			if (ber != NULL) {
807*e1dd0a2fSth 				ber_free(ber, 0);
808*e1dd0a2fSth 			}
809*e1dd0a2fSth 			a = ldap_first_attribute(ld, e, &ber);
810*e1dd0a2fSth 			rewind = 0;
811*e1dd0a2fSth 		} else {
812*e1dd0a2fSth 			a = ldap_next_attribute(ld, e, ber);
813*e1dd0a2fSth 		}
814*e1dd0a2fSth 	}
815*e1dd0a2fSth 	if (ber != NULL) {
816*e1dd0a2fSth 		ber_free(ber, 0);
817*e1dd0a2fSth 	}
818*e1dd0a2fSth 
819*e1dd0a2fSth 	if (e != result_msg) {
820*e1dd0a2fSth 		(void) ldap_msgfree(e);
821*e1dd0a2fSth 	}
822*e1dd0a2fSth 
823*e1dd0a2fSth 	return (NS_LDAP_SUCCESS);
824*e1dd0a2fSth }
825*e1dd0a2fSth 
826*e1dd0a2fSth /*
827*e1dd0a2fSth  * This function looks up the base DN of a directory serving
828*e1dd0a2fSth  * a specified domain name.
829*e1dd0a2fSth  *
830*e1dd0a2fSth  * INPUT:
831*e1dd0a2fSth  *     ld - a pointer to an LDAP structure used for the search operation,
832*e1dd0a2fSth  *     domain_name - the name of a domain.
833*e1dd0a2fSth  *
834*e1dd0a2fSth  * OUTPUT:
835*e1dd0a2fSth  *     a buffer containing a directory's base DN found.
836*e1dd0a2fSth  *     Should be free'ed by the caller.
837*e1dd0a2fSth  */
838*e1dd0a2fSth static
839*e1dd0a2fSth ns_ldap_return_code
840*e1dd0a2fSth getDirBaseDN(LDAP *ld, const char *domain_name, char **dir_base_dn)
841*e1dd0a2fSth {
842*e1dd0a2fSth 	struct timeval		tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
843*e1dd0a2fSth 	char			*attrs[2], *DNlist, *rest, *ptr;
844*e1dd0a2fSth 	char			filter[BUFSIZ], *a = NULL;
845*e1dd0a2fSth 	int			ldap_rc;
846*e1dd0a2fSth 	LDAPMessage		*resultMsg = NULL;
847*e1dd0a2fSth 	ns_ldap_return_code	ret_code;
848*e1dd0a2fSth 
849*e1dd0a2fSth 	/* Get the whole list of naming contexts residing on the server */
850*e1dd0a2fSth 	attrs[0] = "namingcontexts";
851*e1dd0a2fSth 	attrs[1] = NULL;
852*e1dd0a2fSth 	ldap_rc = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
853*e1dd0a2fSth 	    attrs, 0, NULL, NULL, &tv, 0, &resultMsg);
854*e1dd0a2fSth 	switch (ldap_rc) {
855*e1dd0a2fSth 		/* If successful, the root DSE was found. */
856*e1dd0a2fSth 		case LDAP_SUCCESS:
857*e1dd0a2fSth 			break;
858*e1dd0a2fSth 		/*
859*e1dd0a2fSth 		 * If the root DSE was not found, the server does
860*e1dd0a2fSth 		 * not comply with the LDAP v3 protocol.
861*e1dd0a2fSth 		 */
862*e1dd0a2fSth 		default:
863*e1dd0a2fSth 			if (resultMsg) {
864*e1dd0a2fSth 				(void) ldap_msgfree(resultMsg);
865*e1dd0a2fSth 				resultMsg = NULL;
866*e1dd0a2fSth 			}
867*e1dd0a2fSth 
868*e1dd0a2fSth 			return (NS_LDAP_OP_FAILED);
869*e1dd0a2fSth 			break;
870*e1dd0a2fSth 	}
871*e1dd0a2fSth 
872*e1dd0a2fSth 	if ((ret_code = convert_to_door_line(ld,
873*e1dd0a2fSth 	    resultMsg,
874*e1dd0a2fSth 	    DONT_INCLUDE_ATTR_NAMES,
875*e1dd0a2fSth 	    NOT_PROFILE,
876*e1dd0a2fSth 	    &DNlist)) != NS_LDAP_SUCCESS) {
877*e1dd0a2fSth 		if (resultMsg) {
878*e1dd0a2fSth 			(void) ldap_msgfree(resultMsg);
879*e1dd0a2fSth 			resultMsg = NULL;
880*e1dd0a2fSth 		}
881*e1dd0a2fSth 		return (ret_code);
882*e1dd0a2fSth 	}
883*e1dd0a2fSth 
884*e1dd0a2fSth 	if (resultMsg) {
885*e1dd0a2fSth 		(void) ldap_msgfree(resultMsg);
886*e1dd0a2fSth 		resultMsg = NULL;
887*e1dd0a2fSth 	}
888*e1dd0a2fSth 
889*e1dd0a2fSth 	if (DNlist == NULL ||
890*e1dd0a2fSth 	    (ptr = strtok_r(DNlist, DOORLINESEP, &rest)) == NULL) {
891*e1dd0a2fSth 		return (NS_LDAP_NOTFOUND);
892*e1dd0a2fSth 	}
893*e1dd0a2fSth 	attrs[0] = "dn";
894*e1dd0a2fSth 	do {
895*e1dd0a2fSth 		/*
896*e1dd0a2fSth 		 * For each context try to find a NIS domain object
897*e1dd0a2fSth 		 * which 'nisdomain' attribute's value matches the domain name
898*e1dd0a2fSth 		 */
899*e1dd0a2fSth 		(void) snprintf(filter,
900*e1dd0a2fSth 		    BUFSIZ,
901*e1dd0a2fSth 		    "(&(objectclass=nisDomainObject)"
902*e1dd0a2fSth 		    "(nisdomain=%s))",
903*e1dd0a2fSth 		    domain_name);
904*e1dd0a2fSth 		ldap_rc = ldap_search_ext_s(ld,
905*e1dd0a2fSth 		    ptr,
906*e1dd0a2fSth 		    LDAP_SCOPE_SUBTREE,
907*e1dd0a2fSth 		    filter,
908*e1dd0a2fSth 		    attrs,
909*e1dd0a2fSth 		    0,
910*e1dd0a2fSth 		    NULL,
911*e1dd0a2fSth 		    NULL,
912*e1dd0a2fSth 		    &tv,
913*e1dd0a2fSth 		    0,
914*e1dd0a2fSth 		    &resultMsg);
915*e1dd0a2fSth 		if (ldap_rc != LDAP_SUCCESS) {
916*e1dd0a2fSth 			if (resultMsg) {
917*e1dd0a2fSth 				(void) ldap_msgfree(resultMsg);
918*e1dd0a2fSth 				resultMsg = NULL;
919*e1dd0a2fSth 			}
920*e1dd0a2fSth 			continue;
921*e1dd0a2fSth 		}
922*e1dd0a2fSth 		if ((a = ldap_get_dn(ld, resultMsg)) != NULL) {
923*e1dd0a2fSth 			*dir_base_dn = strdup(a);
924*e1dd0a2fSth 			ldap_memfree(a);
925*e1dd0a2fSth 
926*e1dd0a2fSth 			if (resultMsg) {
927*e1dd0a2fSth 				(void) ldap_msgfree(resultMsg);
928*e1dd0a2fSth 				resultMsg = NULL;
929*e1dd0a2fSth 			}
930*e1dd0a2fSth 
931*e1dd0a2fSth 			if (!*dir_base_dn) {
932*e1dd0a2fSth 				free(DNlist);
933*e1dd0a2fSth 				return (NS_LDAP_MEMORY);
934*e1dd0a2fSth 			}
935*e1dd0a2fSth 			break;
936*e1dd0a2fSth 		}
937*e1dd0a2fSth 
938*e1dd0a2fSth 		if (resultMsg) {
939*e1dd0a2fSth 			(void) ldap_msgfree(resultMsg);
940*e1dd0a2fSth 			resultMsg = NULL;
941*e1dd0a2fSth 		}
942*e1dd0a2fSth 	} while (ptr = strtok_r(NULL, DOORLINESEP, &rest));
943*e1dd0a2fSth 
944*e1dd0a2fSth 	free(DNlist);
945*e1dd0a2fSth 
946*e1dd0a2fSth 	if (!*dir_base_dn) {
947*e1dd0a2fSth 		return (NS_LDAP_NOTFOUND);
948*e1dd0a2fSth 	}
949*e1dd0a2fSth 
950*e1dd0a2fSth 	return (NS_LDAP_SUCCESS);
951*e1dd0a2fSth }
952*e1dd0a2fSth 
953*e1dd0a2fSth /*
954*e1dd0a2fSth  * This function parses the results of a search operation
955*e1dd0a2fSth  * requesting a DUAProfile.
956*e1dd0a2fSth  *
957*e1dd0a2fSth  * INPUT:
958*e1dd0a2fSth  *     ld - a pointer to an LDAP structure used for the search operation,
959*e1dd0a2fSth  *     dir_base_dn - the name of a directory's base DN,
960*e1dd0a2fSth  *     profile_name - the name of a DUAProfile to be obtained.
961*e1dd0a2fSth  *
962*e1dd0a2fSth  * OUTPUT:
963*e1dd0a2fSth  *      a buffer containing the DUAProfile in the following format:
964*e1dd0a2fSth  *        [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
965*e1dd0a2fSth  *      Should be free'ed by the caller.
966*e1dd0a2fSth  */
967*e1dd0a2fSth static
968*e1dd0a2fSth ns_ldap_return_code
969*e1dd0a2fSth getDUAProfile(LDAP *ld,
970*e1dd0a2fSth 		const char *dir_base_dn,
971*e1dd0a2fSth 		const char *profile_name,
972*e1dd0a2fSth 		char **profile)
973*e1dd0a2fSth {
974*e1dd0a2fSth 	char			searchBaseDN[BUFSIZ], filter[BUFSIZ];
975*e1dd0a2fSth 	LDAPMessage		*resultMsg = NULL;
976*e1dd0a2fSth 	struct timeval		tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
977*e1dd0a2fSth 	int			ldap_rc;
978*e1dd0a2fSth 	ns_ldap_return_code	ret_code;
979*e1dd0a2fSth 
980*e1dd0a2fSth 	(void) snprintf(searchBaseDN, BUFSIZ, "ou=profile,%s", dir_base_dn);
981*e1dd0a2fSth 	(void) snprintf(filter,
982*e1dd0a2fSth 	    BUFSIZ,
983*e1dd0a2fSth 	    _PROFILE_FILTER,
984*e1dd0a2fSth 	    _PROFILE1_OBJECTCLASS,
985*e1dd0a2fSth 	    _PROFILE2_OBJECTCLASS,
986*e1dd0a2fSth 	    profile_name);
987*e1dd0a2fSth 	ldap_rc = ldap_search_ext_s(ld,
988*e1dd0a2fSth 	    searchBaseDN,
989*e1dd0a2fSth 	    LDAP_SCOPE_SUBTREE,
990*e1dd0a2fSth 	    filter,
991*e1dd0a2fSth 	    NULL,
992*e1dd0a2fSth 	    0,
993*e1dd0a2fSth 	    NULL,
994*e1dd0a2fSth 	    NULL,
995*e1dd0a2fSth 	    &tv,
996*e1dd0a2fSth 	    0,
997*e1dd0a2fSth 	    &resultMsg);
998*e1dd0a2fSth 
999*e1dd0a2fSth 	switch (ldap_rc) {
1000*e1dd0a2fSth 		/* If successful, the DUA profile was found. */
1001*e1dd0a2fSth 		case LDAP_SUCCESS:
1002*e1dd0a2fSth 			break;
1003*e1dd0a2fSth 		/*
1004*e1dd0a2fSth 		 * If the root DSE was not found, the server does
1005*e1dd0a2fSth 		 * not comply with the LDAP v3 protocol.
1006*e1dd0a2fSth 		 */
1007*e1dd0a2fSth 		default:
1008*e1dd0a2fSth 			if (resultMsg) {
1009*e1dd0a2fSth 				(void) ldap_msgfree(resultMsg);
1010*e1dd0a2fSth 				resultMsg = NULL;
1011*e1dd0a2fSth 			}
1012*e1dd0a2fSth 
1013*e1dd0a2fSth 			return (NS_LDAP_OP_FAILED);
1014*e1dd0a2fSth 			break;
1015*e1dd0a2fSth 	}
1016*e1dd0a2fSth 
1017*e1dd0a2fSth 	ret_code = convert_to_door_line(ld,
1018*e1dd0a2fSth 	    resultMsg,
1019*e1dd0a2fSth 	    INCLUDE_ATTR_NAMES,
1020*e1dd0a2fSth 	    IS_PROFILE,
1021*e1dd0a2fSth 	    profile);
1022*e1dd0a2fSth 	if (resultMsg) {
1023*e1dd0a2fSth 		(void) ldap_msgfree(resultMsg);
1024*e1dd0a2fSth 		resultMsg = NULL;
1025*e1dd0a2fSth 	}
1026*e1dd0a2fSth 	return (ret_code);
1027*e1dd0a2fSth }
1028*e1dd0a2fSth 
1029*e1dd0a2fSth /*
1030*e1dd0a2fSth  * This function derives the directory's base DN from a provided domain name.
1031*e1dd0a2fSth  *
1032*e1dd0a2fSth  * INPUT:
1033*e1dd0a2fSth  *     domain_name - the name of a domain to be converted into a base DN,
1034*e1dd0a2fSth  *     buffer - contains the derived base DN,
1035*e1dd0a2fSth  *     buf_len - the length of the buffer.
1036*e1dd0a2fSth  *
1037*e1dd0a2fSth  * OUTPUT:
1038*e1dd0a2fSth  *     The function returns the address of the buffer or NULL.
1039*e1dd0a2fSth  */
1040*e1dd0a2fSth static
1041*e1dd0a2fSth char *
1042*e1dd0a2fSth domainname2baseDN(char *domain_name, char *buffer, uint16_t buf_len)
1043*e1dd0a2fSth {
1044*e1dd0a2fSth 	char		*nextDC, *chr;
1045*e1dd0a2fSth 	uint16_t	i, length;
1046*e1dd0a2fSth 
1047*e1dd0a2fSth 	if (!domain_name || !buffer || buf_len == 0) {
1048*e1dd0a2fSth 		return (NULL);
1049*e1dd0a2fSth 	}
1050*e1dd0a2fSth 
1051*e1dd0a2fSth 	buffer[0] = '\0';
1052*e1dd0a2fSth 	nextDC = chr = domain_name;
1053*e1dd0a2fSth 	length = strlen(domain_name);
1054*e1dd0a2fSth 	for (i = 0; i < length + 1; ++i, ++chr) {
1055*e1dd0a2fSth 		/* Simply replace dots with "dc=" */
1056*e1dd0a2fSth 		if (*chr != '.' && *chr != '\0') {
1057*e1dd0a2fSth 			continue;
1058*e1dd0a2fSth 		}
1059*e1dd0a2fSth 		*chr = '\0';
1060*e1dd0a2fSth 		if (strlcat(buffer, "dc=", buf_len) >= buf_len)
1061*e1dd0a2fSth 			return (NULL);
1062*e1dd0a2fSth 		if (strlcat(buffer, nextDC, buf_len) >= buf_len)
1063*e1dd0a2fSth 			return (NULL);
1064*e1dd0a2fSth 		if (i < length) {
1065*e1dd0a2fSth 			/*
1066*e1dd0a2fSth 			 * The end of the domain name
1067*e1dd0a2fSth 			 * has not been reached yet
1068*e1dd0a2fSth 			 */
1069*e1dd0a2fSth 			if (strlcat(buffer, ",", buf_len) >= buf_len)
1070*e1dd0a2fSth 				return (NULL);
1071*e1dd0a2fSth 			nextDC = chr + 1;
1072*e1dd0a2fSth 			*chr = '.';
1073*e1dd0a2fSth 		}
1074*e1dd0a2fSth 	}
1075*e1dd0a2fSth 
1076*e1dd0a2fSth 	return (buffer);
1077*e1dd0a2fSth }
1078*e1dd0a2fSth 
1079*e1dd0a2fSth /*
1080*e1dd0a2fSth  * This function obtains the directory's base DN and a DUAProfile
1081*e1dd0a2fSth  * from a specified server.
1082*e1dd0a2fSth  *
1083*e1dd0a2fSth  * INPUT:
1084*e1dd0a2fSth  *     server - a structure describing a server to connect to and
1085*e1dd0a2fSth  *              a DUAProfile to be obtained from the server,
1086*e1dd0a2fSth  *     cred - credentials to be used during establishing connections to
1087*e1dd0a2fSth  *            the server.
1088*e1dd0a2fSth  *
1089*e1dd0a2fSth  * OUTPUT:
1090*e1dd0a2fSth  *     dua_profile - a buffer containing the DUAProfile in the following format:
1091*e1dd0a2fSth  *        [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1092*e1dd0a2fSth  *     dir_base_dn - a buffer containing the base DN,
1093*e1dd0a2fSth  *     errorp - an error object describing an error, if any.
1094*e1dd0a2fSth  *
1095*e1dd0a2fSth  *     All the output data structures should be free'ed by the caller.
1096*e1dd0a2fSth  */
1097*e1dd0a2fSth ns_ldap_return_code
1098*e1dd0a2fSth __ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t *server,
1099*e1dd0a2fSth 	const ns_cred_t *cred,
1100*e1dd0a2fSth 	char **dua_profile,
1101*e1dd0a2fSth 	char **dir_base_dn,
1102*e1dd0a2fSth 	ns_ldap_error_t **errorp)
1103*e1dd0a2fSth {
1104*e1dd0a2fSth 	char			serverAddr[MAX_HOSTADDR_LEN];
1105*e1dd0a2fSth 	char			*dirBaseDN = NULL, *duaProfile = NULL;
1106*e1dd0a2fSth 	ns_cred_t		default_cred;
1107*e1dd0a2fSth 	ns_ldap_return_code	ret_code;
1108*e1dd0a2fSth 
1109*e1dd0a2fSth 	ns_config_t		*config_struct = __s_api_create_config();
1110*e1dd0a2fSth 	ConnectionID		sessionId = 0;
1111*e1dd0a2fSth 	Connection		*session = NULL;
1112*e1dd0a2fSth 	char			errmsg[MAXERROR];
1113*e1dd0a2fSth 	char			buffer[NSS_BUFLEN_HOSTS];
1114*e1dd0a2fSth 
1115*e1dd0a2fSth 	if (errorp == NULL) {
1116*e1dd0a2fSth 		__s_api_destroy_config(config_struct);
1117*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
1118*e1dd0a2fSth 	}
1119*e1dd0a2fSth 
1120*e1dd0a2fSth 	*errorp = NULL;
1121*e1dd0a2fSth 
1122*e1dd0a2fSth 	if (server == NULL) {
1123*e1dd0a2fSth 		__s_api_destroy_config(config_struct);
1124*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
1125*e1dd0a2fSth 	}
1126*e1dd0a2fSth 
1127*e1dd0a2fSth 	if (config_struct == NULL) {
1128*e1dd0a2fSth 		return (NS_LDAP_MEMORY);
1129*e1dd0a2fSth 	}
1130*e1dd0a2fSth 
1131*e1dd0a2fSth 	/*
1132*e1dd0a2fSth 	 * If no credentials are specified, try to establish a connection
1133*e1dd0a2fSth 	 * as anonymous.
1134*e1dd0a2fSth 	 */
1135*e1dd0a2fSth 	if (!cred) {
1136*e1dd0a2fSth 		default_cred.cred.unix_cred.passwd = NULL;
1137*e1dd0a2fSth 		default_cred.cred.unix_cred.userID = NULL;
1138*e1dd0a2fSth 		default_cred.auth.type = NS_LDAP_AUTH_NONE;
1139*e1dd0a2fSth 	}
1140*e1dd0a2fSth 
1141*e1dd0a2fSth 	/* Now create a default LDAP configuration */
1142*e1dd0a2fSth 
1143*e1dd0a2fSth 	(void) strncpy(buffer, server->server, sizeof (buffer));
1144*e1dd0a2fSth 	if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SERVERS_P, buffer,
1145*e1dd0a2fSth 	    errorp) != NS_LDAP_SUCCESS) {
1146*e1dd0a2fSth 		__s_api_destroy_config(config_struct);
1147*e1dd0a2fSth 		return (NS_LDAP_CONFIG);
1148*e1dd0a2fSth 	}
1149*e1dd0a2fSth 
1150*e1dd0a2fSth 	/* Put together the address and the port specified by the user app. */
1151*e1dd0a2fSth 	if (server->port > 0) {
1152*e1dd0a2fSth 		(void) snprintf(serverAddr,
1153*e1dd0a2fSth 		    sizeof (serverAddr),
1154*e1dd0a2fSth 		    "%s:%hu",
1155*e1dd0a2fSth 		    buffer,
1156*e1dd0a2fSth 		    server->port);
1157*e1dd0a2fSth 	} else {
1158*e1dd0a2fSth 		(void) strncpy(serverAddr, buffer, sizeof (serverAddr));
1159*e1dd0a2fSth 	}
1160*e1dd0a2fSth 
1161*e1dd0a2fSth 	/*
1162*e1dd0a2fSth 	 * There is no default value for the 'Default Search Base DN' attribute.
1163*e1dd0a2fSth 	 * Derive one from the domain name to make __s_api_crosscheck() happy.
1164*e1dd0a2fSth 	 */
1165*e1dd0a2fSth 	if (domainname2baseDN(server->domainName ?
1166*e1dd0a2fSth 	    server->domainName : config_struct->domainName,
1167*e1dd0a2fSth 	    buffer, NSS_BUFLEN_HOSTS) == NULL) {
1168*e1dd0a2fSth 		(void) snprintf(errmsg,
1169*e1dd0a2fSth 		    sizeof (errmsg),
1170*e1dd0a2fSth 		    gettext("Can not convert %s into a base DN name"),
1171*e1dd0a2fSth 		    server->domainName ?
1172*e1dd0a2fSth 		    server->domainName : config_struct->domainName);
1173*e1dd0a2fSth 		MKERROR(LOG_ERR,
1174*e1dd0a2fSth 		    *errorp,
1175*e1dd0a2fSth 		    NS_LDAP_INTERNAL,
1176*e1dd0a2fSth 		    strdup(errmsg),
1177*e1dd0a2fSth 		    NS_LDAP_MEMORY);
1178*e1dd0a2fSth 		__s_api_destroy_config(config_struct);
1179*e1dd0a2fSth 		return (NS_LDAP_INTERNAL);
1180*e1dd0a2fSth 	}
1181*e1dd0a2fSth 	if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SEARCH_BASEDN_P,
1182*e1dd0a2fSth 	    buffer, errorp) != NS_LDAP_SUCCESS) {
1183*e1dd0a2fSth 		__s_api_destroy_config(config_struct);
1184*e1dd0a2fSth 		return (NS_LDAP_CONFIG);
1185*e1dd0a2fSth 	}
1186*e1dd0a2fSth 
1187*e1dd0a2fSth 	if (__s_api_crosscheck(config_struct, errmsg, B_FALSE) != NS_SUCCESS) {
1188*e1dd0a2fSth 		__s_api_destroy_config(config_struct);
1189*e1dd0a2fSth 		return (NS_LDAP_CONFIG);
1190*e1dd0a2fSth 	}
1191*e1dd0a2fSth 
1192*e1dd0a2fSth 	__s_api_init_config(config_struct);
1193*e1dd0a2fSth 
1194*e1dd0a2fSth 	__s_api_setInitMode();
1195*e1dd0a2fSth 
1196*e1dd0a2fSth 	if ((ret_code = __s_api_getConnection(serverAddr,
1197*e1dd0a2fSth 	    NS_LDAP_NEW_CONN,
1198*e1dd0a2fSth 	    cred ? cred : &default_cred,
1199*e1dd0a2fSth 	    &sessionId,
1200*e1dd0a2fSth 	    &session,
1201*e1dd0a2fSth 	    errorp,
1202*e1dd0a2fSth 	    0,
1203*e1dd0a2fSth 	    0,
1204*e1dd0a2fSth 	    NULL)) != NS_LDAP_SUCCESS) {
1205*e1dd0a2fSth 		__s_api_unsetInitMode();
1206*e1dd0a2fSth 		return (ret_code);
1207*e1dd0a2fSth 	}
1208*e1dd0a2fSth 
1209*e1dd0a2fSth 	__s_api_unsetInitMode();
1210*e1dd0a2fSth 
1211*e1dd0a2fSth 	if ((ret_code = getDirBaseDN(session->ld,
1212*e1dd0a2fSth 	    server->domainName ?
1213*e1dd0a2fSth 	    server->domainName :
1214*e1dd0a2fSth 	    config_struct->domainName,
1215*e1dd0a2fSth 	    &dirBaseDN)) != NS_LDAP_SUCCESS) {
1216*e1dd0a2fSth 		(void) snprintf(errmsg,
1217*e1dd0a2fSth 		    sizeof (errmsg),
1218*e1dd0a2fSth 		    gettext("Can not find the "
1219*e1dd0a2fSth 		    "nisDomainObject for domain %s\n"),
1220*e1dd0a2fSth 		    server->domainName ?
1221*e1dd0a2fSth 		    server->domainName : config_struct->domainName);
1222*e1dd0a2fSth 		MKERROR(LOG_ERR,
1223*e1dd0a2fSth 		    *errorp,
1224*e1dd0a2fSth 		    ret_code,
1225*e1dd0a2fSth 		    strdup(errmsg),
1226*e1dd0a2fSth 		    NS_LDAP_MEMORY);
1227*e1dd0a2fSth 		DropConnection(sessionId, NS_LDAP_NEW_CONN);
1228*e1dd0a2fSth 		return (ret_code);
1229*e1dd0a2fSth 	}
1230*e1dd0a2fSth 
1231*e1dd0a2fSth 	/*
1232*e1dd0a2fSth 	 * And here obtain a DUAProfile which will be used
1233*e1dd0a2fSth 	 * as a real configuration.
1234*e1dd0a2fSth 	 */
1235*e1dd0a2fSth 	if ((ret_code = getDUAProfile(session->ld,
1236*e1dd0a2fSth 	    dirBaseDN,
1237*e1dd0a2fSth 	    server->profileName ?
1238*e1dd0a2fSth 	    server->profileName : "default",
1239*e1dd0a2fSth 	    &duaProfile)) != NS_LDAP_SUCCESS) {
1240*e1dd0a2fSth 		(void) snprintf(errmsg,
1241*e1dd0a2fSth 		    sizeof (errmsg),
1242*e1dd0a2fSth 		    gettext("Can not find the "
1243*e1dd0a2fSth 		    "%s DUAProfile\n"),
1244*e1dd0a2fSth 		    server->profileName ?
1245*e1dd0a2fSth 		    server->profileName : "default");
1246*e1dd0a2fSth 		MKERROR(LOG_ERR,
1247*e1dd0a2fSth 		    *errorp,
1248*e1dd0a2fSth 		    ret_code,
1249*e1dd0a2fSth 		    strdup(errmsg),
1250*e1dd0a2fSth 		    NS_LDAP_MEMORY);
1251*e1dd0a2fSth 		DropConnection(sessionId, NS_LDAP_NEW_CONN);
1252*e1dd0a2fSth 		return (ret_code);
1253*e1dd0a2fSth 	}
1254*e1dd0a2fSth 
1255*e1dd0a2fSth 	if (dir_base_dn) {
1256*e1dd0a2fSth 		*dir_base_dn = dirBaseDN;
1257*e1dd0a2fSth 	} else {
1258*e1dd0a2fSth 		free(dirBaseDN);
1259*e1dd0a2fSth 	}
1260*e1dd0a2fSth 
1261*e1dd0a2fSth 	if (dua_profile) {
1262*e1dd0a2fSth 		*dua_profile = duaProfile;
1263*e1dd0a2fSth 	} else {
1264*e1dd0a2fSth 		free(duaProfile);
1265*e1dd0a2fSth 	}
1266*e1dd0a2fSth 
1267*e1dd0a2fSth 	DropConnection(sessionId, NS_LDAP_NEW_CONN);
1268*e1dd0a2fSth 
1269*e1dd0a2fSth 	return (NS_LDAP_SUCCESS);
1270*e1dd0a2fSth }
1271*e1dd0a2fSth 
1272*e1dd0a2fSth /*
1273*e1dd0a2fSth  * This function obtains the root DSE from a specified server.
1274*e1dd0a2fSth  *
1275*e1dd0a2fSth  * INPUT:
1276*e1dd0a2fSth  *     server_addr - an adress of a server to be connected to.
1277*e1dd0a2fSth  *
1278*e1dd0a2fSth  * OUTPUT:
1279*e1dd0a2fSth  *     root_dse - a buffer containing the root DSE in the following format:
1280*e1dd0a2fSth  *          [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1281*e1dd0a2fSth  *        For example: ( here | used as DOORLINESEP for visual purposes)
1282*e1dd0a2fSth  *          supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL
1283*e1dd0a2fSth  *        Should be free'ed by the caller.
1284*e1dd0a2fSth  */
1285*e1dd0a2fSth ns_ldap_return_code
1286*e1dd0a2fSth __ns_ldap_getRootDSE(const char *server_addr,
1287*e1dd0a2fSth 		char **root_dse,
1288*e1dd0a2fSth 		ns_ldap_error_t **errorp,
1289*e1dd0a2fSth 		int anon_fallback)
1290*e1dd0a2fSth {
1291*e1dd0a2fSth 	char			errmsg[MAXERROR];
1292*e1dd0a2fSth 	ns_ldap_return_code	ret_code;
1293*e1dd0a2fSth 
1294*e1dd0a2fSth 	ConnectionID		sessionId = 0;
1295*e1dd0a2fSth 	Connection		*session = NULL;
1296*e1dd0a2fSth 
1297*e1dd0a2fSth 	struct timeval		tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
1298*e1dd0a2fSth 	char			*attrs[3];
1299*e1dd0a2fSth 	int			ldap_rc, ldaperrno = 0;
1300*e1dd0a2fSth 	LDAPMessage		*resultMsg = NULL;
1301*e1dd0a2fSth 	void			**paramVal = NULL;
1302*e1dd0a2fSth 
1303*e1dd0a2fSth 	ns_cred_t		anon;
1304*e1dd0a2fSth 
1305*e1dd0a2fSth 	if (errorp == NULL) {
1306*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
1307*e1dd0a2fSth 	}
1308*e1dd0a2fSth 
1309*e1dd0a2fSth 	*errorp = NULL;
1310*e1dd0a2fSth 
1311*e1dd0a2fSth 	if (!root_dse) {
1312*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
1313*e1dd0a2fSth 	}
1314*e1dd0a2fSth 
1315*e1dd0a2fSth 	if (!server_addr) {
1316*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
1317*e1dd0a2fSth 	}
1318*e1dd0a2fSth 
1319*e1dd0a2fSth 	__s_api_setInitMode();
1320*e1dd0a2fSth 
1321*e1dd0a2fSth 	/*
1322*e1dd0a2fSth 	 * All the credentials will be taken from the current
1323*e1dd0a2fSth 	 * libsldap configuration.
1324*e1dd0a2fSth 	 */
1325*e1dd0a2fSth 	if ((ret_code = __s_api_getConnection(server_addr,
1326*e1dd0a2fSth 	    NS_LDAP_NEW_CONN,
1327*e1dd0a2fSth 	    NULL,
1328*e1dd0a2fSth 	    &sessionId,
1329*e1dd0a2fSth 	    &session,
1330*e1dd0a2fSth 	    errorp,
1331*e1dd0a2fSth 	    0,
1332*e1dd0a2fSth 	    0,
1333*e1dd0a2fSth 	    NULL)) != NS_LDAP_SUCCESS) {
1334*e1dd0a2fSth 		/* Fallback to anonymous mode is disabled. Stop. */
1335*e1dd0a2fSth 		if (anon_fallback == 0) {
1336*e1dd0a2fSth 			syslog(LOG_WARNING,
1337*e1dd0a2fSth 			    gettext("libsldap: can not get the root DSE from "
1338*e1dd0a2fSth 			    " the %s server: %s. "
1339*e1dd0a2fSth 			    "Falling back to anonymous disabled.\n"),
1340*e1dd0a2fSth 			    server_addr,
1341*e1dd0a2fSth 			    errorp && *errorp && (*errorp)->message ?
1342*e1dd0a2fSth 			    (*errorp)->message : "");
1343*e1dd0a2fSth 			if (errorp != NULL && *errorp != NULL) {
1344*e1dd0a2fSth 				(void) __ns_ldap_freeError(errorp);
1345*e1dd0a2fSth 			}
1346*e1dd0a2fSth 			__s_api_unsetInitMode();
1347*e1dd0a2fSth 			return (ret_code);
1348*e1dd0a2fSth 		}
1349*e1dd0a2fSth 
1350*e1dd0a2fSth 		/*
1351*e1dd0a2fSth 		 * Fallback to anonymous, non-SSL mode for backward
1352*e1dd0a2fSth 		 * compatibility reasons. This mode should only be used when
1353*e1dd0a2fSth 		 * this function (__ns_ldap_getRootDSE) is called from
1354*e1dd0a2fSth 		 * ldap_cachemgr(1M).
1355*e1dd0a2fSth 		 */
1356*e1dd0a2fSth 		syslog(LOG_WARNING,
1357*e1dd0a2fSth 		    gettext("libsldap: Falling back to anonymous, non-SSL"
1358*e1dd0a2fSth 		    " mode for __ns_ldap_getRootDSE. %s\n"),
1359*e1dd0a2fSth 		    errorp && *errorp && (*errorp)->message ?
1360*e1dd0a2fSth 		    (*errorp)->message : "");
1361*e1dd0a2fSth 
1362*e1dd0a2fSth 		/* Setup the anon credential for anonymous connection. */
1363*e1dd0a2fSth 		(void) memset(&anon, 0, sizeof (ns_cred_t));
1364*e1dd0a2fSth 		anon.auth.type = NS_LDAP_AUTH_NONE;
1365*e1dd0a2fSth 
1366*e1dd0a2fSth 		if (*errorp != NULL) {
1367*e1dd0a2fSth 			(void) __ns_ldap_freeError(errorp);
1368*e1dd0a2fSth 		}
1369*e1dd0a2fSth 		*errorp = NULL;
1370*e1dd0a2fSth 
1371*e1dd0a2fSth 		ret_code = __s_api_getConnection(server_addr,
1372*e1dd0a2fSth 		    NS_LDAP_NEW_CONN,
1373*e1dd0a2fSth 		    &anon,
1374*e1dd0a2fSth 		    &sessionId,
1375*e1dd0a2fSth 		    &session,
1376*e1dd0a2fSth 		    errorp,
1377*e1dd0a2fSth 		    0,
1378*e1dd0a2fSth 		    0,
1379*e1dd0a2fSth 		    NULL);
1380*e1dd0a2fSth 
1381*e1dd0a2fSth 		if (ret_code != NS_LDAP_SUCCESS) {
1382*e1dd0a2fSth 			__s_api_unsetInitMode();
1383*e1dd0a2fSth 			return (ret_code);
1384*e1dd0a2fSth 		}
1385*e1dd0a2fSth 	}
1386*e1dd0a2fSth 
1387*e1dd0a2fSth 	__s_api_unsetInitMode();
1388*e1dd0a2fSth 
1389*e1dd0a2fSth 	/* get search timeout value */
1390*e1dd0a2fSth 	(void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P, &paramVal, errorp);
1391*e1dd0a2fSth 	if (paramVal != NULL && *paramVal != NULL) {
1392*e1dd0a2fSth 		tv.tv_sec = **((int **)paramVal);
1393*e1dd0a2fSth 		(void) __ns_ldap_freeParam(&paramVal);
1394*e1dd0a2fSth 	}
1395*e1dd0a2fSth 	if (*errorp != NULL) {
1396*e1dd0a2fSth 		(void) __ns_ldap_freeError(errorp);
1397*e1dd0a2fSth 	}
1398*e1dd0a2fSth 
1399*e1dd0a2fSth 	/* Get root DSE from the server specified by the caller. */
1400*e1dd0a2fSth 	attrs[0] = "supportedControl";
1401*e1dd0a2fSth 	attrs[1] = "supportedsaslmechanisms";
1402*e1dd0a2fSth 	attrs[2] = NULL;
1403*e1dd0a2fSth 	ldap_rc = ldap_search_ext_s(session->ld,
1404*e1dd0a2fSth 	    "",
1405*e1dd0a2fSth 	    LDAP_SCOPE_BASE,
1406*e1dd0a2fSth 	    "(objectclass=*)",
1407*e1dd0a2fSth 	    attrs,
1408*e1dd0a2fSth 	    0,
1409*e1dd0a2fSth 	    NULL,
1410*e1dd0a2fSth 	    NULL,
1411*e1dd0a2fSth 	    &tv,
1412*e1dd0a2fSth 	    0,
1413*e1dd0a2fSth 	    &resultMsg);
1414*e1dd0a2fSth 
1415*e1dd0a2fSth 	if (ldap_rc != LDAP_SUCCESS) {
1416*e1dd0a2fSth 		/*
1417*e1dd0a2fSth 		 * If the root DSE was not found, the server does
1418*e1dd0a2fSth 		 * not comply with the LDAP v3 protocol.
1419*e1dd0a2fSth 		 */
1420*e1dd0a2fSth 		(void) ldap_get_option(session->ld,
1421*e1dd0a2fSth 		    LDAP_OPT_ERROR_NUMBER,
1422*e1dd0a2fSth 		    &ldaperrno);
1423*e1dd0a2fSth 		(void) snprintf(errmsg,
1424*e1dd0a2fSth 		    sizeof (errmsg),
1425*e1dd0a2fSth 		    gettext(ldap_err2string(ldaperrno)));
1426*e1dd0a2fSth 		MKERROR(LOG_ERR,
1427*e1dd0a2fSth 		    *errorp,
1428*e1dd0a2fSth 		    NS_LDAP_OP_FAILED,
1429*e1dd0a2fSth 		    strdup(errmsg),
1430*e1dd0a2fSth 		    NS_LDAP_MEMORY);
1431*e1dd0a2fSth 
1432*e1dd0a2fSth 		if (resultMsg) {
1433*e1dd0a2fSth 			(void) ldap_msgfree(resultMsg);
1434*e1dd0a2fSth 			resultMsg = NULL;
1435*e1dd0a2fSth 		}
1436*e1dd0a2fSth 
1437*e1dd0a2fSth 		return (NS_LDAP_OP_FAILED);
1438*e1dd0a2fSth 	}
1439*e1dd0a2fSth 
1440*e1dd0a2fSth 	ret_code = convert_to_door_line(session->ld,
1441*e1dd0a2fSth 	    resultMsg,
1442*e1dd0a2fSth 	    INCLUDE_ATTR_NAMES,
1443*e1dd0a2fSth 	    NOT_PROFILE,
1444*e1dd0a2fSth 	    root_dse);
1445*e1dd0a2fSth 	if (ret_code == NS_LDAP_NOTFOUND) {
1446*e1dd0a2fSth 		(void) snprintf(errmsg,
1447*e1dd0a2fSth 		    sizeof (errmsg),
1448*e1dd0a2fSth 		    gettext("No root DSE data "
1449*e1dd0a2fSth 		    "for server %s returned."),
1450*e1dd0a2fSth 		    server_addr);
1451*e1dd0a2fSth 		MKERROR(LOG_ERR,
1452*e1dd0a2fSth 		    *errorp,
1453*e1dd0a2fSth 		    NS_LDAP_NOTFOUND,
1454*e1dd0a2fSth 		    strdup(errmsg),
1455*e1dd0a2fSth 		    NS_LDAP_MEMORY);
1456*e1dd0a2fSth 	}
1457*e1dd0a2fSth 
1458*e1dd0a2fSth 	if (resultMsg) {
1459*e1dd0a2fSth 		(void) ldap_msgfree(resultMsg);
1460*e1dd0a2fSth 		resultMsg = NULL;
1461*e1dd0a2fSth 	}
1462*e1dd0a2fSth 
1463*e1dd0a2fSth 	DropConnection(sessionId, NS_LDAP_NEW_CONN);
1464*e1dd0a2fSth 
1465*e1dd0a2fSth 	return (ret_code);
1466*e1dd0a2fSth }
1467*e1dd0a2fSth 
1468*e1dd0a2fSth /*
1469*e1dd0a2fSth  * This function destroys the local list of root DSEs. The input parameter is
1470*e1dd0a2fSth  * a pointer to the list to be erased.
1471*e1dd0a2fSth  * The type of the pointer passed to this function should be
1472*e1dd0a2fSth  * (dir_server_list_t *).
1473*e1dd0a2fSth  */
1474*e1dd0a2fSth static
1475*e1dd0a2fSth void *
1476*e1dd0a2fSth disposeOfOldList(void *param)
1477*e1dd0a2fSth {
1478*e1dd0a2fSth 	dir_server_list_t	*old_list = (dir_server_list_t *)param;
1479*e1dd0a2fSth 	long			i = 0, j;
1480*e1dd0a2fSth 
1481*e1dd0a2fSth 	(void) rw_wrlock(&old_list->listDestroyLock);
1482*e1dd0a2fSth 	/* Destroy the old list */
1483*e1dd0a2fSth 	while (old_list->nsServers[i]) {
1484*e1dd0a2fSth 		free(old_list->nsServers[i]->ip);
1485*e1dd0a2fSth 		j = 0;
1486*e1dd0a2fSth 		while (old_list->nsServers[i]->controls &&
1487*e1dd0a2fSth 		    old_list->nsServers[i]->controls[j]) {
1488*e1dd0a2fSth 			free(old_list->nsServers[i]->controls[j]);
1489*e1dd0a2fSth 			++j;
1490*e1dd0a2fSth 		}
1491*e1dd0a2fSth 		free(old_list->nsServers[i]->controls);
1492*e1dd0a2fSth 		j = 0;
1493*e1dd0a2fSth 		while (old_list->nsServers[i]->saslMech &&
1494*e1dd0a2fSth 		    old_list->nsServers[i]->saslMech[j]) {
1495*e1dd0a2fSth 			free(old_list->nsServers[i]->saslMech[j]);
1496*e1dd0a2fSth 			++j;
1497*e1dd0a2fSth 		}
1498*e1dd0a2fSth 		free(old_list->nsServers[i]->saslMech);
1499*e1dd0a2fSth 		++i;
1500*e1dd0a2fSth 	}
1501*e1dd0a2fSth 	/*
1502*e1dd0a2fSth 	 * All the structures pointed by old_list->nsServers were allocated
1503*e1dd0a2fSth 	 * in one chunck. The nsServers[0] pointer points to the beginning
1504*e1dd0a2fSth 	 * of that chunck.
1505*e1dd0a2fSth 	 */
1506*e1dd0a2fSth 	free(old_list->nsServers[0]);
1507*e1dd0a2fSth 	free(old_list->nsServers);
1508*e1dd0a2fSth 	(void) rw_unlock(&old_list->listDestroyLock);
1509*e1dd0a2fSth 	(void) rwlock_destroy(&old_list->listDestroyLock);
1510*e1dd0a2fSth 	free(old_list);
1511*e1dd0a2fSth 
1512*e1dd0a2fSth 	return (NULL);
1513*e1dd0a2fSth }
1514*e1dd0a2fSth 
1515*e1dd0a2fSth /*
1516*e1dd0a2fSth  * This function cancels the Standalone mode and destroys the list of root DSEs.
1517*e1dd0a2fSth  */
1518*e1dd0a2fSth void
1519*e1dd0a2fSth __ns_ldap_cancelStandalone(void)
1520*e1dd0a2fSth {
1521*e1dd0a2fSth 	dir_server_list_t	*old_list;
1522*e1dd0a2fSth 
1523*e1dd0a2fSth 	(void) mutex_lock(&dir_servers.listReplaceLock);
1524*e1dd0a2fSth 	dir_servers.standalone = 0;
1525*e1dd0a2fSth 	if (!dir_servers.list) {
1526*e1dd0a2fSth 		(void) mutex_unlock(&dir_servers.listReplaceLock);
1527*e1dd0a2fSth 		return;
1528*e1dd0a2fSth 	}
1529*e1dd0a2fSth 	old_list = dir_servers.list;
1530*e1dd0a2fSth 	dir_servers.list = NULL;
1531*e1dd0a2fSth 	(void) mutex_unlock(&dir_servers.listReplaceLock);
1532*e1dd0a2fSth 
1533*e1dd0a2fSth 	(void) disposeOfOldList(old_list);
1534*e1dd0a2fSth }
1535*e1dd0a2fSth 
1536*e1dd0a2fSth 
1537*e1dd0a2fSth static
1538*e1dd0a2fSth void*
1539*e1dd0a2fSth create_ns_servers_entry(void *param)
1540*e1dd0a2fSth {
1541*e1dd0a2fSth #define	CHUNK_SIZE 16
1542*e1dd0a2fSth 
1543*e1dd0a2fSth 	dir_server_t		*server = (dir_server_t *)param;
1544*e1dd0a2fSth 	ns_ldap_return_code	*retCode = calloc(1,
1545*e1dd0a2fSth 	    sizeof (ns_ldap_return_code));
1546*e1dd0a2fSth 	uint32_t		sc_counter = 0, sm_counter = 0;
1547*e1dd0a2fSth 	uint32_t		sc_mem_blocks = 1, sm_mem_blocks = 1;
1548*e1dd0a2fSth 	char			*rootDSE = NULL, *attr, *val, *rest, **ptr;
1549*e1dd0a2fSth 	ns_ldap_error_t		*error = NULL;
1550*e1dd0a2fSth 
1551*e1dd0a2fSth 	if (retCode == NULL) {
1552*e1dd0a2fSth 		return (NULL);
1553*e1dd0a2fSth 	}
1554*e1dd0a2fSth 
1555*e1dd0a2fSth 	/*
1556*e1dd0a2fSth 	 * We call this function in non anon-fallback mode because we
1557*e1dd0a2fSth 	 * want the whole procedure to fail as soon as possible to
1558*e1dd0a2fSth 	 * indicate there are problems with connecting to the server.
1559*e1dd0a2fSth 	 */
1560*e1dd0a2fSth 	*retCode = __ns_ldap_getRootDSE(server->ip,
1561*e1dd0a2fSth 	    &rootDSE,
1562*e1dd0a2fSth 	    &error,
1563*e1dd0a2fSth 	    SA_ALLOW_FALLBACK);
1564*e1dd0a2fSth 
1565*e1dd0a2fSth 	if (*retCode == NS_LDAP_MEMORY) {
1566*e1dd0a2fSth 		free(retCode);
1567*e1dd0a2fSth 		return (NULL);
1568*e1dd0a2fSth 	}
1569*e1dd0a2fSth 
1570*e1dd0a2fSth 	/*
1571*e1dd0a2fSth 	 * If the root DSE can not be obtained, log an error and keep the
1572*e1dd0a2fSth 	 * server.
1573*e1dd0a2fSth 	 */
1574*e1dd0a2fSth 	if (*retCode != NS_LDAP_SUCCESS) {
1575*e1dd0a2fSth 		server->status = INFO_SERVER_ERROR;
1576*e1dd0a2fSth 		syslog(LOG_WARNING,
1577*e1dd0a2fSth 		    gettext("libsldap (\"standalone\" mode): "
1578*e1dd0a2fSth 		    "can not obtain the root DSE from %s. %s"),
1579*e1dd0a2fSth 		    server->ip,
1580*e1dd0a2fSth 		    error && error->message ? error->message : "");
1581*e1dd0a2fSth 		if (error) {
1582*e1dd0a2fSth 			(void) __ns_ldap_freeError(&error);
1583*e1dd0a2fSth 		}
1584*e1dd0a2fSth 		return (retCode);
1585*e1dd0a2fSth 	}
1586*e1dd0a2fSth 
1587*e1dd0a2fSth 	/* Get the first attribute of the root DSE. */
1588*e1dd0a2fSth 	attr = strtok_r(rootDSE, DOORLINESEP, &rest);
1589*e1dd0a2fSth 	if (attr == NULL) {
1590*e1dd0a2fSth 		free(rootDSE);
1591*e1dd0a2fSth 		server->status = INFO_SERVER_ERROR;
1592*e1dd0a2fSth 		syslog(LOG_WARNING,
1593*e1dd0a2fSth 		    gettext("libsldap (\"standalone\" mode): "
1594*e1dd0a2fSth 		    "the root DSE from %s is empty or corrupted."),
1595*e1dd0a2fSth 		    server->ip);
1596*e1dd0a2fSth 		*retCode = NS_LDAP_INTERNAL;
1597*e1dd0a2fSth 		return (retCode);
1598*e1dd0a2fSth 	}
1599*e1dd0a2fSth 
1600*e1dd0a2fSth 	server->controls = (char **)calloc(CHUNK_SIZE, sizeof (char *));
1601*e1dd0a2fSth 	server->saslMech = (char **)calloc(CHUNK_SIZE, sizeof (char *));
1602*e1dd0a2fSth 	if (server->controls == NULL || server->saslMech == NULL) {
1603*e1dd0a2fSth 		free(rootDSE);
1604*e1dd0a2fSth 		free(retCode);
1605*e1dd0a2fSth 		return (NULL);
1606*e1dd0a2fSth 	}
1607*e1dd0a2fSth 
1608*e1dd0a2fSth 	do {
1609*e1dd0a2fSth 		if ((val = strchr(attr, '=')) == NULL) {
1610*e1dd0a2fSth 			continue;
1611*e1dd0a2fSth 		}
1612*e1dd0a2fSth 		++val;
1613*e1dd0a2fSth 
1614*e1dd0a2fSth 		if (strncasecmp(attr,
1615*e1dd0a2fSth 		    _SASLMECHANISM,
1616*e1dd0a2fSth 		    _SASLMECHANISM_LEN) == 0) {
1617*e1dd0a2fSth 			if (sm_counter == CHUNK_SIZE * sm_mem_blocks - 1) {
1618*e1dd0a2fSth 				ptr = (char **)realloc(server->saslMech,
1619*e1dd0a2fSth 				    CHUNK_SIZE *
1620*e1dd0a2fSth 				    ++sm_mem_blocks *
1621*e1dd0a2fSth 				    sizeof (char *));
1622*e1dd0a2fSth 				if (ptr == NULL) {
1623*e1dd0a2fSth 					*retCode = NS_LDAP_MEMORY;
1624*e1dd0a2fSth 					break;
1625*e1dd0a2fSth 				}
1626*e1dd0a2fSth 				bzero((char *)ptr +
1627*e1dd0a2fSth 				    (sm_counter + 1) *
1628*e1dd0a2fSth 				    sizeof (char *),
1629*e1dd0a2fSth 				    CHUNK_SIZE *
1630*e1dd0a2fSth 				    sm_mem_blocks *
1631*e1dd0a2fSth 				    sizeof (char *) -
1632*e1dd0a2fSth 				    (sm_counter + 1) *
1633*e1dd0a2fSth 				    sizeof (char *));
1634*e1dd0a2fSth 				server->saslMech = ptr;
1635*e1dd0a2fSth 			}
1636*e1dd0a2fSth 			server->saslMech[sm_counter] = strdup(val);
1637*e1dd0a2fSth 			if (server->saslMech[sm_counter] == NULL) {
1638*e1dd0a2fSth 				*retCode = NS_LDAP_MEMORY;
1639*e1dd0a2fSth 				break;
1640*e1dd0a2fSth 			}
1641*e1dd0a2fSth 			++sm_counter;
1642*e1dd0a2fSth 			continue;
1643*e1dd0a2fSth 		}
1644*e1dd0a2fSth 		if (strncasecmp(attr,
1645*e1dd0a2fSth 		    _SUPPORTEDCONTROL,
1646*e1dd0a2fSth 		    _SUPPORTEDCONTROL_LEN) == 0) {
1647*e1dd0a2fSth 			if (sc_counter == CHUNK_SIZE * sc_mem_blocks - 1) {
1648*e1dd0a2fSth 				ptr = (char **)realloc(server->controls,
1649*e1dd0a2fSth 				    CHUNK_SIZE *
1650*e1dd0a2fSth 				    ++sc_mem_blocks *
1651*e1dd0a2fSth 				    sizeof (char *));
1652*e1dd0a2fSth 				if (ptr == NULL) {
1653*e1dd0a2fSth 					*retCode = NS_LDAP_MEMORY;
1654*e1dd0a2fSth 					break;
1655*e1dd0a2fSth 				}
1656*e1dd0a2fSth 				bzero((char *)ptr +
1657*e1dd0a2fSth 				    (sc_counter + 1) *
1658*e1dd0a2fSth 				    sizeof (char *),
1659*e1dd0a2fSth 				    CHUNK_SIZE *
1660*e1dd0a2fSth 				    sc_mem_blocks *
1661*e1dd0a2fSth 				    sizeof (char *) -
1662*e1dd0a2fSth 				    (sc_counter + 1) *
1663*e1dd0a2fSth 				    sizeof (char *));
1664*e1dd0a2fSth 				server->controls = ptr;
1665*e1dd0a2fSth 			}
1666*e1dd0a2fSth 
1667*e1dd0a2fSth 			server->controls[sc_counter] = strdup(val);
1668*e1dd0a2fSth 			if (server->controls[sc_counter] == NULL) {
1669*e1dd0a2fSth 				*retCode = NS_LDAP_MEMORY;
1670*e1dd0a2fSth 				break;
1671*e1dd0a2fSth 			}
1672*e1dd0a2fSth 			++sc_counter;
1673*e1dd0a2fSth 			continue;
1674*e1dd0a2fSth 		}
1675*e1dd0a2fSth 
1676*e1dd0a2fSth 	} while (attr = strtok_r(NULL, DOORLINESEP, &rest));
1677*e1dd0a2fSth 
1678*e1dd0a2fSth 	free(rootDSE);
1679*e1dd0a2fSth 
1680*e1dd0a2fSth 	if (*retCode == NS_LDAP_MEMORY) {
1681*e1dd0a2fSth 		free(retCode);
1682*e1dd0a2fSth 		return (NULL);
1683*e1dd0a2fSth 	}
1684*e1dd0a2fSth 
1685*e1dd0a2fSth 	server->controls[sc_counter] = NULL;
1686*e1dd0a2fSth 	server->saslMech[sm_counter] = NULL;
1687*e1dd0a2fSth 
1688*e1dd0a2fSth 	server->status = INFO_SERVER_UP;
1689*e1dd0a2fSth 
1690*e1dd0a2fSth 	return (retCode);
1691*e1dd0a2fSth #undef CHUNK_SIZE
1692*e1dd0a2fSth }
1693*e1dd0a2fSth 
1694*e1dd0a2fSth 
1695*e1dd0a2fSth /*
1696*e1dd0a2fSth  * This function creates a new local list of root DSEs from all the servers
1697*e1dd0a2fSth  * mentioned in the DUAProfile (or local NS BEC) and returns
1698*e1dd0a2fSth  * a pointer to the list.
1699*e1dd0a2fSth  */
1700*e1dd0a2fSth static
1701*e1dd0a2fSth ns_ldap_return_code
1702*e1dd0a2fSth createDirServerList(dir_server_list_t **new_list,
1703*e1dd0a2fSth 		ns_ldap_error_t **errorp)
1704*e1dd0a2fSth {
1705*e1dd0a2fSth 	char			**serverList;
1706*e1dd0a2fSth 	ns_ldap_return_code	retCode = NS_LDAP_SUCCESS;
1707*e1dd0a2fSth 	dir_server_t		*tmpSrvArray;
1708*e1dd0a2fSth 	long			srvListLength, i;
1709*e1dd0a2fSth 	thread_t		*thrPool, thrID;
1710*e1dd0a2fSth 	void			*status = NULL;
1711*e1dd0a2fSth 
1712*e1dd0a2fSth 	if (errorp == NULL) {
1713*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
1714*e1dd0a2fSth 	}
1715*e1dd0a2fSth 
1716*e1dd0a2fSth 	*errorp = NULL;
1717*e1dd0a2fSth 
1718*e1dd0a2fSth 	if (new_list == NULL) {
1719*e1dd0a2fSth 		return (NS_LDAP_INVALID_PARAM);
1720*e1dd0a2fSth 	}
1721*e1dd0a2fSth 
1722*e1dd0a2fSth 	retCode = __s_api_getServers(&serverList, errorp);
1723*e1dd0a2fSth 	if (retCode != NS_LDAP_SUCCESS || serverList == NULL) {
1724*e1dd0a2fSth 		return (retCode);
1725*e1dd0a2fSth 	}
1726*e1dd0a2fSth 
1727*e1dd0a2fSth 	for (i = 0; serverList[i]; ++i) {
1728*e1dd0a2fSth 		;
1729*e1dd0a2fSth 	}
1730*e1dd0a2fSth 	srvListLength = i;
1731*e1dd0a2fSth 
1732*e1dd0a2fSth 	thrPool = calloc(srvListLength, sizeof (thread_t));
1733*e1dd0a2fSth 	if (thrPool == NULL) {
1734*e1dd0a2fSth 		__s_api_free2dArray(serverList);
1735*e1dd0a2fSth 		return (NS_LDAP_MEMORY);
1736*e1dd0a2fSth 	}
1737*e1dd0a2fSth 
1738*e1dd0a2fSth 	*new_list = (dir_server_list_t *)calloc(1,
1739*e1dd0a2fSth 	    sizeof (dir_server_list_t));
1740*e1dd0a2fSth 	if (*new_list == NULL) {
1741*e1dd0a2fSth 		__s_api_free2dArray(serverList);
1742*e1dd0a2fSth 		free(thrPool);
1743*e1dd0a2fSth 		return (NS_LDAP_MEMORY);
1744*e1dd0a2fSth 	}
1745*e1dd0a2fSth 	(void) rwlock_init(&(*new_list)->listDestroyLock, USYNC_THREAD, NULL);
1746*e1dd0a2fSth 
1747*e1dd0a2fSth 	(*new_list)->nsServers = (dir_server_t **)calloc(srvListLength + 1,
1748*e1dd0a2fSth 	    sizeof (dir_server_t *));
1749*e1dd0a2fSth 	if ((*new_list)->nsServers == NULL) {
1750*e1dd0a2fSth 		free(*new_list);
1751*e1dd0a2fSth 		*new_list = NULL;
1752*e1dd0a2fSth 		__s_api_free2dArray(serverList);
1753*e1dd0a2fSth 		free(thrPool);
1754*e1dd0a2fSth 		return (NS_LDAP_MEMORY);
1755*e1dd0a2fSth 	}
1756*e1dd0a2fSth 
1757*e1dd0a2fSth 	/*
1758*e1dd0a2fSth 	 * Allocate a set of dir_server_t structures as an array,
1759*e1dd0a2fSth 	 * with one alloc call and then initialize the nsServers pointers
1760*e1dd0a2fSth 	 * with the addresses of the array's members.
1761*e1dd0a2fSth 	 */
1762*e1dd0a2fSth 	tmpSrvArray = (dir_server_t *)calloc(srvListLength,
1763*e1dd0a2fSth 	    sizeof (dir_server_t));
1764*e1dd0a2fSth 	for (i = 0; i < srvListLength; ++i) {
1765*e1dd0a2fSth 		(*new_list)->nsServers[i] = &tmpSrvArray[i];
1766*e1dd0a2fSth 
1767*e1dd0a2fSth 		(*new_list)->nsServers[i]->info = INFO_STATUS_NEW;
1768*e1dd0a2fSth 		(void) mutex_init(&(*new_list)->nsServers[i]->updateStatus,
1769*e1dd0a2fSth 		    USYNC_THREAD,
1770*e1dd0a2fSth 		    NULL);
1771*e1dd0a2fSth 
1772*e1dd0a2fSth 		(*new_list)->nsServers[i]->ip = strdup(serverList[i]);
1773*e1dd0a2fSth 		if ((*new_list)->nsServers[i]->ip == NULL) {
1774*e1dd0a2fSth 			retCode = NS_LDAP_MEMORY;
1775*e1dd0a2fSth 			break;
1776*e1dd0a2fSth 		}
1777*e1dd0a2fSth 
1778*e1dd0a2fSth 		(*new_list)->nsServers[i]->status = INFO_SERVER_CONNECTING;
1779*e1dd0a2fSth 
1780*e1dd0a2fSth 		switch (thr_create(NULL,
1781*e1dd0a2fSth 		    0,
1782*e1dd0a2fSth 		    create_ns_servers_entry,
1783*e1dd0a2fSth 		    (*new_list)->nsServers[i],
1784*e1dd0a2fSth 		    0,
1785*e1dd0a2fSth 		    &thrID)) {
1786*e1dd0a2fSth 		case EAGAIN:
1787*e1dd0a2fSth 			(*new_list)->nsServers[i]->status =
1788*e1dd0a2fSth 			    INFO_SERVER_ERROR;
1789*e1dd0a2fSth 			continue;
1790*e1dd0a2fSth 			break;
1791*e1dd0a2fSth 		case ENOMEM:
1792*e1dd0a2fSth 			(*new_list)->nsServers[i]->status =
1793*e1dd0a2fSth 			    INFO_SERVER_ERROR;
1794*e1dd0a2fSth 			continue;
1795*e1dd0a2fSth 			break;
1796*e1dd0a2fSth 		default:
1797*e1dd0a2fSth 			thrPool[i] = thrID;
1798*e1dd0a2fSth 			continue;
1799*e1dd0a2fSth 			break;
1800*e1dd0a2fSth 		}
1801*e1dd0a2fSth 	}
1802*e1dd0a2fSth 
1803*e1dd0a2fSth 	for (i = 0; i < srvListLength; ++i) {
1804*e1dd0a2fSth 		if (thrPool[i] != 0 &&
1805*e1dd0a2fSth 		    thr_join(thrPool[i], NULL, &status) == 0) {
1806*e1dd0a2fSth 			if (status == NULL) {
1807*e1dd0a2fSth 				/*
1808*e1dd0a2fSth 				 * Some memory allocation problems occured. Just
1809*e1dd0a2fSth 				 * ignore the server and hope there will be some
1810*e1dd0a2fSth 				 * other good ones.
1811*e1dd0a2fSth 				 */
1812*e1dd0a2fSth 				(*new_list)->nsServers[i]->status =
1813*e1dd0a2fSth 				    INFO_SERVER_ERROR;
1814*e1dd0a2fSth 			}
1815*e1dd0a2fSth 			free(status);
1816*e1dd0a2fSth 		}
1817*e1dd0a2fSth 	}
1818*e1dd0a2fSth 
1819*e1dd0a2fSth 	__s_api_free2dArray(serverList);
1820*e1dd0a2fSth 	free(thrPool);
1821*e1dd0a2fSth 
1822*e1dd0a2fSth 	if (retCode == NS_LDAP_MEMORY) {
1823*e1dd0a2fSth 		(void) disposeOfOldList(*new_list);
1824*e1dd0a2fSth 		return (NS_LDAP_MEMORY);
1825*e1dd0a2fSth 	}
1826*e1dd0a2fSth 
1827*e1dd0a2fSth 	return (NS_LDAP_SUCCESS);
1828*e1dd0a2fSth }
1829*e1dd0a2fSth 
1830*e1dd0a2fSth /*
1831*e1dd0a2fSth  * This functions replaces the local list of root DSEs with a new one and starts
1832*e1dd0a2fSth  * a thread destroying the old list. There is no need for other threads to wait
1833*e1dd0a2fSth  * until the old list will be destroyed.
1834*e1dd0a2fSth  * Since it is possible that more than one thread can start creating the list,
1835*e1dd0a2fSth  * this function should be protected by mutexes to be sure that only one thread
1836*e1dd0a2fSth  * performs the initialization.
1837*e1dd0a2fSth  */
1838*e1dd0a2fSth static
1839*e1dd0a2fSth ns_ldap_return_code
1840*e1dd0a2fSth initGlobalList(ns_ldap_error_t **error)
1841*e1dd0a2fSth {
1842*e1dd0a2fSth 	dir_server_list_t	*new_list, *old_list;
1843*e1dd0a2fSth 	ns_ldap_return_code	ret_code;
1844*e1dd0a2fSth 	thread_t		tid;
1845*e1dd0a2fSth 
1846*e1dd0a2fSth 	ret_code = createDirServerList(&new_list, error);
1847*e1dd0a2fSth 	if (ret_code != NS_LDAP_SUCCESS) {
1848*e1dd0a2fSth 		return (ret_code);
1849*e1dd0a2fSth 	}
1850*e1dd0a2fSth 
1851*e1dd0a2fSth 	old_list = dir_servers.list;
1852*e1dd0a2fSth 	dir_servers.list = new_list;
1853*e1dd0a2fSth 
1854*e1dd0a2fSth 	if (old_list) {
1855*e1dd0a2fSth 		(void) thr_create(NULL,
1856*e1dd0a2fSth 		    0,
1857*e1dd0a2fSth 		    disposeOfOldList,
1858*e1dd0a2fSth 		    old_list,
1859*e1dd0a2fSth 		    THR_DETACHED,
1860*e1dd0a2fSth 		    &tid);
1861*e1dd0a2fSth 	}
1862*e1dd0a2fSth 
1863*e1dd0a2fSth 	return (NS_LDAP_SUCCESS);
1864*e1dd0a2fSth }
1865*e1dd0a2fSth 
1866*e1dd0a2fSth static
1867*e1dd0a2fSth struct {
1868*e1dd0a2fSth 	char *authMech;
1869*e1dd0a2fSth 	ns_auth_t auth;
1870*e1dd0a2fSth } authArray[] = {{"none", {NS_LDAP_AUTH_NONE,
1871*e1dd0a2fSth 			NS_LDAP_TLS_NONE,
1872*e1dd0a2fSth 			NS_LDAP_SASL_NONE,
1873*e1dd0a2fSth 			NS_LDAP_SASLOPT_NONE}},
1874*e1dd0a2fSth 		{"simple", {NS_LDAP_AUTH_SIMPLE,
1875*e1dd0a2fSth 			NS_LDAP_TLS_NONE,
1876*e1dd0a2fSth 			NS_LDAP_SASL_NONE,
1877*e1dd0a2fSth 			NS_LDAP_SASLOPT_NONE}},
1878*e1dd0a2fSth 		{"tls:simple", {NS_LDAP_AUTH_TLS,
1879*e1dd0a2fSth 			NS_LDAP_TLS_SIMPLE,
1880*e1dd0a2fSth 			NS_LDAP_SASL_NONE,
1881*e1dd0a2fSth 			NS_LDAP_SASLOPT_NONE}},
1882*e1dd0a2fSth 		{"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS,
1883*e1dd0a2fSth 			NS_LDAP_TLS_SASL,
1884*e1dd0a2fSth 			NS_LDAP_SASL_CRAM_MD5,
1885*e1dd0a2fSth 			NS_LDAP_SASLOPT_NONE}},
1886*e1dd0a2fSth 		{"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS,
1887*e1dd0a2fSth 			NS_LDAP_TLS_SASL,
1888*e1dd0a2fSth 			NS_LDAP_SASL_DIGEST_MD5,
1889*e1dd0a2fSth 			NS_LDAP_SASLOPT_NONE}},
1890*e1dd0a2fSth 		{"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL,
1891*e1dd0a2fSth 			NS_LDAP_TLS_SASL,
1892*e1dd0a2fSth 			NS_LDAP_SASL_CRAM_MD5,
1893*e1dd0a2fSth 			NS_LDAP_SASLOPT_NONE}},
1894*e1dd0a2fSth 		{"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL,
1895*e1dd0a2fSth 			NS_LDAP_TLS_SASL,
1896*e1dd0a2fSth 			NS_LDAP_SASL_DIGEST_MD5,
1897*e1dd0a2fSth 			NS_LDAP_SASLOPT_NONE}},
1898*e1dd0a2fSth 		{"sasl/GSSAPI", {NS_LDAP_AUTH_SASL,
1899*e1dd0a2fSth 			NS_LDAP_TLS_SASL,
1900*e1dd0a2fSth 			NS_LDAP_SASL_GSSAPI,
1901*e1dd0a2fSth 			NS_LDAP_SASLOPT_PRIV | NS_LDAP_SASLOPT_INT}},
1902*e1dd0a2fSth 		{NULL, {NS_LDAP_AUTH_NONE,
1903*e1dd0a2fSth 			NS_LDAP_TLS_NONE,
1904*e1dd0a2fSth 			NS_LDAP_SASL_NONE,
1905*e1dd0a2fSth 			NS_LDAP_SASLOPT_NONE}}};
1906*e1dd0a2fSth 
1907*e1dd0a2fSth ns_ldap_return_code
1908*e1dd0a2fSth __ns_ldap_initAuth(const char *auth_mech,
1909*e1dd0a2fSth 		ns_auth_t *auth,
1910*e1dd0a2fSth 		ns_ldap_error_t **errorp)
1911*e1dd0a2fSth {
1912*e1dd0a2fSth 	uint32_t	i;
1913*e1dd0a2fSth 	char		errmsg[MAXERROR];
1914*e1dd0a2fSth 
1915*e1dd0a2fSth 	if (auth_mech == NULL) {
1916*e1dd0a2fSth 		(void) snprintf(errmsg,
1917*e1dd0a2fSth 		    sizeof (errmsg),
1918*e1dd0a2fSth 		    gettext("Invalid authentication method specified\n"));
1919*e1dd0a2fSth 		MKERROR(LOG_WARNING,
1920*e1dd0a2fSth 		    *errorp,
1921*e1dd0a2fSth 		    NS_LDAP_INTERNAL,
1922*e1dd0a2fSth 		    strdup(errmsg),
1923*e1dd0a2fSth 		    NS_LDAP_MEMORY);
1924*e1dd0a2fSth 		return (NS_LDAP_INTERNAL);
1925*e1dd0a2fSth 	}
1926*e1dd0a2fSth 
1927*e1dd0a2fSth 	for (i = 0; authArray[i].authMech != NULL; ++i) {
1928*e1dd0a2fSth 		if (strcasecmp(auth_mech, authArray[i].authMech) == 0) {
1929*e1dd0a2fSth 			*auth = authArray[i].auth;
1930*e1dd0a2fSth 			return (NS_LDAP_SUCCESS);
1931*e1dd0a2fSth 		}
1932*e1dd0a2fSth 	}
1933*e1dd0a2fSth 
1934*e1dd0a2fSth 	(void) snprintf(errmsg,
1935*e1dd0a2fSth 	    sizeof (errmsg),
1936*e1dd0a2fSth 	    gettext("Invalid authentication method specified\n"));
1937*e1dd0a2fSth 	MKERROR(LOG_WARNING,
1938*e1dd0a2fSth 	    *errorp,
1939*e1dd0a2fSth 	    NS_LDAP_INTERNAL,
1940*e1dd0a2fSth 	    strdup(errmsg),
1941*e1dd0a2fSth 	    NS_LDAP_MEMORY);
1942*e1dd0a2fSth 	return (NS_LDAP_INTERNAL);
1943*e1dd0a2fSth }
1944*e1dd0a2fSth 
1945*e1dd0a2fSth /*
1946*e1dd0a2fSth  * This function "informs" libsldap that a client application has specified
1947*e1dd0a2fSth  * a directory to use. The function obtains a DUAProfile, credentials,
1948*e1dd0a2fSth  * and naming context. During all further operations on behalf
1949*e1dd0a2fSth  * of the application requested a standalone schema libsldap will use
1950*e1dd0a2fSth  * the information obtained by __ns_ldap_initStandalone() instead of
1951*e1dd0a2fSth  * door_call(3C)ing ldap_cachemgr(1M).
1952*e1dd0a2fSth  *
1953*e1dd0a2fSth  * INPUT:
1954*e1dd0a2fSth  *     sa_conf - a structure describing where and in which way to obtain all
1955*e1dd0a2fSth  *               the configuration describing how to communicate to
1956*e1dd0a2fSth  *               a choosen LDAP directory,
1957*e1dd0a2fSth  *     errorp - an error object describing an error occured.
1958*e1dd0a2fSth  */
1959*e1dd0a2fSth ns_ldap_return_code
1960*e1dd0a2fSth __ns_ldap_initStandalone(const ns_standalone_conf_t *sa_conf,
1961*e1dd0a2fSth 			ns_ldap_error_t	**errorp) {
1962*e1dd0a2fSth 
1963*e1dd0a2fSth 	ns_cred_t	user_cred = {{NS_LDAP_AUTH_NONE,
1964*e1dd0a2fSth 					NS_LDAP_TLS_NONE,
1965*e1dd0a2fSth 					NS_LDAP_SASL_NONE,
1966*e1dd0a2fSth 					NS_LDAP_SASLOPT_NONE},
1967*e1dd0a2fSth 					NULL,
1968*e1dd0a2fSth 					{NULL, NULL}};
1969*e1dd0a2fSth 	char		*dua_profile = NULL;
1970*e1dd0a2fSth 	char		errmsg[MAXERROR];
1971*e1dd0a2fSth 	ns_config_t 	*cfg;
1972*e1dd0a2fSth 	int		ret_code;
1973*e1dd0a2fSth 
1974*e1dd0a2fSth 	if (sa_conf->SA_BIND_DN == NULL && sa_conf->SA_BIND_PWD != NULL ||
1975*e1dd0a2fSth 	    sa_conf->SA_BIND_DN != NULL && sa_conf->SA_BIND_PWD == NULL) {
1976*e1dd0a2fSth 		(void) snprintf(errmsg,
1977*e1dd0a2fSth 		    sizeof (errmsg),
1978*e1dd0a2fSth 		    gettext("Bind DN and bind password"
1979*e1dd0a2fSth 		    " must both be provided\n"));
1980*e1dd0a2fSth 		MKERROR(LOG_ERR,
1981*e1dd0a2fSth 		    *errorp,
1982*e1dd0a2fSth 		    NS_CONFIG_NOTLOADED,
1983*e1dd0a2fSth 		    strdup(errmsg),
1984*e1dd0a2fSth 		    NS_LDAP_MEMORY);
1985*e1dd0a2fSth 		return (NS_LDAP_INTERNAL);
1986*e1dd0a2fSth 	}
1987*e1dd0a2fSth 
1988*e1dd0a2fSth 	switch (sa_conf->type) {
1989*e1dd0a2fSth 	case NS_LDAP_SERVER:
1990*e1dd0a2fSth 		if (sa_conf->SA_BIND_DN != NULL) {
1991*e1dd0a2fSth 			user_cred.cred.unix_cred.userID = sa_conf->SA_BIND_DN;
1992*e1dd0a2fSth 			user_cred.auth.type = NS_LDAP_AUTH_SIMPLE;
1993*e1dd0a2fSth 		}
1994*e1dd0a2fSth 
1995*e1dd0a2fSth 		if (sa_conf->SA_BIND_PWD != NULL) {
1996*e1dd0a2fSth 			user_cred.cred.unix_cred.passwd = sa_conf->SA_BIND_PWD;
1997*e1dd0a2fSth 		}
1998*e1dd0a2fSth 
1999*e1dd0a2fSth 		if (sa_conf->SA_AUTH != NULL) {
2000*e1dd0a2fSth 			user_cred.auth.type = sa_conf->SA_AUTH->type;
2001*e1dd0a2fSth 			user_cred.auth.tlstype = sa_conf->SA_AUTH->tlstype;
2002*e1dd0a2fSth 			user_cred.auth.saslmech = sa_conf->SA_AUTH->saslmech;
2003*e1dd0a2fSth 			user_cred.auth.saslopt = sa_conf->SA_AUTH->saslopt;
2004*e1dd0a2fSth 		}
2005*e1dd0a2fSth 
2006*e1dd0a2fSth 		if (sa_conf->SA_CERT_PATH != NULL) {
2007*e1dd0a2fSth 			user_cred.hostcertpath = sa_conf->SA_CERT_PATH;
2008*e1dd0a2fSth 		}
2009*e1dd0a2fSth 
2010*e1dd0a2fSth 		ret_code = __ns_ldap_getConnectionInfoFromDUA(
2011*e1dd0a2fSth 		    &sa_conf->ds_profile.server,
2012*e1dd0a2fSth 		    &user_cred,
2013*e1dd0a2fSth 		    &dua_profile,
2014*e1dd0a2fSth 		    NULL,
2015*e1dd0a2fSth 		    errorp);
2016*e1dd0a2fSth 		if (ret_code != NS_LDAP_SUCCESS) {
2017*e1dd0a2fSth 			return (ret_code);
2018*e1dd0a2fSth 		}
2019*e1dd0a2fSth 
2020*e1dd0a2fSth 		cfg = __s_api_create_config_door_str(dua_profile, errorp);
2021*e1dd0a2fSth 		if (cfg == NULL) {
2022*e1dd0a2fSth 			free(dua_profile);
2023*e1dd0a2fSth 			return (NS_LDAP_CONFIG);
2024*e1dd0a2fSth 		}
2025*e1dd0a2fSth 
2026*e1dd0a2fSth 		if (sa_conf->SA_CERT_PATH != NULL) {
2027*e1dd0a2fSth 			char		*certPathAttr;
2028*e1dd0a2fSth 			ParamIndexType	type;
2029*e1dd0a2fSth 
2030*e1dd0a2fSth 			switch (cfg->version) {
2031*e1dd0a2fSth 			case NS_LDAP_V1:
2032*e1dd0a2fSth 				certPathAttr = "NS_LDAP_CERT_PATH";
2033*e1dd0a2fSth 				break;
2034*e1dd0a2fSth 			default:	/* Version 2 */
2035*e1dd0a2fSth 				certPathAttr = "NS_LDAP_HOST_CERTPATH";
2036*e1dd0a2fSth 				break;
2037*e1dd0a2fSth 			}
2038*e1dd0a2fSth 
2039*e1dd0a2fSth 			if (__s_api_get_versiontype(cfg,
2040*e1dd0a2fSth 						certPathAttr,
2041*e1dd0a2fSth 						&type) == 0 &&
2042*e1dd0a2fSth 			    (ret_code = __ns_ldap_setParamValue(cfg,
2043*e1dd0a2fSth 						type,
2044*e1dd0a2fSth 						sa_conf->SA_CERT_PATH,
2045*e1dd0a2fSth 						errorp)) != NS_LDAP_SUCCESS) {
2046*e1dd0a2fSth 				__s_api_destroy_config(cfg);
2047*e1dd0a2fSth 				return (ret_code);
2048*e1dd0a2fSth 			}
2049*e1dd0a2fSth 		}
2050*e1dd0a2fSth 
2051*e1dd0a2fSth 		if (sa_conf->SA_BIND_DN != NULL &&
2052*e1dd0a2fSth 		    sa_conf->SA_BIND_PWD != NULL) {
2053*e1dd0a2fSth 			char buffer[BUFSIZE], *authMethods;
2054*e1dd0a2fSth 
2055*e1dd0a2fSth 			authMethods = __s_api_strValue(cfg,
2056*e1dd0a2fSth 			    buffer,
2057*e1dd0a2fSth 			    BUFSIZE,
2058*e1dd0a2fSth 			    NS_LDAP_AUTH_P,
2059*e1dd0a2fSth 			    NS_FILE_FMT);
2060*e1dd0a2fSth 			if (authMethods != NULL &&
2061*e1dd0a2fSth 			    strstr(authMethods, "sasl/GSSAPI") != NULL) {
2062*e1dd0a2fSth 				/*
2063*e1dd0a2fSth 				 * The received DUAProfile specifies
2064*e1dd0a2fSth 				 * sasl/GSSAPI as an auth. mechanism.
2065*e1dd0a2fSth 				 * The bind DN and password will be
2066*e1dd0a2fSth 				 * ignored.
2067*e1dd0a2fSth 				 */
2068*e1dd0a2fSth 				syslog(LOG_INFO, gettext("sasl/GSSAPI will be "
2069*e1dd0a2fSth 				    "used as an authentication method. "
2070*e1dd0a2fSth 				    "The bind DN and password will "
2071*e1dd0a2fSth 				    "be ignored.\n"));
2072*e1dd0a2fSth 				break;
2073*e1dd0a2fSth 			}
2074*e1dd0a2fSth 
2075*e1dd0a2fSth 			if (__ns_ldap_setParamValue(cfg,
2076*e1dd0a2fSth 						NS_LDAP_BINDDN_P,
2077*e1dd0a2fSth 						sa_conf->SA_BIND_DN,
2078*e1dd0a2fSth 						errorp) != NS_LDAP_SUCCESS) {
2079*e1dd0a2fSth 				__s_api_destroy_config(cfg);
2080*e1dd0a2fSth 				return (NS_LDAP_CONFIG);
2081*e1dd0a2fSth 			}
2082*e1dd0a2fSth 
2083*e1dd0a2fSth 			if (__ns_ldap_setParamValue(cfg,
2084*e1dd0a2fSth 			    NS_LDAP_BINDPASSWD_P,
2085*e1dd0a2fSth 			    sa_conf->SA_BIND_PWD,
2086*e1dd0a2fSth 			    errorp) != NS_LDAP_SUCCESS) {
2087*e1dd0a2fSth 				__s_api_destroy_config(cfg);
2088*e1dd0a2fSth 				return (NS_LDAP_CONFIG);
2089*e1dd0a2fSth 			}
2090*e1dd0a2fSth 		}
2091*e1dd0a2fSth 
2092*e1dd0a2fSth 		break;
2093*e1dd0a2fSth 	default:	/* NS_CACHEMGR */
2094*e1dd0a2fSth 		return (NS_LDAP_SUCCESS);
2095*e1dd0a2fSth 	}
2096*e1dd0a2fSth 
2097*e1dd0a2fSth 	__s_api_init_config(cfg);
2098*e1dd0a2fSth 	__ns_ldap_setServer(TRUE);
2099*e1dd0a2fSth 
2100*e1dd0a2fSth 	(void) mutex_lock(&dir_servers.listReplaceLock);
2101*e1dd0a2fSth 	if ((ret_code = initGlobalList(errorp)) != NS_SUCCESS) {
2102*e1dd0a2fSth 		(void) mutex_unlock(&dir_servers.listReplaceLock);
2103*e1dd0a2fSth 		return (ret_code);
2104*e1dd0a2fSth 	}
2105*e1dd0a2fSth 	dir_servers.standalone = 1;
2106*e1dd0a2fSth 	(void) mutex_unlock(&dir_servers.listReplaceLock);
2107*e1dd0a2fSth 
2108*e1dd0a2fSth 	return (NS_LDAP_SUCCESS);
2109*e1dd0a2fSth }
2110*e1dd0a2fSth 
2111*e1dd0a2fSth /*
2112*e1dd0a2fSth  * INPUT:
2113*e1dd0a2fSth  *     serverAddr is the address of a server and
2114*e1dd0a2fSth  *     request is one of the following:
2115*e1dd0a2fSth  *     NS_CACHE_NEW:    get a new server address, addr is ignored.
2116*e1dd0a2fSth  *     NS_CACHE_NORESP: get the next one, remove addr from list.
2117*e1dd0a2fSth  *     NS_CACHE_NEXT:   get the next one, keep addr on list.
2118*e1dd0a2fSth  *     NS_CACHE_WRITE:  get a non-replica server, if possible, if not, same
2119*e1dd0a2fSth  *                      as NS_CACHE_NEXT.
2120*e1dd0a2fSth  *     addrType:
2121*e1dd0a2fSth  *     NS_CACHE_ADDR_IP: return server address as is, this is default.
2122*e1dd0a2fSth  *     NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only
2123*e1dd0a2fSth  *                             self credential case requires such format.
2124*e1dd0a2fSth  * OUTPUT:
2125*e1dd0a2fSth  *     ret
2126*e1dd0a2fSth  *
2127*e1dd0a2fSth  *     a structure of type ns_server_info_t containing the server address
2128*e1dd0a2fSth  *     or name, server controls and supported SASL mechanisms.
2129*e1dd0a2fSth  *     NOTE: Caller should allocate space for the structure and free
2130*e1dd0a2fSth  *     all the space allocated by the function for the information contained
2131*e1dd0a2fSth  *     in the structure.
2132*e1dd0a2fSth  *
2133*e1dd0a2fSth  *     error - an error object describing an error, if any.
2134*e1dd0a2fSth  */
2135*e1dd0a2fSth ns_ldap_return_code
2136*e1dd0a2fSth __s_api_findRootDSE(const char *request,
2137*e1dd0a2fSth 		const char *serverAddr,
2138*e1dd0a2fSth 		const char *addrType,
2139*e1dd0a2fSth 		ns_server_info_t *ret,
2140*e1dd0a2fSth 		ns_ldap_error_t	**error)
2141*e1dd0a2fSth {
2142*e1dd0a2fSth 	dir_server_list_t	*current_list = NULL;
2143*e1dd0a2fSth 	ns_ldap_return_code	ret_code;
2144*e1dd0a2fSth 	long			i = 0;
2145*e1dd0a2fSth 	int			matched = FALSE;
2146*e1dd0a2fSth 	dir_server_t		*server = NULL;
2147*e1dd0a2fSth 	char			errmsg[MAXERROR];
2148*e1dd0a2fSth 
2149*e1dd0a2fSth 	(void) mutex_lock(&dir_servers.listReplaceLock);
2150*e1dd0a2fSth 	if (dir_servers.list == NULL) {
2151*e1dd0a2fSth 		(void) mutex_unlock(&dir_servers.listReplaceLock);
2152*e1dd0a2fSth 		(void) snprintf(errmsg,
2153*e1dd0a2fSth 		    sizeof (errmsg),
2154*e1dd0a2fSth 		    gettext("The list of root DSEs is empty: "
2155*e1dd0a2fSth 		    "the Standalone mode was not properly initialized"));
2156*e1dd0a2fSth 		MKERROR(LOG_ERR,
2157*e1dd0a2fSth 		    *error,
2158*e1dd0a2fSth 		    NS_CONFIG_NOTLOADED,
2159*e1dd0a2fSth 		    strdup(errmsg),
2160*e1dd0a2fSth 		    NS_LDAP_MEMORY);
2161*e1dd0a2fSth 		return (NS_LDAP_INTERNAL);
2162*e1dd0a2fSth 	}
2163*e1dd0a2fSth 
2164*e1dd0a2fSth 	current_list = dir_servers.list;
2165*e1dd0a2fSth 	(void) rw_rdlock(&current_list->listDestroyLock);
2166*e1dd0a2fSth 	(void) mutex_unlock(&dir_servers.listReplaceLock);
2167*e1dd0a2fSth 
2168*e1dd0a2fSth 	/*
2169*e1dd0a2fSth 	 * The code below is mostly the clone of the
2170*e1dd0a2fSth 	 * ldap_cachemgr::cachemgr_getldap.c::getldap_get_serverInfo() function.
2171*e1dd0a2fSth 	 * Currently we have two different server lists: one is maintained
2172*e1dd0a2fSth 	 * by libsldap ('standalone' mode), the other is in ldap_cachemgr
2173*e1dd0a2fSth 	 * (a part of its standard functionality).
2174*e1dd0a2fSth 	 */
2175*e1dd0a2fSth 
2176*e1dd0a2fSth 	/*
2177*e1dd0a2fSth 	 * If NS_CACHE_NEW, or the server info is new,
2178*e1dd0a2fSth 	 * starts from the beginning of the list.
2179*e1dd0a2fSth 	 */
2180*e1dd0a2fSth 	(void) mutex_lock(&current_list->nsServers[0]->updateStatus);
2181*e1dd0a2fSth 	if (strcmp(request, NS_CACHE_NEW) == 0 ||
2182*e1dd0a2fSth 	    current_list->nsServers[0]->info == INFO_STATUS_NEW) {
2183*e1dd0a2fSth 		matched = TRUE;
2184*e1dd0a2fSth 	}
2185*e1dd0a2fSth 	(void) mutex_unlock(&current_list->nsServers[i]->updateStatus);
2186*e1dd0a2fSth 
2187*e1dd0a2fSth 	for (i = 0; current_list->nsServers[i]; ++i) {
2188*e1dd0a2fSth 		/*
2189*e1dd0a2fSth 		 * Lock the updateStatus mutex to
2190*e1dd0a2fSth 		 * make sure the server status stays the same
2191*e1dd0a2fSth 		 * while the data is being processed.
2192*e1dd0a2fSth 		 */
2193*e1dd0a2fSth 		if (matched == FALSE &&
2194*e1dd0a2fSth 		    strcmp(current_list->nsServers[i]->ip,
2195*e1dd0a2fSth 		    serverAddr) == 0) {
2196*e1dd0a2fSth 			matched = TRUE;
2197*e1dd0a2fSth 			if (strcmp(request, NS_CACHE_NORESP) == 0) {
2198*e1dd0a2fSth 
2199*e1dd0a2fSth 				/*
2200*e1dd0a2fSth 				 * if the server has already been removed,
2201*e1dd0a2fSth 				 * don't bother.
2202*e1dd0a2fSth 				 */
2203*e1dd0a2fSth 				(void) mutex_lock(&current_list->
2204*e1dd0a2fSth 				    nsServers[i]->updateStatus);
2205*e1dd0a2fSth 				if (current_list->nsServers[i]->status ==
2206*e1dd0a2fSth 				    INFO_SERVER_REMOVED) {
2207*e1dd0a2fSth 					(void) mutex_unlock(&current_list->
2208*e1dd0a2fSth 					    nsServers[i]->
2209*e1dd0a2fSth 					    updateStatus);
2210*e1dd0a2fSth 					continue;
2211*e1dd0a2fSth 				}
2212*e1dd0a2fSth 				(void) mutex_unlock(&current_list->
2213*e1dd0a2fSth 				    nsServers[i]->
2214*e1dd0a2fSth 				    updateStatus);
2215*e1dd0a2fSth 
2216*e1dd0a2fSth 				/*
2217*e1dd0a2fSth 				 * if the information is new,
2218*e1dd0a2fSth 				 * give this server one more chance.
2219*e1dd0a2fSth 				 */
2220*e1dd0a2fSth 				(void) mutex_lock(&current_list->
2221*e1dd0a2fSth 				    nsServers[i]->
2222*e1dd0a2fSth 				    updateStatus);
2223*e1dd0a2fSth 				if (current_list->nsServers[i]->info ==
2224*e1dd0a2fSth 				    INFO_STATUS_NEW &&
2225*e1dd0a2fSth 				    current_list->nsServers[i]->status  ==
2226*e1dd0a2fSth 				    INFO_SERVER_UP) {
2227*e1dd0a2fSth 					server = current_list->nsServers[i];
2228*e1dd0a2fSth 					(void) mutex_unlock(&current_list->
2229*e1dd0a2fSth 					    nsServers[i]->
2230*e1dd0a2fSth 					    updateStatus);
2231*e1dd0a2fSth 					break;
2232*e1dd0a2fSth 				} else {
2233*e1dd0a2fSth 					/*
2234*e1dd0a2fSth 					 * it is recommended that
2235*e1dd0a2fSth 					 * before removing the
2236*e1dd0a2fSth 					 * server from the list,
2237*e1dd0a2fSth 					 * the server should be
2238*e1dd0a2fSth 					 * contacted one more time
2239*e1dd0a2fSth 					 * to make sure that it is
2240*e1dd0a2fSth 					 * really unavailable.
2241*e1dd0a2fSth 					 * For now, just trust the client
2242*e1dd0a2fSth 					 * (i.e., the sldap library)
2243*e1dd0a2fSth 					 * that it knows what it is
2244*e1dd0a2fSth 					 * doing and would not try
2245*e1dd0a2fSth 					 * to mess up the server
2246*e1dd0a2fSth 					 * list.
2247*e1dd0a2fSth 					 */
2248*e1dd0a2fSth 					current_list->nsServers[i]->status =
2249*e1dd0a2fSth 					    INFO_SERVER_REMOVED;
2250*e1dd0a2fSth 					(void) mutex_unlock(&current_list->
2251*e1dd0a2fSth 					    nsServers[i]->
2252*e1dd0a2fSth 					    updateStatus);
2253*e1dd0a2fSth 					continue;
2254*e1dd0a2fSth 				}
2255*e1dd0a2fSth 			} else {
2256*e1dd0a2fSth 				/*
2257*e1dd0a2fSth 				 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
2258*e1dd0a2fSth 				 */
2259*e1dd0a2fSth 				continue;
2260*e1dd0a2fSth 			}
2261*e1dd0a2fSth 		}
2262*e1dd0a2fSth 
2263*e1dd0a2fSth 		if (matched) {
2264*e1dd0a2fSth 			if (strcmp(request, NS_CACHE_WRITE) == 0) {
2265*e1dd0a2fSth 				/*
2266*e1dd0a2fSth 				 * ldap_cachemgr checks here if the server
2267*e1dd0a2fSth 				 * is not a non-replica server (a server
2268*e1dd0a2fSth 				 * of type INFO_RW_WRITEABLE). But currently
2269*e1dd0a2fSth 				 * it considers all the servers in its list
2270*e1dd0a2fSth 				 * as those.
2271*e1dd0a2fSth 				 */
2272*e1dd0a2fSth 				(void) mutex_lock(&current_list->
2273*e1dd0a2fSth 				    nsServers[i]->
2274*e1dd0a2fSth 				    updateStatus);
2275*e1dd0a2fSth 				if (current_list->nsServers[i]->status  ==
2276*e1dd0a2fSth 				    INFO_SERVER_UP) {
2277*e1dd0a2fSth 					(void) mutex_unlock(&current_list->
2278*e1dd0a2fSth 					    nsServers[i]->
2279*e1dd0a2fSth 					    updateStatus);
2280*e1dd0a2fSth 					server = current_list->nsServers[i];
2281*e1dd0a2fSth 					break;
2282*e1dd0a2fSth 				}
2283*e1dd0a2fSth 			} else {
2284*e1dd0a2fSth 				(void) mutex_lock(&current_list->
2285*e1dd0a2fSth 				    nsServers[i]->
2286*e1dd0a2fSth 				    updateStatus);
2287*e1dd0a2fSth 				if (current_list->nsServers[i]->status ==
2288*e1dd0a2fSth 				    INFO_SERVER_UP) {
2289*e1dd0a2fSth 					(void) mutex_unlock(&current_list->
2290*e1dd0a2fSth 					    nsServers[i]->
2291*e1dd0a2fSth 					    updateStatus);
2292*e1dd0a2fSth 					server = current_list->nsServers[i];
2293*e1dd0a2fSth 					break;
2294*e1dd0a2fSth 				}
2295*e1dd0a2fSth 			}
2296*e1dd0a2fSth 
2297*e1dd0a2fSth 			(void) mutex_unlock(&current_list->
2298*e1dd0a2fSth 			    nsServers[i]->
2299*e1dd0a2fSth 			    updateStatus);
2300*e1dd0a2fSth 		}
2301*e1dd0a2fSth 	}
2302*e1dd0a2fSth 
2303*e1dd0a2fSth 	if (server == NULL) {
2304*e1dd0a2fSth 		(void) rw_unlock(&current_list->listDestroyLock);
2305*e1dd0a2fSth 		(void) snprintf(errmsg,
2306*e1dd0a2fSth 		    sizeof (errmsg),
2307*e1dd0a2fSth 		    gettext("No servers are available"));
2308*e1dd0a2fSth 		MKERROR(LOG_ERR,
2309*e1dd0a2fSth 		    *error,
2310*e1dd0a2fSth 		    NS_CONFIG_NOTLOADED,
2311*e1dd0a2fSth 		    strdup(errmsg),
2312*e1dd0a2fSth 		    NS_LDAP_MEMORY);
2313*e1dd0a2fSth 		return (NS_LDAP_NOTFOUND);
2314*e1dd0a2fSth 	}
2315*e1dd0a2fSth 
2316*e1dd0a2fSth 	(void) mutex_lock(&server->updateStatus);
2317*e1dd0a2fSth 	server->info = INFO_STATUS_OLD;
2318*e1dd0a2fSth 	(void) mutex_unlock(&server->updateStatus);
2319*e1dd0a2fSth 
2320*e1dd0a2fSth 	if (ret == NULL) {
2321*e1dd0a2fSth 		(void) rw_unlock(&current_list->listDestroyLock);
2322*e1dd0a2fSth 		return (NS_LDAP_SUCCESS);
2323*e1dd0a2fSth 	}
2324*e1dd0a2fSth 
2325*e1dd0a2fSth 	if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
2326*e1dd0a2fSth 		ret_code = __s_api_ip2hostname(server->ip, &ret->serverFQDN);
2327*e1dd0a2fSth 		if (ret_code != NS_LDAP_SUCCESS) {
2328*e1dd0a2fSth 			(void) snprintf(errmsg,
2329*e1dd0a2fSth 			    sizeof (errmsg),
2330*e1dd0a2fSth 			    gettext("The %s address "
2331*e1dd0a2fSth 			    "can not be resolved into "
2332*e1dd0a2fSth 			    "a host name. Returning "
2333*e1dd0a2fSth 			    "the address as it is."),
2334*e1dd0a2fSth 			    server->ip);
2335*e1dd0a2fSth 			MKERROR(LOG_ERR,
2336*e1dd0a2fSth 			    *error,
2337*e1dd0a2fSth 			    NS_CONFIG_NOTLOADED,
2338*e1dd0a2fSth 			    strdup(errmsg),
2339*e1dd0a2fSth 			    NS_LDAP_MEMORY);
2340*e1dd0a2fSth 			return (NS_LDAP_INTERNAL);
2341*e1dd0a2fSth 		}
2342*e1dd0a2fSth 	}
2343*e1dd0a2fSth 
2344*e1dd0a2fSth 	ret->server = strdup(server->ip);
2345*e1dd0a2fSth 
2346*e1dd0a2fSth 	ret->controls = __s_api_cp2dArray(server->controls);
2347*e1dd0a2fSth 	ret->saslMechanisms = __s_api_cp2dArray(server->saslMech);
2348*e1dd0a2fSth 
2349*e1dd0a2fSth 	(void) rw_unlock(&current_list->listDestroyLock);
2350*e1dd0a2fSth 
2351*e1dd0a2fSth 	return (NS_LDAP_SUCCESS);
2352*e1dd0a2fSth }
2353*e1dd0a2fSth 
2354*e1dd0a2fSth /*
2355*e1dd0a2fSth  * This function iterates through the list of the configured LDAP servers
2356*e1dd0a2fSth  * and "pings" those which are marked as removed or if any error occurred
2357*e1dd0a2fSth  * during the previous receiving of the server's root DSE. If the
2358*e1dd0a2fSth  * function is able to reach such a server and get its root DSE, it
2359*e1dd0a2fSth  * marks the server as on-line. Otherwise, the server's status is set
2360*e1dd0a2fSth  * to "Error".
2361*e1dd0a2fSth  * For each server the function tries to connect to, it fires up
2362*e1dd0a2fSth  * a separate thread and then waits until all the treads finish.
2363*e1dd0a2fSth  * The function returns NS_LDAP_INTERNAL if the Standalone mode was not
2364*e1dd0a2fSth  * initialized or was canceled prior to an invocation of
2365*e1dd0a2fSth  * __ns_ldap_pingOfflineServers().
2366*e1dd0a2fSth  */
2367*e1dd0a2fSth ns_ldap_return_code
2368*e1dd0a2fSth __ns_ldap_pingOfflineServers(void)
2369*e1dd0a2fSth {
2370*e1dd0a2fSth 	dir_server_list_t	*current_list = NULL;
2371*e1dd0a2fSth 	ns_ldap_return_code	retCode = NS_LDAP_SUCCESS;
2372*e1dd0a2fSth 	long			srvListLength, i = 0;
2373*e1dd0a2fSth 	thread_t		*thrPool, thrID;
2374*e1dd0a2fSth 	void			*status = NULL;
2375*e1dd0a2fSth 
2376*e1dd0a2fSth 	(void) mutex_lock(&dir_servers.listReplaceLock);
2377*e1dd0a2fSth 	if (dir_servers.list == NULL) {
2378*e1dd0a2fSth 		(void) mutex_unlock(&dir_servers.listReplaceLock);
2379*e1dd0a2fSth 		return (NS_LDAP_INTERNAL);
2380*e1dd0a2fSth 	}
2381*e1dd0a2fSth 
2382*e1dd0a2fSth 	current_list = dir_servers.list;
2383*e1dd0a2fSth 	(void) rw_wrlock(&current_list->listDestroyLock);
2384*e1dd0a2fSth 	(void) mutex_unlock(&dir_servers.listReplaceLock);
2385*e1dd0a2fSth 
2386*e1dd0a2fSth 	while (current_list->nsServers[i] != NULL) {
2387*e1dd0a2fSth 		++i;
2388*e1dd0a2fSth 	}
2389*e1dd0a2fSth 	srvListLength = i;
2390*e1dd0a2fSth 
2391*e1dd0a2fSth 	thrPool = calloc(srvListLength, sizeof (thread_t));
2392*e1dd0a2fSth 	if (thrPool == NULL) {
2393*e1dd0a2fSth 		(void) rw_unlock(&current_list->listDestroyLock);
2394*e1dd0a2fSth 		return (NS_LDAP_MEMORY);
2395*e1dd0a2fSth 	}
2396*e1dd0a2fSth 
2397*e1dd0a2fSth 	for (i = 0; i < srvListLength; ++i) {
2398*e1dd0a2fSth 		if (current_list->nsServers[i]->status != INFO_SERVER_REMOVED &&
2399*e1dd0a2fSth 		    current_list->nsServers[i]->status != INFO_SERVER_ERROR) {
2400*e1dd0a2fSth 			continue;
2401*e1dd0a2fSth 		}
2402*e1dd0a2fSth 		current_list->nsServers[i]->status = INFO_SERVER_CONNECTING;
2403*e1dd0a2fSth 		current_list->nsServers[i]->info = INFO_STATUS_NEW;
2404*e1dd0a2fSth 
2405*e1dd0a2fSth 		__s_api_free2dArray(current_list->nsServers[i]->controls);
2406*e1dd0a2fSth 		current_list->nsServers[i]->controls = NULL;
2407*e1dd0a2fSth 		__s_api_free2dArray(current_list->nsServers[i]->saslMech);
2408*e1dd0a2fSth 		current_list->nsServers[i]->saslMech = NULL;
2409*e1dd0a2fSth 
2410*e1dd0a2fSth 		switch (thr_create(NULL,
2411*e1dd0a2fSth 		    0,
2412*e1dd0a2fSth 		    create_ns_servers_entry,
2413*e1dd0a2fSth 		    current_list->nsServers[i],
2414*e1dd0a2fSth 		    0,
2415*e1dd0a2fSth 		    &thrID)) {
2416*e1dd0a2fSth 		case EAGAIN:
2417*e1dd0a2fSth 			current_list->nsServers[i]->status = INFO_SERVER_ERROR;
2418*e1dd0a2fSth 			continue;
2419*e1dd0a2fSth 			break;
2420*e1dd0a2fSth 		case ENOMEM:
2421*e1dd0a2fSth 			current_list->nsServers[i]->status = INFO_SERVER_ERROR;
2422*e1dd0a2fSth 			retCode = NS_LDAP_MEMORY;
2423*e1dd0a2fSth 			break;
2424*e1dd0a2fSth 		default:
2425*e1dd0a2fSth 			thrPool[i] = thrID;
2426*e1dd0a2fSth 			continue;
2427*e1dd0a2fSth 			break;
2428*e1dd0a2fSth 		}
2429*e1dd0a2fSth 		/* A memory allocation error has occured */
2430*e1dd0a2fSth 		break;
2431*e1dd0a2fSth 
2432*e1dd0a2fSth 	}
2433*e1dd0a2fSth 
2434*e1dd0a2fSth 	for (i = 0; i < srvListLength; ++i) {
2435*e1dd0a2fSth 		if (thrPool[i] != 0 &&
2436*e1dd0a2fSth 		    thr_join(thrPool[i], NULL, &status) == 0) {
2437*e1dd0a2fSth 			if (status == NULL) {
2438*e1dd0a2fSth 				current_list->nsServers[i]->status =
2439*e1dd0a2fSth 				    INFO_SERVER_ERROR;
2440*e1dd0a2fSth 				retCode = NS_LDAP_MEMORY;
2441*e1dd0a2fSth 			}
2442*e1dd0a2fSth 			free(status);
2443*e1dd0a2fSth 		}
2444*e1dd0a2fSth 	}
2445*e1dd0a2fSth 
2446*e1dd0a2fSth 	(void) rw_unlock(&current_list->listDestroyLock);
2447*e1dd0a2fSth 
2448*e1dd0a2fSth 	free(thrPool);
2449*e1dd0a2fSth 
2450*e1dd0a2fSth 	return (retCode);
2451*e1dd0a2fSth }
2452