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