xref: /onnv-gate/usr/src/lib/libsldap/common/ns_standalone.c (revision 10132:79e70ba10c05)
16842Sth160488 /*
26842Sth160488  * CDDL HEADER START
36842Sth160488  *
46842Sth160488  * The contents of this file are subject to the terms of the
56842Sth160488  * Common Development and Distribution License (the "License").
66842Sth160488  * You may not use this file except in compliance with the License.
76842Sth160488  *
86842Sth160488  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96842Sth160488  * or http://www.opensolaris.org/os/licensing.
106842Sth160488  * See the License for the specific language governing permissions
116842Sth160488  * and limitations under the License.
126842Sth160488  *
136842Sth160488  * When distributing Covered Code, include this CDDL HEADER in each
146842Sth160488  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156842Sth160488  * If applicable, add the following below this CDDL HEADER, with the
166842Sth160488  * fields enclosed by brackets "[]" replaced with your own identifying
176842Sth160488  * information: Portions Copyright [yyyy] [name of copyright owner]
186842Sth160488  *
196842Sth160488  * CDDL HEADER END
206842Sth160488  */
216842Sth160488 /*
22*10132SMilan.Jurik@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
236842Sth160488  * Use is subject to license terms.
246842Sth160488  */
256842Sth160488 
266842Sth160488 #define	__STANDALONE_MODULE__
276842Sth160488 
286842Sth160488 #include <stdio.h>
296842Sth160488 #include <sys/types.h>
306842Sth160488 #include <stdlib.h>
316842Sth160488 #include <libintl.h>
326842Sth160488 #include <string.h>
336842Sth160488 #include <ctype.h>
346842Sth160488 
356842Sth160488 #include <sys/stat.h>
366842Sth160488 #include <fcntl.h>
376842Sth160488 #include <unistd.h>
386842Sth160488 #include <syslog.h>
396842Sth160488 #include <locale.h>
406842Sth160488 #include <errno.h>
416842Sth160488 #include <sys/time.h>
426842Sth160488 
436842Sth160488 #include <arpa/inet.h>
446842Sth160488 #include <netdb.h>
456842Sth160488 #include <strings.h>
466842Sth160488 
476842Sth160488 #include <thread.h>
486842Sth160488 
496842Sth160488 #include <nsswitch.h>
506842Sth160488 #include <nss_dbdefs.h>
516842Sth160488 #include <nss.h>
526842Sth160488 
536842Sth160488 #include "ns_cache_door.h"
546842Sth160488 #include "ns_internal.h"
556921Smichen #include "ns_connmgmt.h"
566842Sth160488 
576842Sth160488 typedef enum {
586842Sth160488 	INFO_SERVER_JUST_INITED	= -1,
596842Sth160488 	INFO_SERVER_UNKNOWN	= 0,
606842Sth160488 	INFO_SERVER_CONNECTING	= 1,
616842Sth160488 	INFO_SERVER_UP		= 2,
626842Sth160488 	INFO_SERVER_ERROR 	= 3,
636842Sth160488 	INFO_SERVER_REMOVED	= 4
646842Sth160488 } dir_server_status_t;
656842Sth160488 
666842Sth160488 typedef enum {
676842Sth160488 	INFO_STATUS_NEW   	= 2,
686842Sth160488 	INFO_STATUS_OLD		= 3
696842Sth160488 } dir_server_info_t;
706842Sth160488 
716842Sth160488 typedef struct dir_server {
726842Sth160488 	char			*ip;
736842Sth160488 	char			**controls;
746842Sth160488 	char			**saslMech;
756842Sth160488 	dir_server_status_t	status;
766842Sth160488 	mutex_t			updateStatus;
776842Sth160488 	dir_server_info_t	info;
786842Sth160488 } dir_server_t;
796842Sth160488 
806842Sth160488 typedef struct dir_server_list {
816842Sth160488 	dir_server_t	**nsServers;
826842Sth160488 
836842Sth160488 	rwlock_t	listDestroyLock;
846842Sth160488 } dir_server_list_t;
856842Sth160488 
866842Sth160488 struct {
876842Sth160488 	/* The local list of the directory servers' root DSEs. */
886842Sth160488 	dir_server_list_t	*list;
896842Sth160488 	/* The flag indicating if libsldap is in the 'Standalone' mode. */
906842Sth160488 	int			standalone;
916842Sth160488 	/*
926842Sth160488 	 * The mutex ensuring that only one thread performs
936842Sth160488 	 * the initialization of the list.
946842Sth160488 	 */
956842Sth160488 	mutex_t			listReplaceLock;
966842Sth160488 	/*
976842Sth160488 	 * A flag indicating that a particular thread is
986842Sth160488 	 * in the 'ldap_cachemgr' mode. It is stored by thread as
996842Sth160488 	 * a thread specific data.
1006842Sth160488 	 */
1016842Sth160488 	const int		initFlag;
1026842Sth160488 	/*
1036842Sth160488 	 * A thread specific key storing
1046842Sth160488 	 * the the 'ldap_cachemgr' mode indicator.
1056842Sth160488 	 */
1066842Sth160488 	thread_key_t		standaloneInitKey;
1076842Sth160488 } dir_servers = {NULL, 0, DEFAULTMUTEX, '1'};
1086842Sth160488 
1096842Sth160488 typedef struct switchDatabase {
1106842Sth160488 	char *conf;
1116842Sth160488 	uint32_t alloced;
1126842Sth160488 } switch_database_t;
1136842Sth160488 
1146842Sth160488 static thread_key_t switchConfigKey;
1156842Sth160488 
1166842Sth160488 #pragma init(createStandaloneKey)
1176842Sth160488 
1186842Sth160488 #define	DONT_INCLUDE_ATTR_NAMES	0
1196842Sth160488 #define	INCLUDE_ATTR_NAMES	1
1206842Sth160488 #define	IS_PROFILE		1
1216842Sth160488 #define	NOT_PROFILE		0
1226842Sth160488 /* INET6_ADDRSTRLEN + ":" + <5-digit port> + some round-up */
1236842Sth160488 #define	MAX_HOSTADDR_LEN (INET6_ADDRSTRLEN + 6 + 12)
1246842Sth160488 
1256842Sth160488 static
1266842Sth160488 void
switch_conf_disposer(void * data)1276842Sth160488 switch_conf_disposer(void *data)
1286842Sth160488 {
1296842Sth160488 	switch_database_t *localData = (switch_database_t *)data;
1306842Sth160488 
1316842Sth160488 	free(localData->conf);
1326842Sth160488 	free(localData);
1336842Sth160488 }
1346842Sth160488 
1356842Sth160488 /*
1366842Sth160488  * This function initializes an indication that a thread obtaining a root DSE
1376842Sth160488  * will be switched to the 'ldap_cachemgr' mode. Within the thread libsldap
1386842Sth160488  * will not invoke the __s_api_requestServer function. Instead, the library
1396842Sth160488  * will establish a connection to the server specified by
1406842Sth160488  * the __ns_ldap_getRootDSE function.
1416842Sth160488  * Since  ldap_cachmgr can obtain a DUAProfile and root DSEs at the same time
1426842Sth160488  * and we do not want to affect a thread obtaining a DUAProfile,
1436842Sth160488  * the 'ldap_cachemgr' mode is thread private.
1446842Sth160488  * In addition, this function creates a key holding temporary configuration
1456842Sth160488  * for the "hosts" and "ipnodes" databases which is used by the "SKIPDB"
1466842Sth160488  * mechanism (__s_api_ip2hostname() & _s_api_hostname2ip()).
1476842Sth160488  */
1486842Sth160488 static
1496842Sth160488 void
createStandaloneKey()1506842Sth160488 createStandaloneKey()
1516842Sth160488 {
1526842Sth160488 	if (thr_keycreate(&dir_servers.standaloneInitKey, NULL) != 0) {
1536842Sth160488 		syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
1546842Sth160488 		"key needed for sharing ldap connections"));
1556842Sth160488 	}
1566842Sth160488 	if (thr_keycreate(&switchConfigKey, switch_conf_disposer) != 0) {
1576842Sth160488 		syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
1586842Sth160488 		    "key containing current nsswitch configuration"));
1596842Sth160488 	}
1606842Sth160488 }
1616842Sth160488 
1626842Sth160488 /*
1636842Sth160488  * This function sets the 'ldap_cachemgr' mode indication.
1646842Sth160488  */
1656842Sth160488 void
__s_api_setInitMode()1666842Sth160488 __s_api_setInitMode()
1676842Sth160488 {
1686842Sth160488 	(void) thr_setspecific(dir_servers.standaloneInitKey,
1696842Sth160488 	    (void *) &dir_servers.initFlag);
1706842Sth160488 }
1716842Sth160488 
1726842Sth160488 /*
1736842Sth160488  * This function unset the 'ldap_cachemgr' mode indication.
1746842Sth160488  */
1756842Sth160488 void
__s_api_unsetInitMode()1766842Sth160488 __s_api_unsetInitMode()
1776842Sth160488 {
1786842Sth160488 	(void) thr_setspecific(dir_servers.standaloneInitKey, NULL);
1796842Sth160488 }
1806842Sth160488 
1816842Sth160488 /*
1826842Sth160488  * This function checks if the 'ldap_cachemgr' mode indication is set.
1836842Sth160488  */
1846842Sth160488 int
__s_api_isInitializing()1856842Sth160488 __s_api_isInitializing() {
1866842Sth160488 	int *flag = NULL;
1876842Sth160488 
1886842Sth160488 	(void) thr_getspecific(dir_servers.standaloneInitKey, (void **) &flag);
1896842Sth160488 
1906842Sth160488 	return (flag != NULL && *flag == dir_servers.initFlag);
1916842Sth160488 }
1926842Sth160488 
1936842Sth160488 /*
1946842Sth160488  * This function checks if the process runs in the 'Standalone' mode.
1956842Sth160488  * In this mode libsldap will check the local, process private list of root DSEs
1966842Sth160488  * instead of requesting them via a door call to ldap_cachemgr.
1976842Sth160488  */
1986842Sth160488 int
__s_api_isStandalone()1996842Sth160488 __s_api_isStandalone()
2006842Sth160488 {
2016842Sth160488 	int	mode;
2026842Sth160488 
2036842Sth160488 	(void) mutex_lock(&dir_servers.listReplaceLock);
2046842Sth160488 	mode = dir_servers.standalone;
2056842Sth160488 	(void) mutex_unlock(&dir_servers.listReplaceLock);
2066842Sth160488 
2076842Sth160488 	return (mode);
2086842Sth160488 }
2096842Sth160488 
2106842Sth160488 
2116842Sth160488 static
2126842Sth160488 int
remove_ldap(char * dst,char * src,int dst_buf_len)2136842Sth160488 remove_ldap(char *dst, char *src, int dst_buf_len)
2146842Sth160488 {
2156842Sth160488 	int i = 0;
2166842Sth160488 
2176842Sth160488 	if (strlen(src) >= dst_buf_len)
2186842Sth160488 		return (0);
2196842Sth160488 
2206842Sth160488 	while (*src != '\0') {
2216842Sth160488 		/* Copy up to one space from source. */
2226842Sth160488 		if (isspace(*src)) {
2236842Sth160488 			dst[i++] = *src;
2246842Sth160488 			while (isspace(*src))
2256842Sth160488 				src++;
2266842Sth160488 		}
2276842Sth160488 
2286842Sth160488 		/* If not "ldap", just copy. */
2296842Sth160488 		if (strncmp(src, "ldap", 4) != 0) {
2306842Sth160488 			while (!isspace(*src)) {
2316842Sth160488 				dst[i++] = *src++;
2326842Sth160488 				/* At the end of string? */
2336842Sth160488 				if (dst[i-1] == '\0')
2346842Sth160488 					return (1);
2356842Sth160488 			}
2366842Sth160488 			/* Copy up to one space from source. */
2376842Sth160488 			if (isspace(*src)) {
2386842Sth160488 				dst[i++] = *src;
2396842Sth160488 				while (isspace(*src))
2406842Sth160488 					src++;
2416842Sth160488 			}
2426842Sth160488 			/* Copy also the criteria section */
2436842Sth160488 			if (*src == '[')
2446842Sth160488 				while (*src != ']') {
2456842Sth160488 					dst[i++] = *src++;
2466842Sth160488 					/* Shouln't happen if format is right */
2476842Sth160488 					if (dst[i-1] == '\0')
2486842Sth160488 						return (1);
2496842Sth160488 				}
2506842Sth160488 		}
2516842Sth160488 
2526842Sth160488 		/* If next part is ldap, skip over it ... */
2536842Sth160488 		if (strncmp(src, "ldap", 4) == 0) {
2546842Sth160488 			if (isspace(*(src+4)) || *(src+4) == '\0') {
2556842Sth160488 				src += 4;
2566842Sth160488 				while (isspace(*src))
2576842Sth160488 					src++;
2586842Sth160488 				if (*src == '[') {
2596842Sth160488 					while (*src++ != ']') {
2606842Sth160488 						/*
2616842Sth160488 						 * See comment above about
2626842Sth160488 						 * correct format.
2636842Sth160488 						 */
2646842Sth160488 						if (*src == '\0') {
2656842Sth160488 							dst[i++] = '\0';
2666842Sth160488 							return (1);
2676842Sth160488 						}
2686842Sth160488 					}
2696842Sth160488 				}
2706842Sth160488 				while (isspace(*src))
2716842Sth160488 					src++;
2726842Sth160488 			}
2736842Sth160488 		}
2746842Sth160488 		if (*src == '\0')
2756842Sth160488 			dst[i++] = '\0';
2766842Sth160488 	}
2776842Sth160488 
2786842Sth160488 	return (1);
2796842Sth160488 }
2806842Sth160488 
2816842Sth160488 static
2826842Sth160488 char *
get_db(const char * db_name)2836842Sth160488 get_db(const char *db_name)
2846842Sth160488 {
2856842Sth160488 	char			*ptr;
2866842Sth160488 	switch_database_t	*hostService = NULL;
2876842Sth160488 	FILE			*fp = fopen(__NSW_CONFIG_FILE, "rF");
2886842Sth160488 	char			*linep, line[NSS_BUFSIZ];
2896842Sth160488 
2906842Sth160488 	if (fp == NULL) {
2916842Sth160488 		syslog(LOG_WARNING, gettext("libsldap: can not read %s"),
2926842Sth160488 		    __NSW_CONFIG_FILE);
2936842Sth160488 		return (NULL);
2946842Sth160488 	}
2956842Sth160488 
2966842Sth160488 	while ((linep = fgets(line, NSS_BUFSIZ, fp)) != NULL) {
2976842Sth160488 		while (isspace(*linep)) {
2986842Sth160488 			++linep;
2996842Sth160488 		}
3006842Sth160488 		if (*linep == '#') {
3016842Sth160488 			continue;
3026842Sth160488 		}
3036842Sth160488 		if (strncmp(linep, db_name, strlen(db_name)) != 0) {
3046842Sth160488 			continue;
3056842Sth160488 		}
3066842Sth160488 		if ((linep = strchr(linep, ':')) != NULL) {
3076842Sth160488 			if (linep[strlen(linep) - 1] == '\n') {
3086842Sth160488 				linep[strlen(linep) - 1] = '\0';
3096842Sth160488 			}
3106842Sth160488 
3116842Sth160488 			while (isspace(*++linep))
3126842Sth160488 				;
3136842Sth160488 
3146842Sth160488 			if ((ptr = strchr(linep, '#')) != NULL) {
3156842Sth160488 				while (--ptr >= linep && isspace(*ptr))
3166842Sth160488 					;
3176842Sth160488 				*(ptr + 1) = '\0';
3186842Sth160488 			}
3196842Sth160488 
3206842Sth160488 			if (strlen(linep) == 0) {
3216842Sth160488 				continue;
3226842Sth160488 			}
3236842Sth160488 			break;
3246842Sth160488 		}
3256842Sth160488 	}
3266842Sth160488 
3276842Sth160488 	(void) fclose(fp);
3286842Sth160488 
3296842Sth160488 	if (linep == NULL) {
3306842Sth160488 		syslog(LOG_WARNING,
3316842Sth160488 		    gettext("libsldap: the %s database "
3326842Sth160488 		    "is missing from %s"),
3336842Sth160488 		    db_name,
3346842Sth160488 		    __NSW_CONFIG_FILE);
3356842Sth160488 		return (NULL);
3366842Sth160488 	}
3376842Sth160488 
3386842Sth160488 	(void) thr_getspecific(switchConfigKey, (void **) &hostService);
3396842Sth160488 	if (hostService == NULL) {
3406842Sth160488 		hostService = calloc(1, sizeof (switch_database_t));
3416842Sth160488 		if (hostService == NULL) {
3426842Sth160488 			return (NULL);
3436842Sth160488 		}
3446842Sth160488 		(void) thr_setspecific(switchConfigKey, hostService);
3456842Sth160488 	}
3466842Sth160488 
3476842Sth160488 	/*
3486842Sth160488 	 * In a long-living process threads can perform several
3496842Sth160488 	 * getXbyY requests. And the windows between those requests
3506842Sth160488 	 * can be long. The nsswitch configuration can change from time
3516842Sth160488 	 * to time. So instead of allocating/freeing memory every time
3526842Sth160488 	 * the API is called, reallocate memory only when the current
3536842Sth160488 	 * configuration for the database being used is longer than
3546842Sth160488 	 * the previous one.
3556842Sth160488 	 */
3566842Sth160488 	if (strlen(linep) >= hostService->alloced) {
3576842Sth160488 		ptr = (char *)realloc((void *)hostService->conf,
3586842Sth160488 		    strlen(linep) + 1);
3596842Sth160488 		if (ptr == NULL) {
3606842Sth160488 			free((void *)hostService->conf);
3616842Sth160488 			hostService->conf = NULL;
3626842Sth160488 			hostService->alloced = 0;
3636842Sth160488 			return (NULL);
3646842Sth160488 		}
3656842Sth160488 		bzero(ptr, strlen(linep) + 1);
3666842Sth160488 		hostService->conf = ptr;
3676842Sth160488 		hostService->alloced = strlen(linep) + 1;
3686842Sth160488 	}
3696842Sth160488 
3706842Sth160488 	if (remove_ldap(hostService->conf, linep, hostService->alloced))
3716842Sth160488 		return (hostService->conf);
3726842Sth160488 	else
3736842Sth160488 		return (NULL);
3746842Sth160488 }
3756842Sth160488 
3766842Sth160488 static
3776842Sth160488 void
_initf_ipnodes(nss_db_params_t * p)3786842Sth160488 _initf_ipnodes(nss_db_params_t *p)
3796842Sth160488 {
3806842Sth160488 	char *services = get_db("ipnodes");
3816842Sth160488 
3826842Sth160488 	p->name = NSS_DBNAM_IPNODES;
3836842Sth160488 	p->flags |= NSS_USE_DEFAULT_CONFIG;
3846842Sth160488 	p->default_config = services == NULL ? "" : services;
3856842Sth160488 }
3866842Sth160488 
3876842Sth160488 static
3886842Sth160488 void
_initf_hosts(nss_db_params_t * p)3896842Sth160488 _initf_hosts(nss_db_params_t *p)
3906842Sth160488 {
3916842Sth160488 	char *services = get_db("hosts");
3926842Sth160488 
3936842Sth160488 	p->name = NSS_DBNAM_HOSTS;
3946842Sth160488 	p->flags |= NSS_USE_DEFAULT_CONFIG;
3956842Sth160488 	p->default_config = services == NULL ? "" : services;
3966842Sth160488 }
3976842Sth160488 
3986842Sth160488 /*
3996842Sth160488  * This function is an analog of the standard gethostbyaddr_r()
4006842Sth160488  * function with an exception that it removes the 'ldap' back-end
4016842Sth160488  * (if any) from the host/ipnodes nsswitch's databases and then
4026842Sth160488  * looks up using remaining back-ends.
4036842Sth160488  */
4046842Sth160488 static
4056842Sth160488 struct hostent *
_filter_gethostbyaddr_r(const char * addr,int len,int type,struct hostent * result,char * buffer,int buflen,int * h_errnop)4066842Sth160488 _filter_gethostbyaddr_r(const char *addr, int len, int type,
4076842Sth160488 	struct hostent *result, char *buffer, int buflen,
4086842Sth160488 	int *h_errnop)
4096842Sth160488 {
4106842Sth160488 	DEFINE_NSS_DB_ROOT(db_root_hosts);
4116842Sth160488 	DEFINE_NSS_DB_ROOT(db_root_ipnodes);
4126842Sth160488 	nss_XbyY_args_t arg;
4136842Sth160488 	nss_status_t    res;
4146842Sth160488 	int		(*str2ent)();
4156842Sth160488 	void		(*nss_initf)();
4166842Sth160488 	nss_db_root_t	*nss_db_root;
4176842Sth160488 	int		dbop;
4186842Sth160488 
4196842Sth160488 	switch (type) {
4206842Sth160488 	case AF_INET:
4216842Sth160488 		str2ent		= str2hostent;
4226842Sth160488 		nss_initf	= _initf_hosts;
4236842Sth160488 		nss_db_root	= &db_root_hosts;
4246842Sth160488 		dbop		= NSS_DBOP_HOSTS_BYADDR;
4256842Sth160488 		break;
4266842Sth160488 	case AF_INET6:
4276842Sth160488 		str2ent		= str2hostent6;
4286842Sth160488 		nss_initf	= _initf_ipnodes;
4296842Sth160488 		nss_db_root	= &db_root_ipnodes;
4306842Sth160488 		dbop		= NSS_DBOP_IPNODES_BYADDR;
4316842Sth160488 	default:
4326842Sth160488 		return (NULL);
4336842Sth160488 	}
4346842Sth160488 
4356842Sth160488 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent);
4366842Sth160488 
4376842Sth160488 	arg.key.hostaddr.addr	= addr;
4386842Sth160488 	arg.key.hostaddr.len	= len;
4396842Sth160488 	arg.key.hostaddr.type	= type;
4406842Sth160488 	arg.stayopen		= 0;
4416842Sth160488 	arg.h_errno		= NETDB_SUCCESS;
4426842Sth160488 
4436842Sth160488 	res = nss_search(nss_db_root, nss_initf, dbop, &arg);
4446842Sth160488 	arg.status = res;
4456842Sth160488 	*h_errnop = arg.h_errno;
4466842Sth160488 	return (struct hostent *)NSS_XbyY_FINI(&arg);
4476842Sth160488 }
4486842Sth160488 
4496842Sth160488 /*
4506842Sth160488  * This routine is an analog of gethostbyaddr_r().
4516842Sth160488  * But in addition __s_api_hostname2ip() performs the "LDAP SKIPDB" activity
4526842Sth160488  * prior to querying the name services.
4536842Sth160488  * If the buffer is not big enough to accommodate a returning data,
4546842Sth160488  * NULL is returned and h_errnop is set to TRY_AGAIN.
4556842Sth160488  */
4566842Sth160488 struct hostent *
__s_api_hostname2ip(const char * name,struct hostent * result,char * buffer,int buflen,int * h_errnop)4576842Sth160488 __s_api_hostname2ip(const char *name,
4586842Sth160488 	struct hostent *result, char *buffer, int buflen,
4596842Sth160488 	int *h_errnop)
4606842Sth160488 {
4616842Sth160488 	DEFINE_NSS_DB_ROOT(db_root_ipnodes);
4626842Sth160488 	DEFINE_NSS_DB_ROOT(db_root_hosts);
4636842Sth160488 	nss_XbyY_args_t	arg;
4646842Sth160488 	nss_status_t	res;
4656842Sth160488 	struct in_addr	addr;
4666842Sth160488 	struct in6_addr	addr6;
4676842Sth160488 
4686842Sth160488 	if (inet_pton(AF_INET, name, &addr) > 0) {
4696842Sth160488 		if (buflen < strlen(name) + 1 +
4706842Sth160488 		    sizeof (char *) * 2 + /* The h_aliases member */
4716842Sth160488 		    sizeof (struct in_addr) +
4726842Sth160488 		    sizeof (struct in_addr *) * 2) {
4736842Sth160488 			*h_errnop = TRY_AGAIN;
4746842Sth160488 			return (NULL);
4756842Sth160488 		}
4766842Sth160488 
4776842Sth160488 		result->h_addrtype = AF_INET;
4786842Sth160488 		result->h_length = sizeof (struct in_addr);
4796842Sth160488 		(void) strncpy(buffer, name, buflen);
4806842Sth160488 
4816842Sth160488 		result->h_addr_list = (char **)ROUND_UP(
4826842Sth160488 		    buffer + strlen(name) + 1,
4836842Sth160488 		    sizeof (char *));
4846842Sth160488 		result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
4856842Sth160488 		    sizeof (char *));
4866842Sth160488 		result->h_aliases[0] = buffer;
4876842Sth160488 		result->h_aliases[1] = NULL;
4886842Sth160488 		bcopy(&addr,
4896842Sth160488 		    buffer + buflen - sizeof (struct in_addr),
4906842Sth160488 		    sizeof (struct in_addr));
4916842Sth160488 		result->h_addr_list[0] = buffer + buflen -
4926842Sth160488 		    sizeof (struct in_addr);
4936842Sth160488 		result->h_addr_list[1] = NULL;
4946842Sth160488 		result->h_aliases = result->h_addr_list;
4956842Sth160488 		result->h_name = buffer;
4966842Sth160488 
4976842Sth160488 		*h_errnop = NETDB_SUCCESS;
4986842Sth160488 		return (result);
4996842Sth160488 	}
5006842Sth160488 	if (inet_pton(AF_INET6, name, &addr6) > 0) {
5016842Sth160488 		if (buflen < strlen(name) + 1 +
5026842Sth160488 		    sizeof (char *) * 2 + /* The h_aliases member */
5036842Sth160488 		    sizeof (struct in6_addr) +
5046842Sth160488 		    sizeof (struct in6_addr *) * 2) {
5056842Sth160488 			*h_errnop = TRY_AGAIN;
5066842Sth160488 			return (NULL);
5076842Sth160488 		}
5086842Sth160488 
5096842Sth160488 		result->h_addrtype = AF_INET6;
5106842Sth160488 		result->h_length = sizeof (struct in6_addr);
5116842Sth160488 		(void) strncpy(buffer, name, buflen);
5126842Sth160488 
5136842Sth160488 		result->h_addr_list = (char **)ROUND_UP(
5146842Sth160488 		    buffer + strlen(name) + 1,
5156842Sth160488 		    sizeof (char *));
5166842Sth160488 		result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
5176842Sth160488 		    sizeof (char *));
5186842Sth160488 		result->h_aliases[0] = buffer;
5196842Sth160488 		result->h_aliases[1] = NULL;
5206842Sth160488 		bcopy(&addr6,
5216842Sth160488 		    buffer + buflen - sizeof (struct in6_addr),
5226842Sth160488 		    sizeof (struct in6_addr));
5236842Sth160488 		result->h_addr_list[0] = buffer + buflen -
5246842Sth160488 		    sizeof (struct in6_addr);
5256842Sth160488 		result->h_addr_list[1] = NULL;
5266842Sth160488 		result->h_aliases = result->h_addr_list;
5276842Sth160488 		result->h_name = buffer;
5286842Sth160488 
5296842Sth160488 		*h_errnop = NETDB_SUCCESS;
5306842Sth160488 		return (result);
5316842Sth160488 	}
5326842Sth160488 
5336842Sth160488 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
5346842Sth160488 
5356842Sth160488 	arg.key.name = name;
5366842Sth160488 	arg.stayopen = 0;
5376842Sth160488 	arg.h_errno = NETDB_SUCCESS;
5386842Sth160488 
5396842Sth160488 	res = nss_search(&db_root_ipnodes, _initf_ipnodes,
5406842Sth160488 	    NSS_DBOP_IPNODES_BYNAME, &arg);
5416842Sth160488 	if (res == NSS_NOTFOUND || res == NSS_UNAVAIL) {
5426842Sth160488 		arg.h_errno = NETDB_SUCCESS;
5436842Sth160488 		res = nss_search(&db_root_hosts, _initf_hosts,
5446842Sth160488 		    NSS_DBOP_HOSTS_BYNAME, &arg);
5456842Sth160488 	}
5466842Sth160488 	arg.status = res;
5476842Sth160488 	*h_errnop = arg.h_errno;
5486842Sth160488 	return ((struct hostent *)NSS_XbyY_FINI(&arg));
5496842Sth160488 }
5506842Sth160488 
5516842Sth160488 /*
5526842Sth160488  * Convert an IP to a host name.
5536842Sth160488  */
5546842Sth160488 ns_ldap_return_code
__s_api_ip2hostname(char * ipaddr,char ** hostname)5556842Sth160488 __s_api_ip2hostname(char *ipaddr, char **hostname) {
5566842Sth160488 	struct in_addr	in;
5576842Sth160488 	struct in6_addr	in6;
5586842Sth160488 	struct hostent	*hp = NULL, hostEnt;
5596842Sth160488 	char		buffer[NSS_BUFLEN_HOSTS];
5606842Sth160488 	int		buflen = NSS_BUFLEN_HOSTS;
5616842Sth160488 	char		*start = NULL,
5626842Sth160488 			*end = NULL,
5636842Sth160488 			delim = '\0';
5646842Sth160488 	char		*port = NULL,
5656842Sth160488 			*addr = NULL;
5666842Sth160488 	int		errorNum = 0,
5676842Sth160488 			len = 0;
5686842Sth160488 
5696842Sth160488 	if (ipaddr == NULL || hostname == NULL)
5706842Sth160488 		return (NS_LDAP_INVALID_PARAM);
5716842Sth160488 	*hostname = NULL;
5726842Sth160488 	if ((addr = strdup(ipaddr)) == NULL)
5736842Sth160488 		return (NS_LDAP_MEMORY);
5746842Sth160488 
5756842Sth160488 	if (addr[0] == '[') {
5766842Sth160488 		/*
5776842Sth160488 		 * Assume it's [ipv6]:port
5786842Sth160488 		 * Extract ipv6 IP
5796842Sth160488 		 */
5806842Sth160488 		start = &addr[1];
5816842Sth160488 		if ((end = strchr(addr, ']')) != NULL) {
5826842Sth160488 			*end = '\0';
5836842Sth160488 			delim = ']';
5846842Sth160488 			if (*(end + 1) == ':')
5856842Sth160488 				/* extract port */
5866842Sth160488 				port = end + 2;
5876842Sth160488 		} else {
5886842Sth160488 			free(addr);
5896842Sth160488 			return (NS_LDAP_INVALID_PARAM);
5906842Sth160488 		}
5916842Sth160488 	} else if ((end = strchr(addr, ':')) != NULL) {
5926842Sth160488 		/* assume it's ipv4:port */
5936842Sth160488 		*end = '\0';
5946842Sth160488 		delim = ':';
5956842Sth160488 		start = addr;
5966842Sth160488 		port = end + 1;
5976842Sth160488 	} else
5986842Sth160488 		/* No port */
5996842Sth160488 		start = addr;
6006842Sth160488 
6016842Sth160488 
6026842Sth160488 	if (inet_pton(AF_INET, start, &in) == 1) {
6036842Sth160488 		/* IPv4 */
6046842Sth160488 		hp = _filter_gethostbyaddr_r((char *)&in,
6056842Sth160488 		    sizeof (in.s_addr),
6066842Sth160488 		    AF_INET,
6076842Sth160488 		    &hostEnt,
6086842Sth160488 		    buffer,
6096842Sth160488 		    buflen,
6106842Sth160488 		    &errorNum);
6116842Sth160488 		if (hp && hp->h_name) {
6126842Sth160488 			/* hostname + '\0' */
6136842Sth160488 			len = strlen(hp->h_name) + 1;
6146842Sth160488 			if (port)
6156842Sth160488 				/* ':' + port */
6166842Sth160488 				len += strlen(port) + 1;
6176842Sth160488 			if ((*hostname = malloc(len)) == NULL) {
6186842Sth160488 				free(addr);
6196842Sth160488 				return (NS_LDAP_MEMORY);
6206842Sth160488 			}
6216842Sth160488 
6226842Sth160488 			if (port)
6236842Sth160488 				(void) snprintf(*hostname, len, "%s:%s",
6246842Sth160488 						hp->h_name, port);
6256842Sth160488 			else
6266842Sth160488 				(void) strlcpy(*hostname, hp->h_name, len);
6276842Sth160488 
6286842Sth160488 			free(addr);
6296842Sth160488 			return (NS_LDAP_SUCCESS);
6306842Sth160488 		} else {
6316842Sth160488 			free(addr);
6326842Sth160488 			return (NS_LDAP_NOTFOUND);
6336842Sth160488 		}
6346842Sth160488 	} else if (inet_pton(AF_INET6, start, &in6) == 1) {
6356842Sth160488 		/* IPv6 */
6366842Sth160488 		hp = _filter_gethostbyaddr_r((char *)&in6,
6376842Sth160488 		    sizeof (in6.s6_addr),
6386842Sth160488 		    AF_INET6,
6396842Sth160488 		    &hostEnt,
6406842Sth160488 		    buffer,
6416842Sth160488 		    buflen,
6426842Sth160488 		    &errorNum);
6436842Sth160488 		if (hp && hp->h_name) {
6446842Sth160488 			/* hostname + '\0' */
6456842Sth160488 			len = strlen(hp->h_name) + 1;
6466842Sth160488 			if (port)
6476842Sth160488 				/* ':' + port */
6486842Sth160488 				len += strlen(port) + 1;
6496842Sth160488 			if ((*hostname = malloc(len)) == NULL) {
6506842Sth160488 				free(addr);
6516842Sth160488 				return (NS_LDAP_MEMORY);
6526842Sth160488 			}
6536842Sth160488 
6546842Sth160488 			if (port)
6556842Sth160488 				(void) snprintf(*hostname, len, "%s:%s",
6566842Sth160488 						hp->h_name, port);
6576842Sth160488 			else
6586842Sth160488 				(void) strlcpy(*hostname, hp->h_name, len);
6596842Sth160488 
6606842Sth160488 			free(addr);
6616842Sth160488 			return (NS_LDAP_SUCCESS);
6626842Sth160488 		} else {
6636842Sth160488 			free(addr);
6646842Sth160488 			return (NS_LDAP_NOTFOUND);
6656842Sth160488 		}
6666842Sth160488 	} else {
6676842Sth160488 		/*
6686842Sth160488 		 * A hostname
6696842Sth160488 		 * Return it as is
6706842Sth160488 		 */
6716842Sth160488 		if (end)
6726842Sth160488 			*end = delim;
6736842Sth160488 		*hostname = addr;
6746842Sth160488 		return (NS_LDAP_SUCCESS);
6756842Sth160488 	}
6766842Sth160488 }
6776842Sth160488 
6786842Sth160488 /*
6796842Sth160488  * This function obtains data returned by an LDAP search request and puts it
6806842Sth160488  * in a string in the ldap_cachmgr(1) door call format.
6816842Sth160488  *
6826842Sth160488  * INPUT:
6836842Sth160488  *     ld - a pointer to an LDAP structure used for a search operation,
6846842Sth160488  *     result_msg - a pointer to an LDAPMessage returned by the search,
6856842Sth160488  *     include_names - if set to INCLUDE_ATTR_NAMES, the output buffer will
6866842Sth160488  *                     contain attribute names.
6876842Sth160488  *                     Otherwise, only values will be return.
6886842Sth160488  *
6896842Sth160488  * OUTPUT:
6906842Sth160488  *      a buffer containing server info in the following format:
6916842Sth160488  *         [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
6926842Sth160488  *      Should be free'ed by the caller.
6936842Sth160488  */
6946842Sth160488 static
6956842Sth160488 ns_ldap_return_code
convert_to_door_line(LDAP * ld,LDAPMessage * result_msg,int include_names,int is_profile,char ** door_line)6966842Sth160488 convert_to_door_line(LDAP* ld,
6976842Sth160488 		LDAPMessage *result_msg,
6986842Sth160488 		int include_names,
6996842Sth160488 		int is_profile,
7006842Sth160488 		char **door_line)
7016842Sth160488 {
7026842Sth160488 	uint32_t	total_length = 0, attr_len = 0, i;
7036842Sth160488 	LDAPMessage	*e;
7046842Sth160488 	char		*a, **vals;
7056842Sth160488 	BerElement	*ber;
7066842Sth160488 	int		seen_objectclass = 0, rewind = 0;
7076842Sth160488 
7086842Sth160488 	if (!door_line) {
7096842Sth160488 		return (NS_LDAP_INVALID_PARAM);
7106842Sth160488 	}
7116842Sth160488 	*door_line = NULL;
7126842Sth160488 
7136842Sth160488 	if ((e = ldap_first_entry(ld, result_msg)) == NULL) {
7146842Sth160488 		return (NS_LDAP_NOTFOUND);
7156842Sth160488 	}
7166842Sth160488 
7176842Sth160488 	/* calculate length of received data */
7186842Sth160488 	for (a = ldap_first_attribute(ld, e, &ber);
7196842Sth160488 	    a != NULL;
7206842Sth160488 	    a = ldap_next_attribute(ld, e, ber)) {
7216842Sth160488 
7226842Sth160488 		if ((vals = ldap_get_values(ld, e, a)) != NULL) {
7236842Sth160488 			for (i = 0; vals[i] != NULL; i++) {
7246842Sth160488 				total_length += (include_names ?
7256842Sth160488 				    strlen(a) : 0) +
7266842Sth160488 				    strlen(vals[i]) +
7276842Sth160488 				    strlen(DOORLINESEP) +1;
7286842Sth160488 			}
7296842Sth160488 			ldap_value_free(vals);
7306842Sth160488 		}
7316842Sth160488 		ldap_memfree(a);
7326842Sth160488 	}
7336842Sth160488 	if (ber != NULL) {
7346842Sth160488 		ber_free(ber, 0);
7356842Sth160488 	}
7366842Sth160488 
7376842Sth160488 	if (total_length == 0) {
7386842Sth160488 		return (NS_LDAP_NOTFOUND);
7396842Sth160488 	}
7406842Sth160488 
7416842Sth160488 	/* copy the data */
7426842Sth160488 	/* add 1 for the last '\0' */
7436842Sth160488 	*door_line  = (char *)malloc(total_length + 1);
7446842Sth160488 	if (*door_line == NULL) {
7456842Sth160488 		return (NS_LDAP_MEMORY);
7466842Sth160488 	}
7476842Sth160488 
7486842Sth160488 	/* make it an empty string first */
7496842Sth160488 	**door_line = '\0';
7506842Sth160488 	a = ldap_first_attribute(ld, e, &ber);
7516842Sth160488 	while (a != NULL) {
7526842Sth160488 		if (is_profile) {
7536842Sth160488 			/*
7546842Sth160488 			 * If we're processing DUAConfigProfile, we need to make
7556842Sth160488 			 * sure we put objectclass attribute first.
7566842Sth160488 			 * __s_api_create_config_door_str depends on that.
7576842Sth160488 			 */
7586842Sth160488 			if (seen_objectclass) {
7596842Sth160488 				if (strcasecmp(a, "objectclass") == 0) {
7606842Sth160488 					/* Skip objectclass now. */
7616842Sth160488 					a = ldap_next_attribute(ld, e, ber);
7626842Sth160488 					continue;
7636842Sth160488 				}
7646842Sth160488 			} else {
7656842Sth160488 				if (strcasecmp(a, "objectclass") == 0) {
7666842Sth160488 					seen_objectclass = 1;
7676842Sth160488 					rewind = 1;
7686842Sth160488 				} else {
7696842Sth160488 					/* Skip all but objectclass first. */
7706842Sth160488 					a = ldap_next_attribute(ld, e, ber);
7716842Sth160488 					continue;
7726842Sth160488 				}
7736842Sth160488 			}
7746842Sth160488 		}
7756842Sth160488 
7766842Sth160488 		if ((vals = ldap_get_values(ld, e, a)) != NULL) {
7776842Sth160488 			for (i = 0; vals[i] != NULL; i++) {
7786842Sth160488 				if (include_names) {
7796842Sth160488 					attr_len += strlen(a);
7806842Sth160488 				}
7816842Sth160488 				attr_len += strlen(vals[i]) +
7826842Sth160488 				    strlen(DOORLINESEP) + 2;
7836842Sth160488 				if (include_names) {
7846842Sth160488 					(void) snprintf(*door_line +
7856842Sth160488 					    strlen(*door_line),
7866842Sth160488 					    attr_len,
7876842Sth160488 					    "%s=%s%s",
7886842Sth160488 					    a, vals[i],
7896842Sth160488 					    DOORLINESEP);
7906842Sth160488 				} else {
7916842Sth160488 					(void) snprintf(*door_line +
7926842Sth160488 					    strlen(*door_line),
7936842Sth160488 					    attr_len,
7946842Sth160488 					    "%s%s",
7956842Sth160488 					    vals[i],
7966842Sth160488 					    DOORLINESEP);
7976842Sth160488 				}
7986842Sth160488 			}
7996842Sth160488 			ldap_value_free(vals);
8006842Sth160488 		}
8016842Sth160488 		ldap_memfree(a);
8026842Sth160488 
8036842Sth160488 		/* Rewind */
8046842Sth160488 		if (rewind) {
8056842Sth160488 			if (ber != NULL) {
8066842Sth160488 				ber_free(ber, 0);
8076842Sth160488 			}
8086842Sth160488 			a = ldap_first_attribute(ld, e, &ber);
8096842Sth160488 			rewind = 0;
8106842Sth160488 		} else {
8116842Sth160488 			a = ldap_next_attribute(ld, e, ber);
8126842Sth160488 		}
8136842Sth160488 	}
8146842Sth160488 	if (ber != NULL) {
8156842Sth160488 		ber_free(ber, 0);
8166842Sth160488 	}
8176842Sth160488 
8186842Sth160488 	if (e != result_msg) {
8196842Sth160488 		(void) ldap_msgfree(e);
8206842Sth160488 	}
8216842Sth160488 
8226842Sth160488 	return (NS_LDAP_SUCCESS);
8236842Sth160488 }
8246842Sth160488 
8256842Sth160488 /*
8266842Sth160488  * This function looks up the base DN of a directory serving
8276842Sth160488  * a specified domain name.
8286842Sth160488  *
8296842Sth160488  * INPUT:
8306842Sth160488  *     ld - a pointer to an LDAP structure used for the search operation,
8316842Sth160488  *     domain_name - the name of a domain.
8326842Sth160488  *
8336842Sth160488  * OUTPUT:
8346842Sth160488  *     a buffer containing a directory's base DN found.
8356842Sth160488  *     Should be free'ed by the caller.
8366842Sth160488  */
8376842Sth160488 static
8386842Sth160488 ns_ldap_return_code
getDirBaseDN(LDAP * ld,const char * domain_name,char ** dir_base_dn)8396842Sth160488 getDirBaseDN(LDAP *ld, const char *domain_name, char **dir_base_dn)
8406842Sth160488 {
8416842Sth160488 	struct timeval		tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
8426842Sth160488 	char			*attrs[2], *DNlist, *rest, *ptr;
8436842Sth160488 	char			filter[BUFSIZ], *a = NULL;
8446842Sth160488 	int			ldap_rc;
8456842Sth160488 	LDAPMessage		*resultMsg = NULL;
8466842Sth160488 	ns_ldap_return_code	ret_code;
8476842Sth160488 
8486842Sth160488 	/* Get the whole list of naming contexts residing on the server */
8496842Sth160488 	attrs[0] = "namingcontexts";
8506842Sth160488 	attrs[1] = NULL;
8516842Sth160488 	ldap_rc = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
8526842Sth160488 	    attrs, 0, NULL, NULL, &tv, 0, &resultMsg);
8536842Sth160488 	switch (ldap_rc) {
8546842Sth160488 		/* If successful, the root DSE was found. */
8556842Sth160488 		case LDAP_SUCCESS:
8566842Sth160488 			break;
8576842Sth160488 		/*
8586842Sth160488 		 * If the root DSE was not found, the server does
8596842Sth160488 		 * not comply with the LDAP v3 protocol.
8606842Sth160488 		 */
8616842Sth160488 		default:
8626842Sth160488 			if (resultMsg) {
8636842Sth160488 				(void) ldap_msgfree(resultMsg);
8646842Sth160488 				resultMsg = NULL;
8656842Sth160488 			}
8666842Sth160488 
8676842Sth160488 			return (NS_LDAP_OP_FAILED);
8686842Sth160488 			break;
8696842Sth160488 	}
8706842Sth160488 
8716842Sth160488 	if ((ret_code = convert_to_door_line(ld,
8726842Sth160488 	    resultMsg,
8736842Sth160488 	    DONT_INCLUDE_ATTR_NAMES,
8746842Sth160488 	    NOT_PROFILE,
8756842Sth160488 	    &DNlist)) != NS_LDAP_SUCCESS) {
8766842Sth160488 		if (resultMsg) {
8776842Sth160488 			(void) ldap_msgfree(resultMsg);
8786842Sth160488 			resultMsg = NULL;
8796842Sth160488 		}
8806842Sth160488 		return (ret_code);
8816842Sth160488 	}
8826842Sth160488 
8836842Sth160488 	if (resultMsg) {
8846842Sth160488 		(void) ldap_msgfree(resultMsg);
8856842Sth160488 		resultMsg = NULL;
8866842Sth160488 	}
8876842Sth160488 
8886842Sth160488 	if (DNlist == NULL ||
8896842Sth160488 	    (ptr = strtok_r(DNlist, DOORLINESEP, &rest)) == NULL) {
8906842Sth160488 		return (NS_LDAP_NOTFOUND);
8916842Sth160488 	}
8926842Sth160488 	attrs[0] = "dn";
8936842Sth160488 	do {
8946842Sth160488 		/*
8956842Sth160488 		 * For each context try to find a NIS domain object
8966842Sth160488 		 * which 'nisdomain' attribute's value matches the domain name
8976842Sth160488 		 */
8986842Sth160488 		(void) snprintf(filter,
8996842Sth160488 		    BUFSIZ,
9006842Sth160488 		    "(&(objectclass=nisDomainObject)"
9016842Sth160488 		    "(nisdomain=%s))",
9026842Sth160488 		    domain_name);
9036842Sth160488 		ldap_rc = ldap_search_ext_s(ld,
9046842Sth160488 		    ptr,
9056842Sth160488 		    LDAP_SCOPE_SUBTREE,
9066842Sth160488 		    filter,
9076842Sth160488 		    attrs,
9086842Sth160488 		    0,
9096842Sth160488 		    NULL,
9106842Sth160488 		    NULL,
9116842Sth160488 		    &tv,
9126842Sth160488 		    0,
9136842Sth160488 		    &resultMsg);
9146842Sth160488 		if (ldap_rc != LDAP_SUCCESS) {
9156842Sth160488 			if (resultMsg) {
9166842Sth160488 				(void) ldap_msgfree(resultMsg);
9176842Sth160488 				resultMsg = NULL;
9186842Sth160488 			}
9196842Sth160488 			continue;
9206842Sth160488 		}
9216842Sth160488 		if ((a = ldap_get_dn(ld, resultMsg)) != NULL) {
9226842Sth160488 			*dir_base_dn = strdup(a);
9236842Sth160488 			ldap_memfree(a);
9246842Sth160488 
9256842Sth160488 			if (resultMsg) {
9266842Sth160488 				(void) ldap_msgfree(resultMsg);
9276842Sth160488 				resultMsg = NULL;
9286842Sth160488 			}
9296842Sth160488 
9306842Sth160488 			if (!*dir_base_dn) {
9316842Sth160488 				free(DNlist);
9326842Sth160488 				return (NS_LDAP_MEMORY);
9336842Sth160488 			}
9346842Sth160488 			break;
9356842Sth160488 		}
9366842Sth160488 
9376842Sth160488 		if (resultMsg) {
9386842Sth160488 			(void) ldap_msgfree(resultMsg);
9396842Sth160488 			resultMsg = NULL;
9406842Sth160488 		}
9416842Sth160488 	} while (ptr = strtok_r(NULL, DOORLINESEP, &rest));
9426842Sth160488 
9436842Sth160488 	free(DNlist);
9446842Sth160488 
9456842Sth160488 	if (!*dir_base_dn) {
9466842Sth160488 		return (NS_LDAP_NOTFOUND);
9476842Sth160488 	}
9486842Sth160488 
9496842Sth160488 	return (NS_LDAP_SUCCESS);
9506842Sth160488 }
9516842Sth160488 
9526842Sth160488 /*
9536842Sth160488  * This function parses the results of a search operation
9546842Sth160488  * requesting a DUAProfile.
9556842Sth160488  *
9566842Sth160488  * INPUT:
9576842Sth160488  *     ld - a pointer to an LDAP structure used for the search operation,
9586842Sth160488  *     dir_base_dn - the name of a directory's base DN,
9596842Sth160488  *     profile_name - the name of a DUAProfile to be obtained.
9606842Sth160488  *
9616842Sth160488  * OUTPUT:
9626842Sth160488  *      a buffer containing the DUAProfile in the following format:
9636842Sth160488  *        [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
9646842Sth160488  *      Should be free'ed by the caller.
9656842Sth160488  */
9666842Sth160488 static
9676842Sth160488 ns_ldap_return_code
getDUAProfile(LDAP * ld,const char * dir_base_dn,const char * profile_name,char ** profile)9686842Sth160488 getDUAProfile(LDAP *ld,
9696842Sth160488 		const char *dir_base_dn,
9706842Sth160488 		const char *profile_name,
9716842Sth160488 		char **profile)
9726842Sth160488 {
9736842Sth160488 	char			searchBaseDN[BUFSIZ], filter[BUFSIZ];
9746842Sth160488 	LDAPMessage		*resultMsg = NULL;
9756842Sth160488 	struct timeval		tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
9766842Sth160488 	int			ldap_rc;
9776842Sth160488 	ns_ldap_return_code	ret_code;
9786842Sth160488 
9796842Sth160488 	(void) snprintf(searchBaseDN, BUFSIZ, "ou=profile,%s", dir_base_dn);
9806842Sth160488 	(void) snprintf(filter,
9816842Sth160488 	    BUFSIZ,
9826842Sth160488 	    _PROFILE_FILTER,
9836842Sth160488 	    _PROFILE1_OBJECTCLASS,
9846842Sth160488 	    _PROFILE2_OBJECTCLASS,
9856842Sth160488 	    profile_name);
9866842Sth160488 	ldap_rc = ldap_search_ext_s(ld,
9876842Sth160488 	    searchBaseDN,
9886842Sth160488 	    LDAP_SCOPE_SUBTREE,
9896842Sth160488 	    filter,
9906842Sth160488 	    NULL,
9916842Sth160488 	    0,
9926842Sth160488 	    NULL,
9936842Sth160488 	    NULL,
9946842Sth160488 	    &tv,
9956842Sth160488 	    0,
9966842Sth160488 	    &resultMsg);
9976842Sth160488 
9986842Sth160488 	switch (ldap_rc) {
9996842Sth160488 		/* If successful, the DUA profile was found. */
10006842Sth160488 		case LDAP_SUCCESS:
10016842Sth160488 			break;
10026842Sth160488 		/*
10036842Sth160488 		 * If the root DSE was not found, the server does
10046842Sth160488 		 * not comply with the LDAP v3 protocol.
10056842Sth160488 		 */
10066842Sth160488 		default:
10076842Sth160488 			if (resultMsg) {
10086842Sth160488 				(void) ldap_msgfree(resultMsg);
10096842Sth160488 				resultMsg = NULL;
10106842Sth160488 			}
10116842Sth160488 
10126842Sth160488 			return (NS_LDAP_OP_FAILED);
10136842Sth160488 			break;
10146842Sth160488 	}
10156842Sth160488 
10166842Sth160488 	ret_code = convert_to_door_line(ld,
10176842Sth160488 	    resultMsg,
10186842Sth160488 	    INCLUDE_ATTR_NAMES,
10196842Sth160488 	    IS_PROFILE,
10206842Sth160488 	    profile);
10216842Sth160488 	if (resultMsg) {
10226842Sth160488 		(void) ldap_msgfree(resultMsg);
10236842Sth160488 		resultMsg = NULL;
10246842Sth160488 	}
10256842Sth160488 	return (ret_code);
10266842Sth160488 }
10276842Sth160488 
10286842Sth160488 /*
10296842Sth160488  * This function derives the directory's base DN from a provided domain name.
10306842Sth160488  *
10316842Sth160488  * INPUT:
10326842Sth160488  *     domain_name - the name of a domain to be converted into a base DN,
10336842Sth160488  *     buffer - contains the derived base DN,
10346842Sth160488  *     buf_len - the length of the buffer.
10356842Sth160488  *
10366842Sth160488  * OUTPUT:
10376842Sth160488  *     The function returns the address of the buffer or NULL.
10386842Sth160488  */
10396842Sth160488 static
10406842Sth160488 char *
domainname2baseDN(char * domain_name,char * buffer,uint16_t buf_len)10416842Sth160488 domainname2baseDN(char *domain_name, char *buffer, uint16_t buf_len)
10426842Sth160488 {
10436842Sth160488 	char		*nextDC, *chr;
10446842Sth160488 	uint16_t	i, length;
10456842Sth160488 
10466842Sth160488 	if (!domain_name || !buffer || buf_len == 0) {
10476842Sth160488 		return (NULL);
10486842Sth160488 	}
10496842Sth160488 
10506842Sth160488 	buffer[0] = '\0';
10516842Sth160488 	nextDC = chr = domain_name;
10526842Sth160488 	length = strlen(domain_name);
10536842Sth160488 	for (i = 0; i < length + 1; ++i, ++chr) {
10546842Sth160488 		/* Simply replace dots with "dc=" */
10556842Sth160488 		if (*chr != '.' && *chr != '\0') {
10566842Sth160488 			continue;
10576842Sth160488 		}
10586842Sth160488 		*chr = '\0';
10596842Sth160488 		if (strlcat(buffer, "dc=", buf_len) >= buf_len)
10606842Sth160488 			return (NULL);
10616842Sth160488 		if (strlcat(buffer, nextDC, buf_len) >= buf_len)
10626842Sth160488 			return (NULL);
10636842Sth160488 		if (i < length) {
10646842Sth160488 			/*
10656842Sth160488 			 * The end of the domain name
10666842Sth160488 			 * has not been reached yet
10676842Sth160488 			 */
10686842Sth160488 			if (strlcat(buffer, ",", buf_len) >= buf_len)
10696842Sth160488 				return (NULL);
10706842Sth160488 			nextDC = chr + 1;
10716842Sth160488 			*chr = '.';
10726842Sth160488 		}
10736842Sth160488 	}
10746842Sth160488 
10756842Sth160488 	return (buffer);
10766842Sth160488 }
10776842Sth160488 
10786842Sth160488 /*
10796842Sth160488  * This function obtains the directory's base DN and a DUAProfile
10806842Sth160488  * from a specified server.
10816842Sth160488  *
10826842Sth160488  * INPUT:
10836842Sth160488  *     server - a structure describing a server to connect to and
10846842Sth160488  *              a DUAProfile to be obtained from the server,
10856842Sth160488  *     cred - credentials to be used during establishing connections to
10866842Sth160488  *            the server.
10876842Sth160488  *
10886842Sth160488  * OUTPUT:
10896842Sth160488  *     dua_profile - a buffer containing the DUAProfile in the following format:
10906842Sth160488  *        [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
10916842Sth160488  *     dir_base_dn - a buffer containing the base DN,
10926842Sth160488  *     errorp - an error object describing an error, if any.
10936842Sth160488  *
10946842Sth160488  *     All the output data structures should be free'ed by the caller.
10956842Sth160488  */
10966842Sth160488 ns_ldap_return_code
__ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t * server,const ns_cred_t * cred,char ** dua_profile,char ** dir_base_dn,ns_ldap_error_t ** errorp)10976842Sth160488 __ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t *server,
10986842Sth160488 	const ns_cred_t *cred,
10996842Sth160488 	char **dua_profile,
11006842Sth160488 	char **dir_base_dn,
11016842Sth160488 	ns_ldap_error_t **errorp)
11026842Sth160488 {
11036842Sth160488 	char			serverAddr[MAX_HOSTADDR_LEN];
11046842Sth160488 	char			*dirBaseDN = NULL, *duaProfile = NULL;
11056842Sth160488 	ns_cred_t		default_cred;
11066842Sth160488 	ns_ldap_return_code	ret_code;
11076842Sth160488 
11086842Sth160488 	ns_config_t		*config_struct = __s_api_create_config();
11096842Sth160488 	ConnectionID		sessionId = 0;
11106842Sth160488 	Connection		*session = NULL;
11116842Sth160488 	char			errmsg[MAXERROR];
11126842Sth160488 	char			buffer[NSS_BUFLEN_HOSTS];
11137281Smichen 	ns_conn_user_t		*cu = NULL;
11146842Sth160488 
11156842Sth160488 	if (errorp == NULL) {
11166842Sth160488 		__s_api_destroy_config(config_struct);
11176842Sth160488 		return (NS_LDAP_INVALID_PARAM);
11186842Sth160488 	}
11196842Sth160488 
11206842Sth160488 	*errorp = NULL;
11216842Sth160488 
11226842Sth160488 	if (server == NULL) {
11236842Sth160488 		__s_api_destroy_config(config_struct);
11246842Sth160488 		return (NS_LDAP_INVALID_PARAM);
11256842Sth160488 	}
11266842Sth160488 
11276842Sth160488 	if (config_struct == NULL) {
11286842Sth160488 		return (NS_LDAP_MEMORY);
11296842Sth160488 	}
11306842Sth160488 
11316842Sth160488 	/*
11326842Sth160488 	 * If no credentials are specified, try to establish a connection
11336842Sth160488 	 * as anonymous.
11346842Sth160488 	 */
11356842Sth160488 	if (!cred) {
11366842Sth160488 		default_cred.cred.unix_cred.passwd = NULL;
11376842Sth160488 		default_cred.cred.unix_cred.userID = NULL;
11386842Sth160488 		default_cred.auth.type = NS_LDAP_AUTH_NONE;
11396842Sth160488 	}
11406842Sth160488 
11416842Sth160488 	/* Now create a default LDAP configuration */
11426842Sth160488 
11436842Sth160488 	(void) strncpy(buffer, server->server, sizeof (buffer));
11446842Sth160488 	if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SERVERS_P, buffer,
11456842Sth160488 	    errorp) != NS_LDAP_SUCCESS) {
11466842Sth160488 		__s_api_destroy_config(config_struct);
11476842Sth160488 		return (NS_LDAP_CONFIG);
11486842Sth160488 	}
11496842Sth160488 
11506842Sth160488 	/* Put together the address and the port specified by the user app. */
11516842Sth160488 	if (server->port > 0) {
11526842Sth160488 		(void) snprintf(serverAddr,
11536842Sth160488 		    sizeof (serverAddr),
11546842Sth160488 		    "%s:%hu",
11556842Sth160488 		    buffer,
11566842Sth160488 		    server->port);
11576842Sth160488 	} else {
11586842Sth160488 		(void) strncpy(serverAddr, buffer, sizeof (serverAddr));
11596842Sth160488 	}
11606842Sth160488 
11616842Sth160488 	/*
11626842Sth160488 	 * There is no default value for the 'Default Search Base DN' attribute.
11636842Sth160488 	 * Derive one from the domain name to make __s_api_crosscheck() happy.
11646842Sth160488 	 */
11656842Sth160488 	if (domainname2baseDN(server->domainName ?
11666842Sth160488 	    server->domainName : config_struct->domainName,
11676842Sth160488 	    buffer, NSS_BUFLEN_HOSTS) == NULL) {
11686842Sth160488 		(void) snprintf(errmsg,
11696842Sth160488 		    sizeof (errmsg),
11706842Sth160488 		    gettext("Can not convert %s into a base DN name"),
11716842Sth160488 		    server->domainName ?
11726842Sth160488 		    server->domainName : config_struct->domainName);
11736842Sth160488 		MKERROR(LOG_ERR,
11746842Sth160488 		    *errorp,
11756842Sth160488 		    NS_LDAP_INTERNAL,
11766842Sth160488 		    strdup(errmsg),
11776842Sth160488 		    NS_LDAP_MEMORY);
11786842Sth160488 		__s_api_destroy_config(config_struct);
11796842Sth160488 		return (NS_LDAP_INTERNAL);
11806842Sth160488 	}
11816842Sth160488 	if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SEARCH_BASEDN_P,
11826842Sth160488 	    buffer, errorp) != NS_LDAP_SUCCESS) {
11836842Sth160488 		__s_api_destroy_config(config_struct);
11846842Sth160488 		return (NS_LDAP_CONFIG);
11856842Sth160488 	}
11866842Sth160488 
11876842Sth160488 	if (__s_api_crosscheck(config_struct, errmsg, B_FALSE) != NS_SUCCESS) {
11886842Sth160488 		__s_api_destroy_config(config_struct);
11896842Sth160488 		return (NS_LDAP_CONFIG);
11906842Sth160488 	}
11916842Sth160488 
11926842Sth160488 	__s_api_init_config(config_struct);
11936842Sth160488 
11946842Sth160488 	__s_api_setInitMode();
11956842Sth160488 
11967281Smichen 	cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE);
11977281Smichen 	if (cu == NULL) {
11987281Smichen 		return (NS_LDAP_INTERNAL);
11997281Smichen 	}
12007281Smichen 
12016842Sth160488 	if ((ret_code = __s_api_getConnection(serverAddr,
12026842Sth160488 	    NS_LDAP_NEW_CONN,
12036842Sth160488 	    cred ? cred : &default_cred,
12046842Sth160488 	    &sessionId,
12056842Sth160488 	    &session,
12066842Sth160488 	    errorp,
12076842Sth160488 	    0,
12086842Sth160488 	    0,
12097281Smichen 	    cu)) != NS_LDAP_SUCCESS) {
12107281Smichen 		__s_api_conn_user_free(cu);
12116842Sth160488 		__s_api_unsetInitMode();
12126842Sth160488 		return (ret_code);
12136842Sth160488 	}
12146842Sth160488 
12156842Sth160488 	__s_api_unsetInitMode();
12166842Sth160488 
12176842Sth160488 	if ((ret_code = getDirBaseDN(session->ld,
12186842Sth160488 	    server->domainName ?
12196842Sth160488 	    server->domainName :
12206842Sth160488 	    config_struct->domainName,
12216842Sth160488 	    &dirBaseDN)) != NS_LDAP_SUCCESS) {
12226842Sth160488 		(void) snprintf(errmsg,
12236842Sth160488 		    sizeof (errmsg),
12246842Sth160488 		    gettext("Can not find the "
12256842Sth160488 		    "nisDomainObject for domain %s\n"),
12266842Sth160488 		    server->domainName ?
12276842Sth160488 		    server->domainName : config_struct->domainName);
12286842Sth160488 		MKERROR(LOG_ERR,
12296842Sth160488 		    *errorp,
12306842Sth160488 		    ret_code,
12316842Sth160488 		    strdup(errmsg),
12326842Sth160488 		    NS_LDAP_MEMORY);
12337281Smichen 		__s_api_conn_user_free(cu);
12346842Sth160488 		DropConnection(sessionId, NS_LDAP_NEW_CONN);
12356842Sth160488 		return (ret_code);
12366842Sth160488 	}
12376842Sth160488 
12386842Sth160488 	/*
12396842Sth160488 	 * And here obtain a DUAProfile which will be used
12406842Sth160488 	 * as a real configuration.
12416842Sth160488 	 */
12426842Sth160488 	if ((ret_code = getDUAProfile(session->ld,
12436842Sth160488 	    dirBaseDN,
12446842Sth160488 	    server->profileName ?
12456842Sth160488 	    server->profileName : "default",
12466842Sth160488 	    &duaProfile)) != NS_LDAP_SUCCESS) {
12476842Sth160488 		(void) snprintf(errmsg,
12486842Sth160488 		    sizeof (errmsg),
12496842Sth160488 		    gettext("Can not find the "
12506842Sth160488 		    "%s DUAProfile\n"),
12516842Sth160488 		    server->profileName ?
12526842Sth160488 		    server->profileName : "default");
12536842Sth160488 		MKERROR(LOG_ERR,
12546842Sth160488 		    *errorp,
12556842Sth160488 		    ret_code,
12566842Sth160488 		    strdup(errmsg),
12576842Sth160488 		    NS_LDAP_MEMORY);
12587281Smichen 		__s_api_conn_user_free(cu);
12596842Sth160488 		DropConnection(sessionId, NS_LDAP_NEW_CONN);
12606842Sth160488 		return (ret_code);
12616842Sth160488 	}
12626842Sth160488 
12636842Sth160488 	if (dir_base_dn) {
12646842Sth160488 		*dir_base_dn = dirBaseDN;
12656842Sth160488 	} else {
12666842Sth160488 		free(dirBaseDN);
12676842Sth160488 	}
12686842Sth160488 
12696842Sth160488 	if (dua_profile) {
12706842Sth160488 		*dua_profile = duaProfile;
12716842Sth160488 	} else {
12726842Sth160488 		free(duaProfile);
12736842Sth160488 	}
12746842Sth160488 
12757281Smichen 	__s_api_conn_user_free(cu);
12766842Sth160488 	DropConnection(sessionId, NS_LDAP_NEW_CONN);
12776842Sth160488 
12786842Sth160488 	return (NS_LDAP_SUCCESS);
12796842Sth160488 }
12806842Sth160488 
12816842Sth160488 /*
12826842Sth160488  * This function obtains the root DSE from a specified server.
12836842Sth160488  *
12846842Sth160488  * INPUT:
12856842Sth160488  *     server_addr - an adress of a server to be connected to.
12866842Sth160488  *
12876842Sth160488  * OUTPUT:
12886842Sth160488  *     root_dse - a buffer containing the root DSE in the following format:
12896842Sth160488  *          [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
12906842Sth160488  *        For example: ( here | used as DOORLINESEP for visual purposes)
12916842Sth160488  *          supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL
12926842Sth160488  *        Should be free'ed by the caller.
12936842Sth160488  */
12946842Sth160488 ns_ldap_return_code
__ns_ldap_getRootDSE(const char * server_addr,char ** root_dse,ns_ldap_error_t ** errorp,int anon_fallback)12956842Sth160488 __ns_ldap_getRootDSE(const char *server_addr,
12966842Sth160488 		char **root_dse,
12976842Sth160488 		ns_ldap_error_t **errorp,
12986842Sth160488 		int anon_fallback)
12996842Sth160488 {
13006842Sth160488 	char			errmsg[MAXERROR];
13016842Sth160488 	ns_ldap_return_code	ret_code;
13026842Sth160488 
13036842Sth160488 	ConnectionID		sessionId = 0;
13046842Sth160488 	Connection		*session = NULL;
13056842Sth160488 
13066842Sth160488 	struct timeval		tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
13076842Sth160488 	char			*attrs[3];
13086842Sth160488 	int			ldap_rc, ldaperrno = 0;
13096842Sth160488 	LDAPMessage		*resultMsg = NULL;
13106842Sth160488 	void			**paramVal = NULL;
13116842Sth160488 
13126842Sth160488 	ns_cred_t		anon;
13137281Smichen 	ns_conn_user_t		*cu = NULL;
13146842Sth160488 
13156842Sth160488 	if (errorp == NULL) {
13166842Sth160488 		return (NS_LDAP_INVALID_PARAM);
13176842Sth160488 	}
13186842Sth160488 
13196842Sth160488 	*errorp = NULL;
13206842Sth160488 
13216842Sth160488 	if (!root_dse) {
13226842Sth160488 		return (NS_LDAP_INVALID_PARAM);
13236842Sth160488 	}
13246842Sth160488 
13256842Sth160488 	if (!server_addr) {
13266842Sth160488 		return (NS_LDAP_INVALID_PARAM);
13276842Sth160488 	}
13286842Sth160488 
13296842Sth160488 	__s_api_setInitMode();
13306842Sth160488 
13317281Smichen 	cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE);
13327281Smichen 	if (cu == NULL) {
13337281Smichen 		return (NS_LDAP_INTERNAL);
13347281Smichen 	}
13357281Smichen 
13366842Sth160488 	/*
13376842Sth160488 	 * All the credentials will be taken from the current
13386842Sth160488 	 * libsldap configuration.
13396842Sth160488 	 */
13406842Sth160488 	if ((ret_code = __s_api_getConnection(server_addr,
13416842Sth160488 	    NS_LDAP_NEW_CONN,
13426842Sth160488 	    NULL,
13436842Sth160488 	    &sessionId,
13446842Sth160488 	    &session,
13456842Sth160488 	    errorp,
13466842Sth160488 	    0,
13476842Sth160488 	    0,
13487281Smichen 	    cu)) != NS_LDAP_SUCCESS) {
13496842Sth160488 		/* Fallback to anonymous mode is disabled. Stop. */
13506842Sth160488 		if (anon_fallback == 0) {
13516842Sth160488 			syslog(LOG_WARNING,
13526842Sth160488 			    gettext("libsldap: can not get the root DSE from "
13536842Sth160488 			    " the %s server: %s. "
13546842Sth160488 			    "Falling back to anonymous disabled.\n"),
13556842Sth160488 			    server_addr,
13566842Sth160488 			    errorp && *errorp && (*errorp)->message ?
13576842Sth160488 			    (*errorp)->message : "");
13586842Sth160488 			if (errorp != NULL && *errorp != NULL) {
13596842Sth160488 				(void) __ns_ldap_freeError(errorp);
13606842Sth160488 			}
13616842Sth160488 			__s_api_unsetInitMode();
13626842Sth160488 			return (ret_code);
13636842Sth160488 		}
13646842Sth160488 
13656842Sth160488 		/*
13666842Sth160488 		 * Fallback to anonymous, non-SSL mode for backward
13676842Sth160488 		 * compatibility reasons. This mode should only be used when
13686842Sth160488 		 * this function (__ns_ldap_getRootDSE) is called from
13696842Sth160488 		 * ldap_cachemgr(1M).
13706842Sth160488 		 */
13716842Sth160488 		syslog(LOG_WARNING,
13726842Sth160488 		    gettext("libsldap: Falling back to anonymous, non-SSL"
13736842Sth160488 		    " mode for __ns_ldap_getRootDSE. %s\n"),
13746842Sth160488 		    errorp && *errorp && (*errorp)->message ?
13756842Sth160488 		    (*errorp)->message : "");
13766842Sth160488 
13776842Sth160488 		/* Setup the anon credential for anonymous connection. */
13786842Sth160488 		(void) memset(&anon, 0, sizeof (ns_cred_t));
13796842Sth160488 		anon.auth.type = NS_LDAP_AUTH_NONE;
13806842Sth160488 
13816842Sth160488 		if (*errorp != NULL) {
13826842Sth160488 			(void) __ns_ldap_freeError(errorp);
13836842Sth160488 		}
13846842Sth160488 		*errorp = NULL;
13856842Sth160488 
13866842Sth160488 		ret_code = __s_api_getConnection(server_addr,
13876842Sth160488 		    NS_LDAP_NEW_CONN,
13886842Sth160488 		    &anon,
13896842Sth160488 		    &sessionId,
13906842Sth160488 		    &session,
13916842Sth160488 		    errorp,
13926842Sth160488 		    0,
13936842Sth160488 		    0,
13947281Smichen 		    cu);
13956842Sth160488 
13966842Sth160488 		if (ret_code != NS_LDAP_SUCCESS) {
13977281Smichen 			__s_api_conn_user_free(cu);
13986842Sth160488 			__s_api_unsetInitMode();
13996842Sth160488 			return (ret_code);
14006842Sth160488 		}
14016842Sth160488 	}
14026842Sth160488 
14036842Sth160488 	__s_api_unsetInitMode();
14046842Sth160488 
14056842Sth160488 	/* get search timeout value */
14066842Sth160488 	(void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P, &paramVal, errorp);
14076842Sth160488 	if (paramVal != NULL && *paramVal != NULL) {
14086842Sth160488 		tv.tv_sec = **((int **)paramVal);
14096842Sth160488 		(void) __ns_ldap_freeParam(&paramVal);
14106842Sth160488 	}
14116842Sth160488 	if (*errorp != NULL) {
14126842Sth160488 		(void) __ns_ldap_freeError(errorp);
14136842Sth160488 	}
14146842Sth160488 
14156842Sth160488 	/* Get root DSE from the server specified by the caller. */
14166842Sth160488 	attrs[0] = "supportedControl";
14176842Sth160488 	attrs[1] = "supportedsaslmechanisms";
14186842Sth160488 	attrs[2] = NULL;
14196842Sth160488 	ldap_rc = ldap_search_ext_s(session->ld,
14206842Sth160488 	    "",
14216842Sth160488 	    LDAP_SCOPE_BASE,
14226842Sth160488 	    "(objectclass=*)",
14236842Sth160488 	    attrs,
14246842Sth160488 	    0,
14256842Sth160488 	    NULL,
14266842Sth160488 	    NULL,
14276842Sth160488 	    &tv,
14286842Sth160488 	    0,
14296842Sth160488 	    &resultMsg);
14306842Sth160488 
14316842Sth160488 	if (ldap_rc != LDAP_SUCCESS) {
14326842Sth160488 		/*
14336842Sth160488 		 * If the root DSE was not found, the server does
14346842Sth160488 		 * not comply with the LDAP v3 protocol.
14356842Sth160488 		 */
14366842Sth160488 		(void) ldap_get_option(session->ld,
14376842Sth160488 		    LDAP_OPT_ERROR_NUMBER,
14386842Sth160488 		    &ldaperrno);
14396842Sth160488 		(void) snprintf(errmsg,
14406842Sth160488 		    sizeof (errmsg),
14416842Sth160488 		    gettext(ldap_err2string(ldaperrno)));
14426842Sth160488 		MKERROR(LOG_ERR,
14436842Sth160488 		    *errorp,
14446842Sth160488 		    NS_LDAP_OP_FAILED,
14456842Sth160488 		    strdup(errmsg),
14466842Sth160488 		    NS_LDAP_MEMORY);
14476842Sth160488 
14486842Sth160488 		if (resultMsg) {
14496842Sth160488 			(void) ldap_msgfree(resultMsg);
14506842Sth160488 			resultMsg = NULL;
14516842Sth160488 		}
14526842Sth160488 
14537281Smichen 		__s_api_conn_user_free(cu);
14546842Sth160488 		return (NS_LDAP_OP_FAILED);
14556842Sth160488 	}
14567281Smichen 	__s_api_conn_user_free(cu);
14576842Sth160488 
14586842Sth160488 	ret_code = convert_to_door_line(session->ld,
14596842Sth160488 	    resultMsg,
14606842Sth160488 	    INCLUDE_ATTR_NAMES,
14616842Sth160488 	    NOT_PROFILE,
14626842Sth160488 	    root_dse);
14636842Sth160488 	if (ret_code == NS_LDAP_NOTFOUND) {
14646842Sth160488 		(void) snprintf(errmsg,
14656842Sth160488 		    sizeof (errmsg),
14666842Sth160488 		    gettext("No root DSE data "
14676842Sth160488 		    "for server %s returned."),
14686842Sth160488 		    server_addr);
14696842Sth160488 		MKERROR(LOG_ERR,
14706842Sth160488 		    *errorp,
14716842Sth160488 		    NS_LDAP_NOTFOUND,
14726842Sth160488 		    strdup(errmsg),
14736842Sth160488 		    NS_LDAP_MEMORY);
14746842Sth160488 	}
14756842Sth160488 
14766842Sth160488 	if (resultMsg) {
14776842Sth160488 		(void) ldap_msgfree(resultMsg);
14786842Sth160488 		resultMsg = NULL;
14796842Sth160488 	}
14806842Sth160488 
14816842Sth160488 	DropConnection(sessionId, NS_LDAP_NEW_CONN);
14826842Sth160488 
14836842Sth160488 	return (ret_code);
14846842Sth160488 }
14856842Sth160488 
14866842Sth160488 /*
14876842Sth160488  * This function destroys the local list of root DSEs. The input parameter is
14886842Sth160488  * a pointer to the list to be erased.
14896842Sth160488  * The type of the pointer passed to this function should be
14906842Sth160488  * (dir_server_list_t *).
14916842Sth160488  */
14926842Sth160488 static
14936842Sth160488 void *
disposeOfOldList(void * param)14946842Sth160488 disposeOfOldList(void *param)
14956842Sth160488 {
14966842Sth160488 	dir_server_list_t	*old_list = (dir_server_list_t *)param;
14976842Sth160488 	long			i = 0, j;
14986842Sth160488 
14996842Sth160488 	(void) rw_wrlock(&old_list->listDestroyLock);
15006842Sth160488 	/* Destroy the old list */
15016842Sth160488 	while (old_list->nsServers[i]) {
15026842Sth160488 		free(old_list->nsServers[i]->ip);
15036842Sth160488 		j = 0;
15046842Sth160488 		while (old_list->nsServers[i]->controls &&
15056842Sth160488 		    old_list->nsServers[i]->controls[j]) {
15066842Sth160488 			free(old_list->nsServers[i]->controls[j]);
15076842Sth160488 			++j;
15086842Sth160488 		}
15096842Sth160488 		free(old_list->nsServers[i]->controls);
15106842Sth160488 		j = 0;
15116842Sth160488 		while (old_list->nsServers[i]->saslMech &&
15126842Sth160488 		    old_list->nsServers[i]->saslMech[j]) {
15136842Sth160488 			free(old_list->nsServers[i]->saslMech[j]);
15146842Sth160488 			++j;
15156842Sth160488 		}
15166842Sth160488 		free(old_list->nsServers[i]->saslMech);
15176842Sth160488 		++i;
15186842Sth160488 	}
15196842Sth160488 	/*
15206842Sth160488 	 * All the structures pointed by old_list->nsServers were allocated
15216842Sth160488 	 * in one chunck. The nsServers[0] pointer points to the beginning
15226842Sth160488 	 * of that chunck.
15236842Sth160488 	 */
15246842Sth160488 	free(old_list->nsServers[0]);
15256842Sth160488 	free(old_list->nsServers);
15266842Sth160488 	(void) rw_unlock(&old_list->listDestroyLock);
15276842Sth160488 	(void) rwlock_destroy(&old_list->listDestroyLock);
15286842Sth160488 	free(old_list);
15296842Sth160488 
15306842Sth160488 	return (NULL);
15316842Sth160488 }
15326842Sth160488 
15336842Sth160488 /*
15346842Sth160488  * This function cancels the Standalone mode and destroys the list of root DSEs.
15356842Sth160488  */
15366842Sth160488 void
__ns_ldap_cancelStandalone(void)15376842Sth160488 __ns_ldap_cancelStandalone(void)
15386842Sth160488 {
15396842Sth160488 	dir_server_list_t	*old_list;
15406842Sth160488 
15416842Sth160488 	(void) mutex_lock(&dir_servers.listReplaceLock);
15426842Sth160488 	dir_servers.standalone = 0;
15436842Sth160488 	if (!dir_servers.list) {
15446842Sth160488 		(void) mutex_unlock(&dir_servers.listReplaceLock);
15456842Sth160488 		return;
15466842Sth160488 	}
15476842Sth160488 	old_list = dir_servers.list;
15486842Sth160488 	dir_servers.list = NULL;
15496842Sth160488 	(void) mutex_unlock(&dir_servers.listReplaceLock);
15506842Sth160488 
15516842Sth160488 	(void) disposeOfOldList(old_list);
15526842Sth160488 }
15536842Sth160488 
15546842Sth160488 
15556842Sth160488 static
15566842Sth160488 void*
create_ns_servers_entry(void * param)15576842Sth160488 create_ns_servers_entry(void *param)
15586842Sth160488 {
15596842Sth160488 #define	CHUNK_SIZE 16
15606842Sth160488 
15616842Sth160488 	dir_server_t		*server = (dir_server_t *)param;
15626842Sth160488 	ns_ldap_return_code	*retCode = calloc(1,
15636842Sth160488 	    sizeof (ns_ldap_return_code));
15646842Sth160488 	uint32_t		sc_counter = 0, sm_counter = 0;
15656842Sth160488 	uint32_t		sc_mem_blocks = 1, sm_mem_blocks = 1;
15666842Sth160488 	char			*rootDSE = NULL, *attr, *val, *rest, **ptr;
15676842Sth160488 	ns_ldap_error_t		*error = NULL;
15686842Sth160488 
15696842Sth160488 	if (retCode == NULL) {
15706842Sth160488 		return (NULL);
15716842Sth160488 	}
15726842Sth160488 
15736842Sth160488 	/*
15746842Sth160488 	 * We call this function in non anon-fallback mode because we
15756842Sth160488 	 * want the whole procedure to fail as soon as possible to
15766842Sth160488 	 * indicate there are problems with connecting to the server.
15776842Sth160488 	 */
15786842Sth160488 	*retCode = __ns_ldap_getRootDSE(server->ip,
15796842Sth160488 	    &rootDSE,
15806842Sth160488 	    &error,
15816842Sth160488 	    SA_ALLOW_FALLBACK);
15826842Sth160488 
15836842Sth160488 	if (*retCode == NS_LDAP_MEMORY) {
15846842Sth160488 		free(retCode);
15856842Sth160488 		return (NULL);
15866842Sth160488 	}
15876842Sth160488 
15886842Sth160488 	/*
15896842Sth160488 	 * If the root DSE can not be obtained, log an error and keep the
15906842Sth160488 	 * server.
15916842Sth160488 	 */
15926842Sth160488 	if (*retCode != NS_LDAP_SUCCESS) {
15936842Sth160488 		server->status = INFO_SERVER_ERROR;
15946842Sth160488 		syslog(LOG_WARNING,
15956842Sth160488 		    gettext("libsldap (\"standalone\" mode): "
15966842Sth160488 		    "can not obtain the root DSE from %s. %s"),
15976842Sth160488 		    server->ip,
15986842Sth160488 		    error && error->message ? error->message : "");
15996842Sth160488 		if (error) {
16006842Sth160488 			(void) __ns_ldap_freeError(&error);
16016842Sth160488 		}
16026842Sth160488 		return (retCode);
16036842Sth160488 	}
16046842Sth160488 
16056842Sth160488 	/* Get the first attribute of the root DSE. */
16066842Sth160488 	attr = strtok_r(rootDSE, DOORLINESEP, &rest);
16076842Sth160488 	if (attr == NULL) {
16086842Sth160488 		free(rootDSE);
16096842Sth160488 		server->status = INFO_SERVER_ERROR;
16106842Sth160488 		syslog(LOG_WARNING,
16116842Sth160488 		    gettext("libsldap (\"standalone\" mode): "
16126842Sth160488 		    "the root DSE from %s is empty or corrupted."),
16136842Sth160488 		    server->ip);
16146842Sth160488 		*retCode = NS_LDAP_INTERNAL;
16156842Sth160488 		return (retCode);
16166842Sth160488 	}
16176842Sth160488 
16186842Sth160488 	server->controls = (char **)calloc(CHUNK_SIZE, sizeof (char *));
16196842Sth160488 	server->saslMech = (char **)calloc(CHUNK_SIZE, sizeof (char *));
16206842Sth160488 	if (server->controls == NULL || server->saslMech == NULL) {
16216842Sth160488 		free(rootDSE);
16226842Sth160488 		free(retCode);
16236842Sth160488 		return (NULL);
16246842Sth160488 	}
16256842Sth160488 
16266842Sth160488 	do {
16276842Sth160488 		if ((val = strchr(attr, '=')) == NULL) {
16286842Sth160488 			continue;
16296842Sth160488 		}
16306842Sth160488 		++val;
16316842Sth160488 
16326842Sth160488 		if (strncasecmp(attr,
16336842Sth160488 		    _SASLMECHANISM,
16346842Sth160488 		    _SASLMECHANISM_LEN) == 0) {
16356842Sth160488 			if (sm_counter == CHUNK_SIZE * sm_mem_blocks - 1) {
16366842Sth160488 				ptr = (char **)realloc(server->saslMech,
16376842Sth160488 				    CHUNK_SIZE *
16386842Sth160488 				    ++sm_mem_blocks *
16396842Sth160488 				    sizeof (char *));
16406842Sth160488 				if (ptr == NULL) {
16416842Sth160488 					*retCode = NS_LDAP_MEMORY;
16426842Sth160488 					break;
16436842Sth160488 				}
16446842Sth160488 				bzero((char *)ptr +
16456842Sth160488 				    (sm_counter + 1) *
16466842Sth160488 				    sizeof (char *),
16476842Sth160488 				    CHUNK_SIZE *
16486842Sth160488 				    sm_mem_blocks *
16496842Sth160488 				    sizeof (char *) -
16506842Sth160488 				    (sm_counter + 1) *
16516842Sth160488 				    sizeof (char *));
16526842Sth160488 				server->saslMech = ptr;
16536842Sth160488 			}
16546842Sth160488 			server->saslMech[sm_counter] = strdup(val);
16556842Sth160488 			if (server->saslMech[sm_counter] == NULL) {
16566842Sth160488 				*retCode = NS_LDAP_MEMORY;
16576842Sth160488 				break;
16586842Sth160488 			}
16596842Sth160488 			++sm_counter;
16606842Sth160488 			continue;
16616842Sth160488 		}
16626842Sth160488 		if (strncasecmp(attr,
16636842Sth160488 		    _SUPPORTEDCONTROL,
16646842Sth160488 		    _SUPPORTEDCONTROL_LEN) == 0) {
16656842Sth160488 			if (sc_counter == CHUNK_SIZE * sc_mem_blocks - 1) {
16666842Sth160488 				ptr = (char **)realloc(server->controls,
16676842Sth160488 				    CHUNK_SIZE *
16686842Sth160488 				    ++sc_mem_blocks *
16696842Sth160488 				    sizeof (char *));
16706842Sth160488 				if (ptr == NULL) {
16716842Sth160488 					*retCode = NS_LDAP_MEMORY;
16726842Sth160488 					break;
16736842Sth160488 				}
16746842Sth160488 				bzero((char *)ptr +
16756842Sth160488 				    (sc_counter + 1) *
16766842Sth160488 				    sizeof (char *),
16776842Sth160488 				    CHUNK_SIZE *
16786842Sth160488 				    sc_mem_blocks *
16796842Sth160488 				    sizeof (char *) -
16806842Sth160488 				    (sc_counter + 1) *
16816842Sth160488 				    sizeof (char *));
16826842Sth160488 				server->controls = ptr;
16836842Sth160488 			}
16846842Sth160488 
16856842Sth160488 			server->controls[sc_counter] = strdup(val);
16866842Sth160488 			if (server->controls[sc_counter] == NULL) {
16876842Sth160488 				*retCode = NS_LDAP_MEMORY;
16886842Sth160488 				break;
16896842Sth160488 			}
16906842Sth160488 			++sc_counter;
16916842Sth160488 			continue;
16926842Sth160488 		}
16936842Sth160488 
16946842Sth160488 	} while (attr = strtok_r(NULL, DOORLINESEP, &rest));
16956842Sth160488 
16966842Sth160488 	free(rootDSE);
16976842Sth160488 
16986842Sth160488 	if (*retCode == NS_LDAP_MEMORY) {
16996842Sth160488 		free(retCode);
17006842Sth160488 		return (NULL);
17016842Sth160488 	}
17026842Sth160488 
17036842Sth160488 	server->controls[sc_counter] = NULL;
17046842Sth160488 	server->saslMech[sm_counter] = NULL;
17056842Sth160488 
17066842Sth160488 	server->status = INFO_SERVER_UP;
17076842Sth160488 
17086842Sth160488 	return (retCode);
17096842Sth160488 #undef CHUNK_SIZE
17106842Sth160488 }
17116842Sth160488 
17126842Sth160488 
17136842Sth160488 /*
17146842Sth160488  * This function creates a new local list of root DSEs from all the servers
17156842Sth160488  * mentioned in the DUAProfile (or local NS BEC) and returns
17166842Sth160488  * a pointer to the list.
17176842Sth160488  */
17186842Sth160488 static
17196842Sth160488 ns_ldap_return_code
createDirServerList(dir_server_list_t ** new_list,ns_ldap_error_t ** errorp)17206842Sth160488 createDirServerList(dir_server_list_t **new_list,
17216842Sth160488 		ns_ldap_error_t **errorp)
17226842Sth160488 {
17236842Sth160488 	char			**serverList;
17246842Sth160488 	ns_ldap_return_code	retCode = NS_LDAP_SUCCESS;
17256842Sth160488 	dir_server_t		*tmpSrvArray;
17266842Sth160488 	long			srvListLength, i;
17276842Sth160488 	thread_t		*thrPool, thrID;
17286842Sth160488 	void			*status = NULL;
17296842Sth160488 
17306842Sth160488 	if (errorp == NULL) {
17316842Sth160488 		return (NS_LDAP_INVALID_PARAM);
17326842Sth160488 	}
17336842Sth160488 
17346842Sth160488 	*errorp = NULL;
17356842Sth160488 
17366842Sth160488 	if (new_list == NULL) {
17376842Sth160488 		return (NS_LDAP_INVALID_PARAM);
17386842Sth160488 	}
17396842Sth160488 
17406842Sth160488 	retCode = __s_api_getServers(&serverList, errorp);
17416842Sth160488 	if (retCode != NS_LDAP_SUCCESS || serverList == NULL) {
17426842Sth160488 		return (retCode);
17436842Sth160488 	}
17446842Sth160488 
17456842Sth160488 	for (i = 0; serverList[i]; ++i) {
17466842Sth160488 		;
17476842Sth160488 	}
17486842Sth160488 	srvListLength = i;
17496842Sth160488 
17506842Sth160488 	thrPool = calloc(srvListLength, sizeof (thread_t));
17516842Sth160488 	if (thrPool == NULL) {
17526842Sth160488 		__s_api_free2dArray(serverList);
17536842Sth160488 		return (NS_LDAP_MEMORY);
17546842Sth160488 	}
17556842Sth160488 
17566842Sth160488 	*new_list = (dir_server_list_t *)calloc(1,
17576842Sth160488 	    sizeof (dir_server_list_t));
17586842Sth160488 	if (*new_list == NULL) {
17596842Sth160488 		__s_api_free2dArray(serverList);
17606842Sth160488 		free(thrPool);
17616842Sth160488 		return (NS_LDAP_MEMORY);
17626842Sth160488 	}
17636842Sth160488 	(void) rwlock_init(&(*new_list)->listDestroyLock, USYNC_THREAD, NULL);
17646842Sth160488 
17656842Sth160488 	(*new_list)->nsServers = (dir_server_t **)calloc(srvListLength + 1,
17666842Sth160488 	    sizeof (dir_server_t *));
17676842Sth160488 	if ((*new_list)->nsServers == NULL) {
17686842Sth160488 		free(*new_list);
17696842Sth160488 		*new_list = NULL;
17706842Sth160488 		__s_api_free2dArray(serverList);
17716842Sth160488 		free(thrPool);
17726842Sth160488 		return (NS_LDAP_MEMORY);
17736842Sth160488 	}
17746842Sth160488 
17756842Sth160488 	/*
17766842Sth160488 	 * Allocate a set of dir_server_t structures as an array,
17776842Sth160488 	 * with one alloc call and then initialize the nsServers pointers
17786842Sth160488 	 * with the addresses of the array's members.
17796842Sth160488 	 */
17806842Sth160488 	tmpSrvArray = (dir_server_t *)calloc(srvListLength,
17816842Sth160488 	    sizeof (dir_server_t));
17826842Sth160488 	for (i = 0; i < srvListLength; ++i) {
17836842Sth160488 		(*new_list)->nsServers[i] = &tmpSrvArray[i];
17846842Sth160488 
17856842Sth160488 		(*new_list)->nsServers[i]->info = INFO_STATUS_NEW;
17866842Sth160488 		(void) mutex_init(&(*new_list)->nsServers[i]->updateStatus,
17876842Sth160488 		    USYNC_THREAD,
17886842Sth160488 		    NULL);
17896842Sth160488 
17906842Sth160488 		(*new_list)->nsServers[i]->ip = strdup(serverList[i]);
17916842Sth160488 		if ((*new_list)->nsServers[i]->ip == NULL) {
17926842Sth160488 			retCode = NS_LDAP_MEMORY;
17936842Sth160488 			break;
17946842Sth160488 		}
17956842Sth160488 
17966842Sth160488 		(*new_list)->nsServers[i]->status = INFO_SERVER_CONNECTING;
17976842Sth160488 
17986842Sth160488 		switch (thr_create(NULL,
17996842Sth160488 		    0,
18006842Sth160488 		    create_ns_servers_entry,
18016842Sth160488 		    (*new_list)->nsServers[i],
18026842Sth160488 		    0,
18036842Sth160488 		    &thrID)) {
18046842Sth160488 		case EAGAIN:
18056842Sth160488 			(*new_list)->nsServers[i]->status =
18066842Sth160488 			    INFO_SERVER_ERROR;
18076842Sth160488 			continue;
18086842Sth160488 			break;
18096842Sth160488 		case ENOMEM:
18106842Sth160488 			(*new_list)->nsServers[i]->status =
18116842Sth160488 			    INFO_SERVER_ERROR;
18126842Sth160488 			continue;
18136842Sth160488 			break;
18146842Sth160488 		default:
18156842Sth160488 			thrPool[i] = thrID;
18166842Sth160488 			continue;
18176842Sth160488 			break;
18186842Sth160488 		}
18196842Sth160488 	}
18206842Sth160488 
18216842Sth160488 	for (i = 0; i < srvListLength; ++i) {
18226842Sth160488 		if (thrPool[i] != 0 &&
18236842Sth160488 		    thr_join(thrPool[i], NULL, &status) == 0) {
18246842Sth160488 			if (status == NULL) {
18256842Sth160488 				/*
18266842Sth160488 				 * Some memory allocation problems occured. Just
18276842Sth160488 				 * ignore the server and hope there will be some
18286842Sth160488 				 * other good ones.
18296842Sth160488 				 */
18306842Sth160488 				(*new_list)->nsServers[i]->status =
18316842Sth160488 				    INFO_SERVER_ERROR;
18326842Sth160488 			}
18336842Sth160488 			free(status);
18346842Sth160488 		}
18356842Sth160488 	}
18366842Sth160488 
18376842Sth160488 	__s_api_free2dArray(serverList);
18386842Sth160488 	free(thrPool);
18396842Sth160488 
18406842Sth160488 	if (retCode == NS_LDAP_MEMORY) {
18416842Sth160488 		(void) disposeOfOldList(*new_list);
18426842Sth160488 		return (NS_LDAP_MEMORY);
18436842Sth160488 	}
18446842Sth160488 
18456842Sth160488 	return (NS_LDAP_SUCCESS);
18466842Sth160488 }
18476842Sth160488 
18486842Sth160488 /*
18496842Sth160488  * This functions replaces the local list of root DSEs with a new one and starts
18506842Sth160488  * a thread destroying the old list. There is no need for other threads to wait
18516842Sth160488  * until the old list will be destroyed.
18526842Sth160488  * Since it is possible that more than one thread can start creating the list,
18536842Sth160488  * this function should be protected by mutexes to be sure that only one thread
18546842Sth160488  * performs the initialization.
18556842Sth160488  */
18566842Sth160488 static
18576842Sth160488 ns_ldap_return_code
initGlobalList(ns_ldap_error_t ** error)18586842Sth160488 initGlobalList(ns_ldap_error_t **error)
18596842Sth160488 {
18606842Sth160488 	dir_server_list_t	*new_list, *old_list;
18616842Sth160488 	ns_ldap_return_code	ret_code;
18626842Sth160488 	thread_t		tid;
18636842Sth160488 
18646842Sth160488 	ret_code = createDirServerList(&new_list, error);
18656842Sth160488 	if (ret_code != NS_LDAP_SUCCESS) {
18666842Sth160488 		return (ret_code);
18676842Sth160488 	}
18686842Sth160488 
18696842Sth160488 	old_list = dir_servers.list;
18706842Sth160488 	dir_servers.list = new_list;
18716842Sth160488 
18726842Sth160488 	if (old_list) {
18736842Sth160488 		(void) thr_create(NULL,
18746842Sth160488 		    0,
18756842Sth160488 		    disposeOfOldList,
18766842Sth160488 		    old_list,
18776842Sth160488 		    THR_DETACHED,
18786842Sth160488 		    &tid);
18796842Sth160488 	}
18806842Sth160488 
18816842Sth160488 	return (NS_LDAP_SUCCESS);
18826842Sth160488 }
18836842Sth160488 
18846842Sth160488 static
18856842Sth160488 struct {
18866842Sth160488 	char *authMech;
18876842Sth160488 	ns_auth_t auth;
18886842Sth160488 } authArray[] = {{"none", {NS_LDAP_AUTH_NONE,
18896842Sth160488 			NS_LDAP_TLS_NONE,
18906842Sth160488 			NS_LDAP_SASL_NONE,
18916842Sth160488 			NS_LDAP_SASLOPT_NONE}},
18926842Sth160488 		{"simple", {NS_LDAP_AUTH_SIMPLE,
18936842Sth160488 			NS_LDAP_TLS_NONE,
18946842Sth160488 			NS_LDAP_SASL_NONE,
18956842Sth160488 			NS_LDAP_SASLOPT_NONE}},
18966842Sth160488 		{"tls:simple", {NS_LDAP_AUTH_TLS,
18976842Sth160488 			NS_LDAP_TLS_SIMPLE,
18986842Sth160488 			NS_LDAP_SASL_NONE,
18996842Sth160488 			NS_LDAP_SASLOPT_NONE}},
19006842Sth160488 		{"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS,
19016842Sth160488 			NS_LDAP_TLS_SASL,
19026842Sth160488 			NS_LDAP_SASL_CRAM_MD5,
19036842Sth160488 			NS_LDAP_SASLOPT_NONE}},
19046842Sth160488 		{"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS,
19056842Sth160488 			NS_LDAP_TLS_SASL,
19066842Sth160488 			NS_LDAP_SASL_DIGEST_MD5,
19076842Sth160488 			NS_LDAP_SASLOPT_NONE}},
19086842Sth160488 		{"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL,
19096842Sth160488 			NS_LDAP_TLS_SASL,
19106842Sth160488 			NS_LDAP_SASL_CRAM_MD5,
19116842Sth160488 			NS_LDAP_SASLOPT_NONE}},
19126842Sth160488 		{"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL,
19136842Sth160488 			NS_LDAP_TLS_SASL,
19146842Sth160488 			NS_LDAP_SASL_DIGEST_MD5,
19156842Sth160488 			NS_LDAP_SASLOPT_NONE}},
19166842Sth160488 		{"sasl/GSSAPI", {NS_LDAP_AUTH_SASL,
19176842Sth160488 			NS_LDAP_TLS_SASL,
19186842Sth160488 			NS_LDAP_SASL_GSSAPI,
19196842Sth160488 			NS_LDAP_SASLOPT_PRIV | NS_LDAP_SASLOPT_INT}},
19206842Sth160488 		{NULL, {NS_LDAP_AUTH_NONE,
19216842Sth160488 			NS_LDAP_TLS_NONE,
19226842Sth160488 			NS_LDAP_SASL_NONE,
19236842Sth160488 			NS_LDAP_SASLOPT_NONE}}};
19246842Sth160488 
19256842Sth160488 ns_ldap_return_code
__ns_ldap_initAuth(const char * auth_mech,ns_auth_t * auth,ns_ldap_error_t ** errorp)19266842Sth160488 __ns_ldap_initAuth(const char *auth_mech,
19276842Sth160488 		ns_auth_t *auth,
19286842Sth160488 		ns_ldap_error_t **errorp)
19296842Sth160488 {
19306842Sth160488 	uint32_t	i;
19316842Sth160488 	char		errmsg[MAXERROR];
19326842Sth160488 
19336842Sth160488 	if (auth_mech == NULL) {
19346842Sth160488 		(void) snprintf(errmsg,
19356842Sth160488 		    sizeof (errmsg),
19366842Sth160488 		    gettext("Invalid authentication method specified\n"));
19376842Sth160488 		MKERROR(LOG_WARNING,
19386842Sth160488 		    *errorp,
19396842Sth160488 		    NS_LDAP_INTERNAL,
19406842Sth160488 		    strdup(errmsg),
19416842Sth160488 		    NS_LDAP_MEMORY);
19426842Sth160488 		return (NS_LDAP_INTERNAL);
19436842Sth160488 	}
19446842Sth160488 
19456842Sth160488 	for (i = 0; authArray[i].authMech != NULL; ++i) {
19466842Sth160488 		if (strcasecmp(auth_mech, authArray[i].authMech) == 0) {
19476842Sth160488 			*auth = authArray[i].auth;
19486842Sth160488 			return (NS_LDAP_SUCCESS);
19496842Sth160488 		}
19506842Sth160488 	}
19516842Sth160488 
19526842Sth160488 	(void) snprintf(errmsg,
19536842Sth160488 	    sizeof (errmsg),
19546842Sth160488 	    gettext("Invalid authentication method specified\n"));
19556842Sth160488 	MKERROR(LOG_WARNING,
19566842Sth160488 	    *errorp,
19576842Sth160488 	    NS_LDAP_INTERNAL,
19586842Sth160488 	    strdup(errmsg),
19596842Sth160488 	    NS_LDAP_MEMORY);
19606842Sth160488 	return (NS_LDAP_INTERNAL);
19616842Sth160488 }
19626842Sth160488 
19636842Sth160488 /*
19646842Sth160488  * This function "informs" libsldap that a client application has specified
19656842Sth160488  * a directory to use. The function obtains a DUAProfile, credentials,
19666842Sth160488  * and naming context. During all further operations on behalf
19676842Sth160488  * of the application requested a standalone schema libsldap will use
19686842Sth160488  * the information obtained by __ns_ldap_initStandalone() instead of
19696842Sth160488  * door_call(3C)ing ldap_cachemgr(1M).
19706842Sth160488  *
19716842Sth160488  * INPUT:
19726842Sth160488  *     sa_conf - a structure describing where and in which way to obtain all
19736842Sth160488  *               the configuration describing how to communicate to
19746842Sth160488  *               a choosen LDAP directory,
19756842Sth160488  *     errorp - an error object describing an error occured.
19766842Sth160488  */
19776842Sth160488 ns_ldap_return_code
__ns_ldap_initStandalone(const ns_standalone_conf_t * sa_conf,ns_ldap_error_t ** errorp)19786842Sth160488 __ns_ldap_initStandalone(const ns_standalone_conf_t *sa_conf,
19796842Sth160488 			ns_ldap_error_t	**errorp) {
19806842Sth160488 
19816842Sth160488 	ns_cred_t	user_cred = {{NS_LDAP_AUTH_NONE,
19826842Sth160488 					NS_LDAP_TLS_NONE,
19836842Sth160488 					NS_LDAP_SASL_NONE,
19846842Sth160488 					NS_LDAP_SASLOPT_NONE},
19856842Sth160488 					NULL,
19866842Sth160488 					{NULL, NULL}};
19876842Sth160488 	char		*dua_profile = NULL;
19886842Sth160488 	char		errmsg[MAXERROR];
19896842Sth160488 	ns_config_t 	*cfg;
19906842Sth160488 	int		ret_code;
19916842Sth160488 
19926842Sth160488 	if (sa_conf->SA_BIND_DN == NULL && sa_conf->SA_BIND_PWD != NULL ||
19936842Sth160488 	    sa_conf->SA_BIND_DN != NULL && sa_conf->SA_BIND_PWD == NULL) {
19946842Sth160488 		(void) snprintf(errmsg,
19956842Sth160488 		    sizeof (errmsg),
19966842Sth160488 		    gettext("Bind DN and bind password"
19976842Sth160488 		    " must both be provided\n"));
19986842Sth160488 		MKERROR(LOG_ERR,
19996842Sth160488 		    *errorp,
20006842Sth160488 		    NS_CONFIG_NOTLOADED,
20016842Sth160488 		    strdup(errmsg),
20026842Sth160488 		    NS_LDAP_MEMORY);
20036842Sth160488 		return (NS_LDAP_INTERNAL);
20046842Sth160488 	}
20056842Sth160488 
20066842Sth160488 	switch (sa_conf->type) {
20076842Sth160488 	case NS_LDAP_SERVER:
20086842Sth160488 		if (sa_conf->SA_BIND_DN != NULL) {
20096842Sth160488 			user_cred.cred.unix_cred.userID = sa_conf->SA_BIND_DN;
20106842Sth160488 			user_cred.auth.type = NS_LDAP_AUTH_SIMPLE;
20116842Sth160488 		}
20126842Sth160488 
20136842Sth160488 		if (sa_conf->SA_BIND_PWD != NULL) {
20146842Sth160488 			user_cred.cred.unix_cred.passwd = sa_conf->SA_BIND_PWD;
20156842Sth160488 		}
20166842Sth160488 
20176842Sth160488 		if (sa_conf->SA_AUTH != NULL) {
20186842Sth160488 			user_cred.auth.type = sa_conf->SA_AUTH->type;
20196842Sth160488 			user_cred.auth.tlstype = sa_conf->SA_AUTH->tlstype;
20206842Sth160488 			user_cred.auth.saslmech = sa_conf->SA_AUTH->saslmech;
20216842Sth160488 			user_cred.auth.saslopt = sa_conf->SA_AUTH->saslopt;
20226842Sth160488 		}
20236842Sth160488 
20246842Sth160488 		if (sa_conf->SA_CERT_PATH != NULL) {
20256842Sth160488 			user_cred.hostcertpath = sa_conf->SA_CERT_PATH;
20266842Sth160488 		}
20276842Sth160488 
20286842Sth160488 		ret_code = __ns_ldap_getConnectionInfoFromDUA(
20296842Sth160488 		    &sa_conf->ds_profile.server,
20306842Sth160488 		    &user_cred,
20316842Sth160488 		    &dua_profile,
20326842Sth160488 		    NULL,
20336842Sth160488 		    errorp);
20346842Sth160488 		if (ret_code != NS_LDAP_SUCCESS) {
20356842Sth160488 			return (ret_code);
20366842Sth160488 		}
20376842Sth160488 
20386842Sth160488 		cfg = __s_api_create_config_door_str(dua_profile, errorp);
20396842Sth160488 		if (cfg == NULL) {
20406842Sth160488 			free(dua_profile);
20416842Sth160488 			return (NS_LDAP_CONFIG);
20426842Sth160488 		}
20436842Sth160488 
20446842Sth160488 		if (sa_conf->SA_CERT_PATH != NULL) {
20456842Sth160488 			char		*certPathAttr;
20466842Sth160488 			ParamIndexType	type;
20476842Sth160488 
20486842Sth160488 			switch (cfg->version) {
20496842Sth160488 			case NS_LDAP_V1:
20506842Sth160488 				certPathAttr = "NS_LDAP_CERT_PATH";
20516842Sth160488 				break;
20526842Sth160488 			default:	/* Version 2 */
20536842Sth160488 				certPathAttr = "NS_LDAP_HOST_CERTPATH";
20546842Sth160488 				break;
20556842Sth160488 			}
20566842Sth160488 
20576842Sth160488 			if (__s_api_get_versiontype(cfg,
20586842Sth160488 						certPathAttr,
20596842Sth160488 						&type) == 0 &&
20606842Sth160488 			    (ret_code = __ns_ldap_setParamValue(cfg,
20616842Sth160488 						type,
20626842Sth160488 						sa_conf->SA_CERT_PATH,
20636842Sth160488 						errorp)) != NS_LDAP_SUCCESS) {
20646842Sth160488 				__s_api_destroy_config(cfg);
20656842Sth160488 				return (ret_code);
20666842Sth160488 			}
20676842Sth160488 		}
20686842Sth160488 
20696842Sth160488 		if (sa_conf->SA_BIND_DN != NULL &&
20706842Sth160488 		    sa_conf->SA_BIND_PWD != NULL) {
2071*10132SMilan.Jurik@Sun.COM 			char *authMethods;
20726842Sth160488 
2073*10132SMilan.Jurik@Sun.COM 			authMethods = __s_api_strValue(cfg, NS_LDAP_AUTH_P,
20746842Sth160488 			    NS_FILE_FMT);
20756842Sth160488 			if (authMethods != NULL &&
20766842Sth160488 			    strstr(authMethods, "sasl/GSSAPI") != NULL) {
20776842Sth160488 				/*
20786842Sth160488 				 * The received DUAProfile specifies
20796842Sth160488 				 * sasl/GSSAPI as an auth. mechanism.
20806842Sth160488 				 * The bind DN and password will be
20816842Sth160488 				 * ignored.
20826842Sth160488 				 */
20836842Sth160488 				syslog(LOG_INFO, gettext("sasl/GSSAPI will be "
20846842Sth160488 				    "used as an authentication method. "
20856842Sth160488 				    "The bind DN and password will "
20866842Sth160488 				    "be ignored.\n"));
2087*10132SMilan.Jurik@Sun.COM 				free(authMethods);
20886842Sth160488 				break;
20896842Sth160488 			}
20906842Sth160488 
2091*10132SMilan.Jurik@Sun.COM 			if (authMethods != NULL)
2092*10132SMilan.Jurik@Sun.COM 				free(authMethods);
2093*10132SMilan.Jurik@Sun.COM 
20946842Sth160488 			if (__ns_ldap_setParamValue(cfg,
20956842Sth160488 						NS_LDAP_BINDDN_P,
20966842Sth160488 						sa_conf->SA_BIND_DN,
20976842Sth160488 						errorp) != NS_LDAP_SUCCESS) {
20986842Sth160488 				__s_api_destroy_config(cfg);
20996842Sth160488 				return (NS_LDAP_CONFIG);
21006842Sth160488 			}
21016842Sth160488 
21026842Sth160488 			if (__ns_ldap_setParamValue(cfg,
21036842Sth160488 			    NS_LDAP_BINDPASSWD_P,
21046842Sth160488 			    sa_conf->SA_BIND_PWD,
21056842Sth160488 			    errorp) != NS_LDAP_SUCCESS) {
21066842Sth160488 				__s_api_destroy_config(cfg);
21076842Sth160488 				return (NS_LDAP_CONFIG);
21086842Sth160488 			}
21096842Sth160488 		}
21106842Sth160488 
21116842Sth160488 		break;
21126842Sth160488 	default:	/* NS_CACHEMGR */
21136842Sth160488 		return (NS_LDAP_SUCCESS);
21146842Sth160488 	}
21156842Sth160488 
21166842Sth160488 	__s_api_init_config(cfg);
21176921Smichen 	/* Connection management should use the new config now. */
21186921Smichen 	__s_api_reinit_conn_mgmt_new_config(cfg);
21196842Sth160488 	__ns_ldap_setServer(TRUE);
21206842Sth160488 
21216842Sth160488 	(void) mutex_lock(&dir_servers.listReplaceLock);
21226842Sth160488 	if ((ret_code = initGlobalList(errorp)) != NS_SUCCESS) {
21236842Sth160488 		(void) mutex_unlock(&dir_servers.listReplaceLock);
21246842Sth160488 		return (ret_code);
21256842Sth160488 	}
21266842Sth160488 	dir_servers.standalone = 1;
21276842Sth160488 	(void) mutex_unlock(&dir_servers.listReplaceLock);
21286842Sth160488 
21296842Sth160488 	return (NS_LDAP_SUCCESS);
21306842Sth160488 }
21316842Sth160488 
21326842Sth160488 /*
21336842Sth160488  * INPUT:
21346842Sth160488  *     serverAddr is the address of a server and
21356842Sth160488  *     request is one of the following:
21366842Sth160488  *     NS_CACHE_NEW:    get a new server address, addr is ignored.
21376842Sth160488  *     NS_CACHE_NORESP: get the next one, remove addr from list.
21386842Sth160488  *     NS_CACHE_NEXT:   get the next one, keep addr on list.
21396842Sth160488  *     NS_CACHE_WRITE:  get a non-replica server, if possible, if not, same
21406842Sth160488  *                      as NS_CACHE_NEXT.
21416842Sth160488  *     addrType:
21426842Sth160488  *     NS_CACHE_ADDR_IP: return server address as is, this is default.
21436842Sth160488  *     NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only
21446842Sth160488  *                             self credential case requires such format.
21456842Sth160488  * OUTPUT:
21466842Sth160488  *     ret
21476842Sth160488  *
21486842Sth160488  *     a structure of type ns_server_info_t containing the server address
21496842Sth160488  *     or name, server controls and supported SASL mechanisms.
21506842Sth160488  *     NOTE: Caller should allocate space for the structure and free
21516842Sth160488  *     all the space allocated by the function for the information contained
21526842Sth160488  *     in the structure.
21536842Sth160488  *
21546842Sth160488  *     error - an error object describing an error, if any.
21556842Sth160488  */
21566842Sth160488 ns_ldap_return_code
__s_api_findRootDSE(const char * request,const char * serverAddr,const char * addrType,ns_server_info_t * ret,ns_ldap_error_t ** error)21576842Sth160488 __s_api_findRootDSE(const char *request,
21586842Sth160488 		const char *serverAddr,
21596842Sth160488 		const char *addrType,
21606842Sth160488 		ns_server_info_t *ret,
21616842Sth160488 		ns_ldap_error_t	**error)
21626842Sth160488 {
21636842Sth160488 	dir_server_list_t	*current_list = NULL;
21646842Sth160488 	ns_ldap_return_code	ret_code;
21656842Sth160488 	long			i = 0;
21666842Sth160488 	int			matched = FALSE;
21676842Sth160488 	dir_server_t		*server = NULL;
21686842Sth160488 	char			errmsg[MAXERROR];
21696842Sth160488 
21706842Sth160488 	(void) mutex_lock(&dir_servers.listReplaceLock);
21716842Sth160488 	if (dir_servers.list == NULL) {
21726842Sth160488 		(void) mutex_unlock(&dir_servers.listReplaceLock);
21736842Sth160488 		(void) snprintf(errmsg,
21746842Sth160488 		    sizeof (errmsg),
21756842Sth160488 		    gettext("The list of root DSEs is empty: "
21766842Sth160488 		    "the Standalone mode was not properly initialized"));
21776842Sth160488 		MKERROR(LOG_ERR,
21786842Sth160488 		    *error,
21796842Sth160488 		    NS_CONFIG_NOTLOADED,
21806842Sth160488 		    strdup(errmsg),
21816842Sth160488 		    NS_LDAP_MEMORY);
21826842Sth160488 		return (NS_LDAP_INTERNAL);
21836842Sth160488 	}
21846842Sth160488 
21856842Sth160488 	current_list = dir_servers.list;
21866842Sth160488 	(void) rw_rdlock(&current_list->listDestroyLock);
21876842Sth160488 	(void) mutex_unlock(&dir_servers.listReplaceLock);
21886842Sth160488 
21896842Sth160488 	/*
21906842Sth160488 	 * The code below is mostly the clone of the
21916842Sth160488 	 * ldap_cachemgr::cachemgr_getldap.c::getldap_get_serverInfo() function.
21926842Sth160488 	 * Currently we have two different server lists: one is maintained
21936842Sth160488 	 * by libsldap ('standalone' mode), the other is in ldap_cachemgr
21946842Sth160488 	 * (a part of its standard functionality).
21956842Sth160488 	 */
21966842Sth160488 
21976842Sth160488 	/*
21986842Sth160488 	 * If NS_CACHE_NEW, or the server info is new,
21996842Sth160488 	 * starts from the beginning of the list.
22006842Sth160488 	 */
22016842Sth160488 	(void) mutex_lock(&current_list->nsServers[0]->updateStatus);
22026842Sth160488 	if (strcmp(request, NS_CACHE_NEW) == 0 ||
22036842Sth160488 	    current_list->nsServers[0]->info == INFO_STATUS_NEW) {
22046842Sth160488 		matched = TRUE;
22056842Sth160488 	}
22066842Sth160488 	(void) mutex_unlock(&current_list->nsServers[i]->updateStatus);
22076842Sth160488 
22086842Sth160488 	for (i = 0; current_list->nsServers[i]; ++i) {
22096842Sth160488 		/*
22106842Sth160488 		 * Lock the updateStatus mutex to
22116842Sth160488 		 * make sure the server status stays the same
22126842Sth160488 		 * while the data is being processed.
22136842Sth160488 		 */
22146842Sth160488 		if (matched == FALSE &&
22156842Sth160488 		    strcmp(current_list->nsServers[i]->ip,
22166842Sth160488 		    serverAddr) == 0) {
22176842Sth160488 			matched = TRUE;
22186842Sth160488 			if (strcmp(request, NS_CACHE_NORESP) == 0) {
22196842Sth160488 
22206842Sth160488 				/*
22216842Sth160488 				 * if the server has already been removed,
22226842Sth160488 				 * don't bother.
22236842Sth160488 				 */
22246842Sth160488 				(void) mutex_lock(&current_list->
22256842Sth160488 				    nsServers[i]->updateStatus);
22266842Sth160488 				if (current_list->nsServers[i]->status ==
22276842Sth160488 				    INFO_SERVER_REMOVED) {
22286842Sth160488 					(void) mutex_unlock(&current_list->
22296842Sth160488 					    nsServers[i]->
22306842Sth160488 					    updateStatus);
22316842Sth160488 					continue;
22326842Sth160488 				}
22336842Sth160488 				(void) mutex_unlock(&current_list->
22346842Sth160488 				    nsServers[i]->
22356842Sth160488 				    updateStatus);
22366842Sth160488 
22376842Sth160488 				/*
22386842Sth160488 				 * if the information is new,
22396842Sth160488 				 * give this server one more chance.
22406842Sth160488 				 */
22416842Sth160488 				(void) mutex_lock(&current_list->
22426842Sth160488 				    nsServers[i]->
22436842Sth160488 				    updateStatus);
22446842Sth160488 				if (current_list->nsServers[i]->info ==
22456842Sth160488 				    INFO_STATUS_NEW &&
22466842Sth160488 				    current_list->nsServers[i]->status  ==
22476842Sth160488 				    INFO_SERVER_UP) {
22486842Sth160488 					server = current_list->nsServers[i];
22496842Sth160488 					(void) mutex_unlock(&current_list->
22506842Sth160488 					    nsServers[i]->
22516842Sth160488 					    updateStatus);
22526842Sth160488 					break;
22536842Sth160488 				} else {
22546842Sth160488 					/*
22556842Sth160488 					 * it is recommended that
22566842Sth160488 					 * before removing the
22576842Sth160488 					 * server from the list,
22586842Sth160488 					 * the server should be
22596842Sth160488 					 * contacted one more time
22606842Sth160488 					 * to make sure that it is
22616842Sth160488 					 * really unavailable.
22626842Sth160488 					 * For now, just trust the client
22636842Sth160488 					 * (i.e., the sldap library)
22646842Sth160488 					 * that it knows what it is
22656842Sth160488 					 * doing and would not try
22666842Sth160488 					 * to mess up the server
22676842Sth160488 					 * list.
22686842Sth160488 					 */
22696842Sth160488 					current_list->nsServers[i]->status =
22706842Sth160488 					    INFO_SERVER_REMOVED;
22716842Sth160488 					(void) mutex_unlock(&current_list->
22726842Sth160488 					    nsServers[i]->
22736842Sth160488 					    updateStatus);
22746842Sth160488 					continue;
22756842Sth160488 				}
22766842Sth160488 			} else {
22776842Sth160488 				/*
22786842Sth160488 				 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
22796842Sth160488 				 */
22806842Sth160488 				continue;
22816842Sth160488 			}
22826842Sth160488 		}
22836842Sth160488 
22846842Sth160488 		if (matched) {
22856842Sth160488 			if (strcmp(request, NS_CACHE_WRITE) == 0) {
22866842Sth160488 				/*
22876842Sth160488 				 * ldap_cachemgr checks here if the server
22886842Sth160488 				 * is not a non-replica server (a server
22896842Sth160488 				 * of type INFO_RW_WRITEABLE). But currently
22906842Sth160488 				 * it considers all the servers in its list
22916842Sth160488 				 * as those.
22926842Sth160488 				 */
22936842Sth160488 				(void) mutex_lock(&current_list->
22946842Sth160488 				    nsServers[i]->
22956842Sth160488 				    updateStatus);
22966842Sth160488 				if (current_list->nsServers[i]->status  ==
22976842Sth160488 				    INFO_SERVER_UP) {
22986842Sth160488 					(void) mutex_unlock(&current_list->
22996842Sth160488 					    nsServers[i]->
23006842Sth160488 					    updateStatus);
23016842Sth160488 					server = current_list->nsServers[i];
23026842Sth160488 					break;
23036842Sth160488 				}
23046842Sth160488 			} else {
23056842Sth160488 				(void) mutex_lock(&current_list->
23066842Sth160488 				    nsServers[i]->
23076842Sth160488 				    updateStatus);
23086842Sth160488 				if (current_list->nsServers[i]->status ==
23096842Sth160488 				    INFO_SERVER_UP) {
23106842Sth160488 					(void) mutex_unlock(&current_list->
23116842Sth160488 					    nsServers[i]->
23126842Sth160488 					    updateStatus);
23136842Sth160488 					server = current_list->nsServers[i];
23146842Sth160488 					break;
23156842Sth160488 				}
23166842Sth160488 			}
23176842Sth160488 
23186842Sth160488 			(void) mutex_unlock(&current_list->
23196842Sth160488 			    nsServers[i]->
23206842Sth160488 			    updateStatus);
23216842Sth160488 		}
23226842Sth160488 	}
23236842Sth160488 
23246842Sth160488 	if (server == NULL) {
23256842Sth160488 		(void) rw_unlock(&current_list->listDestroyLock);
23266842Sth160488 		(void) snprintf(errmsg,
23276842Sth160488 		    sizeof (errmsg),
23286842Sth160488 		    gettext("No servers are available"));
23296842Sth160488 		MKERROR(LOG_ERR,
23306842Sth160488 		    *error,
23316842Sth160488 		    NS_CONFIG_NOTLOADED,
23326842Sth160488 		    strdup(errmsg),
23336842Sth160488 		    NS_LDAP_MEMORY);
23346842Sth160488 		return (NS_LDAP_NOTFOUND);
23356842Sth160488 	}
23366842Sth160488 
23376842Sth160488 	(void) mutex_lock(&server->updateStatus);
23386842Sth160488 	server->info = INFO_STATUS_OLD;
23396842Sth160488 	(void) mutex_unlock(&server->updateStatus);
23406842Sth160488 
23416842Sth160488 	if (ret == NULL) {
23426842Sth160488 		(void) rw_unlock(&current_list->listDestroyLock);
23436842Sth160488 		return (NS_LDAP_SUCCESS);
23446842Sth160488 	}
23456842Sth160488 
23466842Sth160488 	if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
23476842Sth160488 		ret_code = __s_api_ip2hostname(server->ip, &ret->serverFQDN);
23486842Sth160488 		if (ret_code != NS_LDAP_SUCCESS) {
23496842Sth160488 			(void) snprintf(errmsg,
23506842Sth160488 			    sizeof (errmsg),
23516842Sth160488 			    gettext("The %s address "
23526842Sth160488 			    "can not be resolved into "
23536842Sth160488 			    "a host name. Returning "
23546842Sth160488 			    "the address as it is."),
23556842Sth160488 			    server->ip);
23566842Sth160488 			MKERROR(LOG_ERR,
23576842Sth160488 			    *error,
23586842Sth160488 			    NS_CONFIG_NOTLOADED,
23596842Sth160488 			    strdup(errmsg),
23606842Sth160488 			    NS_LDAP_MEMORY);
23616842Sth160488 			return (NS_LDAP_INTERNAL);
23626842Sth160488 		}
23636842Sth160488 	}
23646842Sth160488 
23656842Sth160488 	ret->server = strdup(server->ip);
23666842Sth160488 
23676842Sth160488 	ret->controls = __s_api_cp2dArray(server->controls);
23686842Sth160488 	ret->saslMechanisms = __s_api_cp2dArray(server->saslMech);
23696842Sth160488 
23706842Sth160488 	(void) rw_unlock(&current_list->listDestroyLock);
23716842Sth160488 
23726842Sth160488 	return (NS_LDAP_SUCCESS);
23736842Sth160488 }
23746842Sth160488 
23756842Sth160488 /*
23766842Sth160488  * This function iterates through the list of the configured LDAP servers
23776842Sth160488  * and "pings" those which are marked as removed or if any error occurred
23786842Sth160488  * during the previous receiving of the server's root DSE. If the
23796842Sth160488  * function is able to reach such a server and get its root DSE, it
23806842Sth160488  * marks the server as on-line. Otherwise, the server's status is set
23816842Sth160488  * to "Error".
23826842Sth160488  * For each server the function tries to connect to, it fires up
23836842Sth160488  * a separate thread and then waits until all the treads finish.
23846842Sth160488  * The function returns NS_LDAP_INTERNAL if the Standalone mode was not
23856842Sth160488  * initialized or was canceled prior to an invocation of
23866842Sth160488  * __ns_ldap_pingOfflineServers().
23876842Sth160488  */
23886842Sth160488 ns_ldap_return_code
__ns_ldap_pingOfflineServers(void)23896842Sth160488 __ns_ldap_pingOfflineServers(void)
23906842Sth160488 {
23916842Sth160488 	dir_server_list_t	*current_list = NULL;
23926842Sth160488 	ns_ldap_return_code	retCode = NS_LDAP_SUCCESS;
23936842Sth160488 	long			srvListLength, i = 0;
23946842Sth160488 	thread_t		*thrPool, thrID;
23956842Sth160488 	void			*status = NULL;
23966842Sth160488 
23976842Sth160488 	(void) mutex_lock(&dir_servers.listReplaceLock);
23986842Sth160488 	if (dir_servers.list == NULL) {
23996842Sth160488 		(void) mutex_unlock(&dir_servers.listReplaceLock);
24006842Sth160488 		return (NS_LDAP_INTERNAL);
24016842Sth160488 	}
24026842Sth160488 
24036842Sth160488 	current_list = dir_servers.list;
24046842Sth160488 	(void) rw_wrlock(&current_list->listDestroyLock);
24056842Sth160488 	(void) mutex_unlock(&dir_servers.listReplaceLock);
24066842Sth160488 
24076842Sth160488 	while (current_list->nsServers[i] != NULL) {
24086842Sth160488 		++i;
24096842Sth160488 	}
24106842Sth160488 	srvListLength = i;
24116842Sth160488 
24126842Sth160488 	thrPool = calloc(srvListLength, sizeof (thread_t));
24136842Sth160488 	if (thrPool == NULL) {
24146842Sth160488 		(void) rw_unlock(&current_list->listDestroyLock);
24156842Sth160488 		return (NS_LDAP_MEMORY);
24166842Sth160488 	}
24176842Sth160488 
24186842Sth160488 	for (i = 0; i < srvListLength; ++i) {
24196842Sth160488 		if (current_list->nsServers[i]->status != INFO_SERVER_REMOVED &&
24206842Sth160488 		    current_list->nsServers[i]->status != INFO_SERVER_ERROR) {
24216842Sth160488 			continue;
24226842Sth160488 		}
24236842Sth160488 		current_list->nsServers[i]->status = INFO_SERVER_CONNECTING;
24246842Sth160488 		current_list->nsServers[i]->info = INFO_STATUS_NEW;
24256842Sth160488 
24266842Sth160488 		__s_api_free2dArray(current_list->nsServers[i]->controls);
24276842Sth160488 		current_list->nsServers[i]->controls = NULL;
24286842Sth160488 		__s_api_free2dArray(current_list->nsServers[i]->saslMech);
24296842Sth160488 		current_list->nsServers[i]->saslMech = NULL;
24306842Sth160488 
24316842Sth160488 		switch (thr_create(NULL,
24326842Sth160488 		    0,
24336842Sth160488 		    create_ns_servers_entry,
24346842Sth160488 		    current_list->nsServers[i],
24356842Sth160488 		    0,
24366842Sth160488 		    &thrID)) {
24376842Sth160488 		case EAGAIN:
24386842Sth160488 			current_list->nsServers[i]->status = INFO_SERVER_ERROR;
24396842Sth160488 			continue;
24406842Sth160488 			break;
24416842Sth160488 		case ENOMEM:
24426842Sth160488 			current_list->nsServers[i]->status = INFO_SERVER_ERROR;
24436842Sth160488 			retCode = NS_LDAP_MEMORY;
24446842Sth160488 			break;
24456842Sth160488 		default:
24466842Sth160488 			thrPool[i] = thrID;
24476842Sth160488 			continue;
24486842Sth160488 			break;
24496842Sth160488 		}
24506842Sth160488 		/* A memory allocation error has occured */
24516842Sth160488 		break;
24526842Sth160488 
24536842Sth160488 	}
24546842Sth160488 
24556842Sth160488 	for (i = 0; i < srvListLength; ++i) {
24566842Sth160488 		if (thrPool[i] != 0 &&
24576842Sth160488 		    thr_join(thrPool[i], NULL, &status) == 0) {
24586842Sth160488 			if (status == NULL) {
24596842Sth160488 				current_list->nsServers[i]->status =
24606842Sth160488 				    INFO_SERVER_ERROR;
24616842Sth160488 				retCode = NS_LDAP_MEMORY;
24626842Sth160488 			}
24636842Sth160488 			free(status);
24646842Sth160488 		}
24656842Sth160488 	}
24666842Sth160488 
24676842Sth160488 	(void) rw_unlock(&current_list->listDestroyLock);
24686842Sth160488 
24696842Sth160488 	free(thrPool);
24706842Sth160488 
24716842Sth160488 	return (retCode);
24726842Sth160488 }
2473