xref: /onnv-gate/usr/src/lib/nsswitch/ad/common/ad_common.c (revision 8671:d3ec1a19966c)
18040SBaban.Kenkre@Sun.COM /*
28040SBaban.Kenkre@Sun.COM  * CDDL HEADER START
38040SBaban.Kenkre@Sun.COM  *
48040SBaban.Kenkre@Sun.COM  * The contents of this file are subject to the terms of the
58040SBaban.Kenkre@Sun.COM  * Common Development and Distribution License (the "License").
68040SBaban.Kenkre@Sun.COM  * You may not use this file except in compliance with the License.
78040SBaban.Kenkre@Sun.COM  *
88040SBaban.Kenkre@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98040SBaban.Kenkre@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108040SBaban.Kenkre@Sun.COM  * See the License for the specific language governing permissions
118040SBaban.Kenkre@Sun.COM  * and limitations under the License.
128040SBaban.Kenkre@Sun.COM  *
138040SBaban.Kenkre@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148040SBaban.Kenkre@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158040SBaban.Kenkre@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168040SBaban.Kenkre@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178040SBaban.Kenkre@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188040SBaban.Kenkre@Sun.COM  *
198040SBaban.Kenkre@Sun.COM  * CDDL HEADER END
208040SBaban.Kenkre@Sun.COM  */
218040SBaban.Kenkre@Sun.COM /*
22*8671SJulian.Pullen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238040SBaban.Kenkre@Sun.COM  * Use is subject to license terms.
248040SBaban.Kenkre@Sun.COM  */
258040SBaban.Kenkre@Sun.COM 
268040SBaban.Kenkre@Sun.COM #include <malloc.h>
278040SBaban.Kenkre@Sun.COM #include <synch.h>
288040SBaban.Kenkre@Sun.COM #include <syslog.h>
298040SBaban.Kenkre@Sun.COM #include <rpcsvc/ypclnt.h>
308040SBaban.Kenkre@Sun.COM #include <rpcsvc/yp_prot.h>
318040SBaban.Kenkre@Sun.COM #include <pthread.h>
328040SBaban.Kenkre@Sun.COM #include <ctype.h>
338040SBaban.Kenkre@Sun.COM #include <stdlib.h>
348040SBaban.Kenkre@Sun.COM #include <stdio.h>
358040SBaban.Kenkre@Sun.COM #include <signal.h>
368040SBaban.Kenkre@Sun.COM #include <sys/stat.h>
378040SBaban.Kenkre@Sun.COM #include <assert.h>
388040SBaban.Kenkre@Sun.COM #include "ad_common.h"
398040SBaban.Kenkre@Sun.COM 
408040SBaban.Kenkre@Sun.COM static pthread_mutex_t	statelock = PTHREAD_MUTEX_INITIALIZER;
418040SBaban.Kenkre@Sun.COM static nssad_state_t	state = {0};
428040SBaban.Kenkre@Sun.COM 
438040SBaban.Kenkre@Sun.COM static void
nssad_cfg_free_props(nssad_prop_t * props)448040SBaban.Kenkre@Sun.COM nssad_cfg_free_props(nssad_prop_t *props)
458040SBaban.Kenkre@Sun.COM {
468040SBaban.Kenkre@Sun.COM 	if (props->domain_name != NULL) {
478040SBaban.Kenkre@Sun.COM 		free(props->domain_name);
488040SBaban.Kenkre@Sun.COM 		props->domain_name = NULL;
498040SBaban.Kenkre@Sun.COM 	}
508040SBaban.Kenkre@Sun.COM 	if (props->domain_controller != NULL) {
518040SBaban.Kenkre@Sun.COM 		free(props->domain_controller);
528040SBaban.Kenkre@Sun.COM 		props->domain_controller = NULL;
538040SBaban.Kenkre@Sun.COM 	}
548040SBaban.Kenkre@Sun.COM }
558040SBaban.Kenkre@Sun.COM 
568040SBaban.Kenkre@Sun.COM static int
nssad_cfg_discover_props(const char * domain,ad_disc_t ad_ctx,nssad_prop_t * props)578040SBaban.Kenkre@Sun.COM nssad_cfg_discover_props(const char *domain, ad_disc_t ad_ctx,
588040SBaban.Kenkre@Sun.COM 	nssad_prop_t *props)
598040SBaban.Kenkre@Sun.COM {
608040SBaban.Kenkre@Sun.COM 	ad_disc_refresh(ad_ctx);
618040SBaban.Kenkre@Sun.COM 	if (ad_disc_set_DomainName(ad_ctx, domain) != 0)
628040SBaban.Kenkre@Sun.COM 		return (-1);
638040SBaban.Kenkre@Sun.COM 	if (props->domain_controller == NULL)
648040SBaban.Kenkre@Sun.COM 		props->domain_controller =
658361SJulian.Pullen@Sun.COM 		    ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE,
668361SJulian.Pullen@Sun.COM 		    NULL);
678040SBaban.Kenkre@Sun.COM 	return (0);
688040SBaban.Kenkre@Sun.COM }
698040SBaban.Kenkre@Sun.COM 
708040SBaban.Kenkre@Sun.COM static int
nssad_cfg_reload_ad(nssad_prop_t * props,adutils_ad_t ** ad)718040SBaban.Kenkre@Sun.COM nssad_cfg_reload_ad(nssad_prop_t *props, adutils_ad_t **ad)
728040SBaban.Kenkre@Sun.COM {
738040SBaban.Kenkre@Sun.COM 	int		i;
748040SBaban.Kenkre@Sun.COM 	adutils_ad_t	*new;
758040SBaban.Kenkre@Sun.COM 
768040SBaban.Kenkre@Sun.COM 	if (props->domain_controller == NULL ||
778040SBaban.Kenkre@Sun.COM 	    props->domain_controller[0].host[0] == '\0')
788040SBaban.Kenkre@Sun.COM 		return (0);
798040SBaban.Kenkre@Sun.COM 	if (adutils_ad_alloc(&new, props->domain_name,
808040SBaban.Kenkre@Sun.COM 	    ADUTILS_AD_DATA) != ADUTILS_SUCCESS)
818040SBaban.Kenkre@Sun.COM 		return (-1);
828040SBaban.Kenkre@Sun.COM 	for (i = 0; props->domain_controller[i].host[0] != '\0'; i++) {
838040SBaban.Kenkre@Sun.COM 		if (adutils_add_ds(new,
848040SBaban.Kenkre@Sun.COM 		    props->domain_controller[i].host,
858040SBaban.Kenkre@Sun.COM 		    props->domain_controller[i].port) != ADUTILS_SUCCESS) {
868040SBaban.Kenkre@Sun.COM 			adutils_ad_free(&new);
878040SBaban.Kenkre@Sun.COM 			return (-1);
888040SBaban.Kenkre@Sun.COM 		}
898040SBaban.Kenkre@Sun.COM 	}
908040SBaban.Kenkre@Sun.COM 
918040SBaban.Kenkre@Sun.COM 	if (*ad != NULL)
928040SBaban.Kenkre@Sun.COM 		adutils_ad_free(ad);
938040SBaban.Kenkre@Sun.COM 	*ad = new;
948040SBaban.Kenkre@Sun.COM 	return (0);
958040SBaban.Kenkre@Sun.COM }
968040SBaban.Kenkre@Sun.COM 
978040SBaban.Kenkre@Sun.COM static
988040SBaban.Kenkre@Sun.COM int
update_dirs(idmap_ad_disc_ds_t ** value,idmap_ad_disc_ds_t ** new)998040SBaban.Kenkre@Sun.COM update_dirs(idmap_ad_disc_ds_t **value, idmap_ad_disc_ds_t **new)
1008040SBaban.Kenkre@Sun.COM {
1018040SBaban.Kenkre@Sun.COM 	if (*value == *new)
1028040SBaban.Kenkre@Sun.COM 		return (0);
1038040SBaban.Kenkre@Sun.COM 
1048040SBaban.Kenkre@Sun.COM 	if (*value != NULL && *new != NULL &&
1058040SBaban.Kenkre@Sun.COM 	    ad_disc_compare_ds(*value, *new) == 0) {
1068040SBaban.Kenkre@Sun.COM 		free(*new);
1078040SBaban.Kenkre@Sun.COM 		*new = NULL;
1088040SBaban.Kenkre@Sun.COM 		return (0);
1098040SBaban.Kenkre@Sun.COM 	}
1108040SBaban.Kenkre@Sun.COM 
1118040SBaban.Kenkre@Sun.COM 	if (*value)
1128040SBaban.Kenkre@Sun.COM 		free(*value);
1138040SBaban.Kenkre@Sun.COM 	*value = *new;
1148040SBaban.Kenkre@Sun.COM 	*new = NULL;
1158040SBaban.Kenkre@Sun.COM 	return (1);
1168040SBaban.Kenkre@Sun.COM }
1178040SBaban.Kenkre@Sun.COM 
1188040SBaban.Kenkre@Sun.COM static
1198040SBaban.Kenkre@Sun.COM int
nssad_cfg_refresh(nssad_cfg_t * cp)1208040SBaban.Kenkre@Sun.COM nssad_cfg_refresh(nssad_cfg_t *cp)
1218040SBaban.Kenkre@Sun.COM {
1228040SBaban.Kenkre@Sun.COM 	nssad_prop_t	props;
1238040SBaban.Kenkre@Sun.COM 
1248040SBaban.Kenkre@Sun.COM 	(void) ad_disc_SubnetChanged(cp->ad_ctx);
1258040SBaban.Kenkre@Sun.COM 	(void) memset(&props, 0, sizeof (props));
1268040SBaban.Kenkre@Sun.COM 	if (nssad_cfg_discover_props(cp->props.domain_name, cp->ad_ctx,
1278040SBaban.Kenkre@Sun.COM 	    &props) < 0)
1288040SBaban.Kenkre@Sun.COM 		return (-1);
1298040SBaban.Kenkre@Sun.COM 	if (update_dirs(&cp->props.domain_controller,
1308040SBaban.Kenkre@Sun.COM 	    &props.domain_controller)) {
1318040SBaban.Kenkre@Sun.COM 		if (cp->props.domain_controller != NULL &&
1328040SBaban.Kenkre@Sun.COM 		    cp->props.domain_controller[0].host[0] != '\0')
1338040SBaban.Kenkre@Sun.COM 			(void) nssad_cfg_reload_ad(&cp->props, &cp->ad);
1348040SBaban.Kenkre@Sun.COM 	}
1358040SBaban.Kenkre@Sun.COM 	return (0);
1368040SBaban.Kenkre@Sun.COM }
1378040SBaban.Kenkre@Sun.COM 
1388040SBaban.Kenkre@Sun.COM static void
nssad_cfg_destroy(nssad_cfg_t * cp)1398040SBaban.Kenkre@Sun.COM nssad_cfg_destroy(nssad_cfg_t *cp)
1408040SBaban.Kenkre@Sun.COM {
1418040SBaban.Kenkre@Sun.COM 	if (cp != NULL) {
1428040SBaban.Kenkre@Sun.COM 		(void) pthread_rwlock_destroy(&cp->lock);
1438040SBaban.Kenkre@Sun.COM 		ad_disc_fini(cp->ad_ctx);
1448040SBaban.Kenkre@Sun.COM 		nssad_cfg_free_props(&cp->props);
1458040SBaban.Kenkre@Sun.COM 		adutils_ad_free(&cp->ad);
1468040SBaban.Kenkre@Sun.COM 		free(cp);
1478040SBaban.Kenkre@Sun.COM 	}
1488040SBaban.Kenkre@Sun.COM }
1498040SBaban.Kenkre@Sun.COM 
1508040SBaban.Kenkre@Sun.COM static nssad_cfg_t *
nssad_cfg_create(const char * domain)1518040SBaban.Kenkre@Sun.COM nssad_cfg_create(const char *domain)
1528040SBaban.Kenkre@Sun.COM {
1538040SBaban.Kenkre@Sun.COM 	nssad_cfg_t	*cp;
1548040SBaban.Kenkre@Sun.COM 
1558040SBaban.Kenkre@Sun.COM 	if ((cp = calloc(1, sizeof (*cp))) == NULL)
1568040SBaban.Kenkre@Sun.COM 		return (NULL);
1578040SBaban.Kenkre@Sun.COM 	if (pthread_rwlock_init(&cp->lock, NULL) != 0) {
1588040SBaban.Kenkre@Sun.COM 		free(cp);
1598040SBaban.Kenkre@Sun.COM 		return (NULL);
1608040SBaban.Kenkre@Sun.COM 	}
1618040SBaban.Kenkre@Sun.COM 	if ((cp->ad_ctx = ad_disc_init()) == NULL)
1628040SBaban.Kenkre@Sun.COM 		goto errout;
1638040SBaban.Kenkre@Sun.COM 	if ((cp->props.domain_name = strdup(domain)) == NULL)
1648040SBaban.Kenkre@Sun.COM 		goto errout;
1658040SBaban.Kenkre@Sun.COM 	if (nssad_cfg_discover_props(domain, cp->ad_ctx, &cp->props) < 0)
1668040SBaban.Kenkre@Sun.COM 		goto errout;
1678040SBaban.Kenkre@Sun.COM 	if (nssad_cfg_reload_ad(&cp->props, &cp->ad) < 0)
1688040SBaban.Kenkre@Sun.COM 		goto errout;
1698040SBaban.Kenkre@Sun.COM 	return (cp);
1708040SBaban.Kenkre@Sun.COM errout:
1718040SBaban.Kenkre@Sun.COM 	nssad_cfg_destroy(cp);
1728040SBaban.Kenkre@Sun.COM 	return (NULL);
1738040SBaban.Kenkre@Sun.COM }
1748040SBaban.Kenkre@Sun.COM 
1758040SBaban.Kenkre@Sun.COM #define	hex_char(n)	"0123456789abcdef"[n & 0xf]
1768040SBaban.Kenkre@Sun.COM 
1778040SBaban.Kenkre@Sun.COM int
_ldap_filter_name(char * filter_name,const char * name,int filter_name_size)1788040SBaban.Kenkre@Sun.COM _ldap_filter_name(char *filter_name, const char *name, int filter_name_size)
1798040SBaban.Kenkre@Sun.COM {
1808040SBaban.Kenkre@Sun.COM 	char *end = filter_name + filter_name_size;
1818040SBaban.Kenkre@Sun.COM 	char c;
1828040SBaban.Kenkre@Sun.COM 
1838040SBaban.Kenkre@Sun.COM 	for (; *name; name++) {
1848040SBaban.Kenkre@Sun.COM 		c = *name;
1858040SBaban.Kenkre@Sun.COM 		switch (c) {
1868040SBaban.Kenkre@Sun.COM 			case '*':
1878040SBaban.Kenkre@Sun.COM 			case '(':
1888040SBaban.Kenkre@Sun.COM 			case ')':
1898040SBaban.Kenkre@Sun.COM 			case '\\':
1908040SBaban.Kenkre@Sun.COM 				if (end <= filter_name + 3)
1918040SBaban.Kenkre@Sun.COM 					return (-1);
1928040SBaban.Kenkre@Sun.COM 				*filter_name++ = '\\';
1938040SBaban.Kenkre@Sun.COM 				*filter_name++ = hex_char(c >> 4);
1948040SBaban.Kenkre@Sun.COM 				*filter_name++ = hex_char(c & 0xf);
1958040SBaban.Kenkre@Sun.COM 				break;
1968040SBaban.Kenkre@Sun.COM 			default:
1978040SBaban.Kenkre@Sun.COM 				if (end <= filter_name + 1)
1988040SBaban.Kenkre@Sun.COM 					return (-1);
1998040SBaban.Kenkre@Sun.COM 				*filter_name++ = c;
2008040SBaban.Kenkre@Sun.COM 				break;
2018040SBaban.Kenkre@Sun.COM 		}
2028040SBaban.Kenkre@Sun.COM 	}
2038040SBaban.Kenkre@Sun.COM 	if (end <= filter_name)
2048040SBaban.Kenkre@Sun.COM 		return (-1);
2058040SBaban.Kenkre@Sun.COM 	*filter_name = '\0';
2068040SBaban.Kenkre@Sun.COM 	return (0);
2078040SBaban.Kenkre@Sun.COM }
2088040SBaban.Kenkre@Sun.COM 
2098040SBaban.Kenkre@Sun.COM static
2108040SBaban.Kenkre@Sun.COM nss_status_t
map_adrc2nssrc(adutils_rc adrc)2118040SBaban.Kenkre@Sun.COM map_adrc2nssrc(adutils_rc adrc)
2128040SBaban.Kenkre@Sun.COM {
2138040SBaban.Kenkre@Sun.COM 	if (adrc == ADUTILS_SUCCESS)
2148040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_SUCCESS);
2158040SBaban.Kenkre@Sun.COM 	if (adrc == ADUTILS_ERR_NOTFOUND)
2168040SBaban.Kenkre@Sun.COM 		errno = 0;
2178040SBaban.Kenkre@Sun.COM 	return ((nss_status_t)NSS_NOTFOUND);
2188040SBaban.Kenkre@Sun.COM }
2198040SBaban.Kenkre@Sun.COM 
2208040SBaban.Kenkre@Sun.COM /* ARGSUSED */
2218040SBaban.Kenkre@Sun.COM nss_status_t
_nss_ad_marshall_data(ad_backend_ptr be,nss_XbyY_args_t * argp)2228040SBaban.Kenkre@Sun.COM _nss_ad_marshall_data(ad_backend_ptr be, nss_XbyY_args_t *argp)
2238040SBaban.Kenkre@Sun.COM {
2248040SBaban.Kenkre@Sun.COM 	int	stat;
2258040SBaban.Kenkre@Sun.COM 
2268040SBaban.Kenkre@Sun.COM 	if (argp->buf.result == NULL) {
2278040SBaban.Kenkre@Sun.COM 		/*
2288040SBaban.Kenkre@Sun.COM 		 * This suggests that the process (e.g. nscd) expects
2298040SBaban.Kenkre@Sun.COM 		 * nssad to return the data in native file format in
2308040SBaban.Kenkre@Sun.COM 		 * argp->buf.buffer i.e. no need to marshall the data.
2318040SBaban.Kenkre@Sun.COM 		 */
2328040SBaban.Kenkre@Sun.COM 		argp->returnval = argp->buf.buffer;
2338040SBaban.Kenkre@Sun.COM 		argp->returnlen = strlen(argp->buf.buffer);
2348040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_STR_PARSE_SUCCESS);
2358040SBaban.Kenkre@Sun.COM 	}
2368040SBaban.Kenkre@Sun.COM 
2378040SBaban.Kenkre@Sun.COM 	if (argp->str2ent == NULL)
2388040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_STR_PARSE_PARSE);
2398040SBaban.Kenkre@Sun.COM 
2408040SBaban.Kenkre@Sun.COM 	stat = (*argp->str2ent)(be->buffer, be->buflen,
2418040SBaban.Kenkre@Sun.COM 	    argp->buf.result, argp->buf.buffer, argp->buf.buflen);
2428040SBaban.Kenkre@Sun.COM 
2438040SBaban.Kenkre@Sun.COM 	if (stat == NSS_STR_PARSE_SUCCESS) {
2448040SBaban.Kenkre@Sun.COM 		argp->returnval = argp->buf.result;
2458040SBaban.Kenkre@Sun.COM 		argp->returnlen = 1; /* irrelevant */
2468040SBaban.Kenkre@Sun.COM 	}
2478040SBaban.Kenkre@Sun.COM 	return ((nss_status_t)stat);
2488040SBaban.Kenkre@Sun.COM }
2498040SBaban.Kenkre@Sun.COM 
2508040SBaban.Kenkre@Sun.COM nss_status_t
_nss_ad_sanitize_status(ad_backend_ptr be,nss_XbyY_args_t * argp,nss_status_t stat)2518040SBaban.Kenkre@Sun.COM _nss_ad_sanitize_status(ad_backend_ptr be, nss_XbyY_args_t *argp,
2528040SBaban.Kenkre@Sun.COM 		nss_status_t stat)
2538040SBaban.Kenkre@Sun.COM {
2548040SBaban.Kenkre@Sun.COM 	if (be->buffer != NULL) {
2558040SBaban.Kenkre@Sun.COM 		free(be->buffer);
2568040SBaban.Kenkre@Sun.COM 		be->buffer = NULL;
2578040SBaban.Kenkre@Sun.COM 		be->buflen = 0;
2588040SBaban.Kenkre@Sun.COM 		be->db_type = NSS_AD_DB_NONE;
2598040SBaban.Kenkre@Sun.COM 	}
2608040SBaban.Kenkre@Sun.COM 
2618040SBaban.Kenkre@Sun.COM 	if (stat == NSS_STR_PARSE_SUCCESS) {
2628040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_SUCCESS);
2638040SBaban.Kenkre@Sun.COM 	} else if (stat == NSS_STR_PARSE_PARSE) {
2648040SBaban.Kenkre@Sun.COM 		argp->returnval = 0;
2658040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
2668040SBaban.Kenkre@Sun.COM 	} else if (stat == NSS_STR_PARSE_ERANGE) {
2678040SBaban.Kenkre@Sun.COM 		argp->erange = 1;
2688040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
2698040SBaban.Kenkre@Sun.COM 	}
2708040SBaban.Kenkre@Sun.COM 	return ((nss_status_t)NSS_UNAVAIL);
2718040SBaban.Kenkre@Sun.COM }
2728040SBaban.Kenkre@Sun.COM 
2738040SBaban.Kenkre@Sun.COM /* ARGSUSED */
2748040SBaban.Kenkre@Sun.COM static
2758040SBaban.Kenkre@Sun.COM nssad_cfg_t *
get_cfg(const char * domain)2768040SBaban.Kenkre@Sun.COM get_cfg(const char *domain)
2778040SBaban.Kenkre@Sun.COM {
2788040SBaban.Kenkre@Sun.COM 	nssad_cfg_t	*cp, *lru, *prev;
2798040SBaban.Kenkre@Sun.COM 
2808040SBaban.Kenkre@Sun.COM 	/*
2818040SBaban.Kenkre@Sun.COM 	 * Note about the queue:
2828040SBaban.Kenkre@Sun.COM 	 *
2838040SBaban.Kenkre@Sun.COM 	 * The queue is used to hold our per domain
2848040SBaban.Kenkre@Sun.COM 	 * configs. The queue is limited to CFG_QUEUE_MAX_SIZE.
2858040SBaban.Kenkre@Sun.COM 	 * If the queue increases beyond that point we toss
2868040SBaban.Kenkre@Sun.COM 	 * out the LRU entry. The entries are inserted into
2878040SBaban.Kenkre@Sun.COM 	 * the queue at state.qtail and the LRU entry is
2888040SBaban.Kenkre@Sun.COM 	 * removed from state.qhead. state.qnext points
2898040SBaban.Kenkre@Sun.COM 	 * from the qtail to the qhead. Everytime a config
2908040SBaban.Kenkre@Sun.COM 	 * is accessed it is moved to qtail.
2918040SBaban.Kenkre@Sun.COM 	 */
2928040SBaban.Kenkre@Sun.COM 
2938040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&statelock);
2948040SBaban.Kenkre@Sun.COM 
2958040SBaban.Kenkre@Sun.COM 	for (cp = state.qtail, prev = NULL; cp != NULL;
2968040SBaban.Kenkre@Sun.COM 	    prev = cp, cp = cp->qnext) {
2978040SBaban.Kenkre@Sun.COM 		if (cp->props.domain_name == NULL ||
2988040SBaban.Kenkre@Sun.COM 		    strcasecmp(cp->props.domain_name, domain) != 0)
2998040SBaban.Kenkre@Sun.COM 			continue;
3008040SBaban.Kenkre@Sun.COM 
3018040SBaban.Kenkre@Sun.COM 		/* Found config for the given domain. */
3028040SBaban.Kenkre@Sun.COM 
3038040SBaban.Kenkre@Sun.COM 		if (state.qtail != cp) {
3048040SBaban.Kenkre@Sun.COM 			/*
3058040SBaban.Kenkre@Sun.COM 			 * Move the entry to the tail of the queue.
3068040SBaban.Kenkre@Sun.COM 			 * This way the LRU entry can be found at
3078040SBaban.Kenkre@Sun.COM 			 * the head of the queue.
3088040SBaban.Kenkre@Sun.COM 			 */
3098040SBaban.Kenkre@Sun.COM 			prev->qnext = cp->qnext;
3108040SBaban.Kenkre@Sun.COM 			if (state.qhead == cp)
3118040SBaban.Kenkre@Sun.COM 				state.qhead = prev;
3128040SBaban.Kenkre@Sun.COM 			cp->qnext = state.qtail;
3138040SBaban.Kenkre@Sun.COM 			state.qtail = cp;
3148040SBaban.Kenkre@Sun.COM 		}
3158040SBaban.Kenkre@Sun.COM 
3168040SBaban.Kenkre@Sun.COM 		if (ad_disc_get_TTL(cp->ad_ctx) == 0) {
3178040SBaban.Kenkre@Sun.COM 			/*
3188040SBaban.Kenkre@Sun.COM 			 * If there are expired items in the
3198040SBaban.Kenkre@Sun.COM 			 * config, grab the write lock and
3208040SBaban.Kenkre@Sun.COM 			 * refresh the config.
3218040SBaban.Kenkre@Sun.COM 			 */
3228040SBaban.Kenkre@Sun.COM 			(void) pthread_rwlock_wrlock(&cp->lock);
3238040SBaban.Kenkre@Sun.COM 			if (nssad_cfg_refresh(cp) < 0) {
3248040SBaban.Kenkre@Sun.COM 				(void) pthread_rwlock_unlock(&cp->lock);
3258040SBaban.Kenkre@Sun.COM 				(void) pthread_mutex_unlock(&statelock);
3268040SBaban.Kenkre@Sun.COM 				return (NULL);
3278040SBaban.Kenkre@Sun.COM 			}
3288040SBaban.Kenkre@Sun.COM 			(void) pthread_rwlock_unlock(&cp->lock);
3298040SBaban.Kenkre@Sun.COM 		}
3308040SBaban.Kenkre@Sun.COM 
3318040SBaban.Kenkre@Sun.COM 		/* Return the config found */
3328040SBaban.Kenkre@Sun.COM 		(void) pthread_rwlock_rdlock(&cp->lock);
3338040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&statelock);
3348040SBaban.Kenkre@Sun.COM 		return (cp);
3358040SBaban.Kenkre@Sun.COM 	}
3368040SBaban.Kenkre@Sun.COM 
3378040SBaban.Kenkre@Sun.COM 	/* Create new config entry for the domain */
3388040SBaban.Kenkre@Sun.COM 	if ((cp = nssad_cfg_create(domain)) == NULL) {
3398040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&statelock);
3408040SBaban.Kenkre@Sun.COM 		return (NULL);
3418040SBaban.Kenkre@Sun.COM 	}
3428040SBaban.Kenkre@Sun.COM 
3438040SBaban.Kenkre@Sun.COM 	/* Add it to the queue */
3448040SBaban.Kenkre@Sun.COM 	state.qcount++;
3458040SBaban.Kenkre@Sun.COM 	if (state.qtail == NULL) {
3468040SBaban.Kenkre@Sun.COM 		state.qtail = state.qhead = cp;
3478040SBaban.Kenkre@Sun.COM 		(void) pthread_rwlock_rdlock(&cp->lock);
3488040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&statelock);
3498040SBaban.Kenkre@Sun.COM 		return (cp);
3508040SBaban.Kenkre@Sun.COM 	}
3518040SBaban.Kenkre@Sun.COM 	cp->qnext = state.qtail;
3528040SBaban.Kenkre@Sun.COM 	state.qtail = cp;
3538040SBaban.Kenkre@Sun.COM 
3548040SBaban.Kenkre@Sun.COM 	/* If the queue has exceeded its size, remove the LRU entry */
3558040SBaban.Kenkre@Sun.COM 	if (state.qcount >= CFG_QUEUE_MAX_SIZE) {
3568040SBaban.Kenkre@Sun.COM 		/* Detach the lru entry and destroy */
3578040SBaban.Kenkre@Sun.COM 		lru = state.qhead;
3588040SBaban.Kenkre@Sun.COM 		if (pthread_rwlock_trywrlock(&lru->lock) == 0) {
3598040SBaban.Kenkre@Sun.COM 			for (prev = state.qtail; prev != NULL;
3608040SBaban.Kenkre@Sun.COM 			    prev = prev->qnext) {
3618040SBaban.Kenkre@Sun.COM 				if (prev->qnext != lru)
3628040SBaban.Kenkre@Sun.COM 					continue;
3638040SBaban.Kenkre@Sun.COM 				state.qhead = prev;
3648040SBaban.Kenkre@Sun.COM 				prev->qnext = NULL;
3658040SBaban.Kenkre@Sun.COM 				state.qcount--;
3668040SBaban.Kenkre@Sun.COM 				(void) pthread_rwlock_unlock(&lru->lock);
3678040SBaban.Kenkre@Sun.COM 				nssad_cfg_destroy(lru);
3688040SBaban.Kenkre@Sun.COM 				break;
3698040SBaban.Kenkre@Sun.COM 			}
3708040SBaban.Kenkre@Sun.COM 			(void) assert(prev != NULL);
3718040SBaban.Kenkre@Sun.COM 		}
3728040SBaban.Kenkre@Sun.COM 	}
3738040SBaban.Kenkre@Sun.COM 
3748040SBaban.Kenkre@Sun.COM 	(void) pthread_rwlock_rdlock(&cp->lock);
3758040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&statelock);
3768040SBaban.Kenkre@Sun.COM 	return (cp);
3778040SBaban.Kenkre@Sun.COM }
3788040SBaban.Kenkre@Sun.COM 
3798040SBaban.Kenkre@Sun.COM 
3808040SBaban.Kenkre@Sun.COM /* ARGSUSED */
3818040SBaban.Kenkre@Sun.COM static
3828040SBaban.Kenkre@Sun.COM nss_status_t
ad_lookup(const char * filter,const char ** attrs,const char * domain,adutils_result_t ** result)3838040SBaban.Kenkre@Sun.COM ad_lookup(const char *filter, const char **attrs,
3848040SBaban.Kenkre@Sun.COM 	const char *domain, adutils_result_t **result)
3858040SBaban.Kenkre@Sun.COM {
3868040SBaban.Kenkre@Sun.COM 	int			retries = 0;
3878040SBaban.Kenkre@Sun.COM 	adutils_rc		rc, brc;
3888040SBaban.Kenkre@Sun.COM 	adutils_query_state_t	*qs;
3898040SBaban.Kenkre@Sun.COM 	nssad_cfg_t		*cp;
3908040SBaban.Kenkre@Sun.COM 
3918040SBaban.Kenkre@Sun.COM retry:
3928040SBaban.Kenkre@Sun.COM 	if ((cp = get_cfg(domain)) == NULL)
3938040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
3948040SBaban.Kenkre@Sun.COM 
3958040SBaban.Kenkre@Sun.COM 	rc = adutils_lookup_batch_start(cp->ad, 1, NULL, NULL, &qs);
3968040SBaban.Kenkre@Sun.COM 	(void) pthread_rwlock_unlock(&cp->lock);
3978040SBaban.Kenkre@Sun.COM 	if (rc != ADUTILS_SUCCESS)
3988040SBaban.Kenkre@Sun.COM 		goto out;
3998040SBaban.Kenkre@Sun.COM 
4008040SBaban.Kenkre@Sun.COM 	rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc);
4018040SBaban.Kenkre@Sun.COM 	if (rc != ADUTILS_SUCCESS) {
4028040SBaban.Kenkre@Sun.COM 		adutils_lookup_batch_release(&qs);
4038040SBaban.Kenkre@Sun.COM 		goto out;
4048040SBaban.Kenkre@Sun.COM 	}
4058040SBaban.Kenkre@Sun.COM 
4068040SBaban.Kenkre@Sun.COM 	rc = adutils_lookup_batch_end(&qs);
4078040SBaban.Kenkre@Sun.COM 	if (rc != ADUTILS_SUCCESS)
4088040SBaban.Kenkre@Sun.COM 		goto out;
4098040SBaban.Kenkre@Sun.COM 	rc = brc;
4108040SBaban.Kenkre@Sun.COM 
4118040SBaban.Kenkre@Sun.COM out:
4128040SBaban.Kenkre@Sun.COM 	if (rc == ADUTILS_ERR_RETRIABLE_NET_ERR &&
4138040SBaban.Kenkre@Sun.COM 	    retries++ < ADUTILS_DEF_NUM_RETRIES)
4148040SBaban.Kenkre@Sun.COM 		goto retry;
4158040SBaban.Kenkre@Sun.COM 	return (map_adrc2nssrc(rc));
4168040SBaban.Kenkre@Sun.COM }
4178040SBaban.Kenkre@Sun.COM 
4188040SBaban.Kenkre@Sun.COM 
4198040SBaban.Kenkre@Sun.COM /* ARGSUSED */
4208040SBaban.Kenkre@Sun.COM nss_status_t
_nss_ad_lookup(ad_backend_ptr be,nss_XbyY_args_t * argp,const char * database,const char * searchfilter,const char * dname,int * try_idmap)4218040SBaban.Kenkre@Sun.COM _nss_ad_lookup(ad_backend_ptr be, nss_XbyY_args_t *argp,
4228040SBaban.Kenkre@Sun.COM 		const char *database, const char *searchfilter,
4238040SBaban.Kenkre@Sun.COM 		const char *dname, int *try_idmap)
4248040SBaban.Kenkre@Sun.COM {
4258040SBaban.Kenkre@Sun.COM 	nss_status_t	stat;
4268040SBaban.Kenkre@Sun.COM 
4278040SBaban.Kenkre@Sun.COM 	*try_idmap = 0;
4288040SBaban.Kenkre@Sun.COM 
4298040SBaban.Kenkre@Sun.COM 	/* Clear up results if any */
4308040SBaban.Kenkre@Sun.COM 	(void) adutils_freeresult(&be->result);
4318040SBaban.Kenkre@Sun.COM 
4328040SBaban.Kenkre@Sun.COM 	/* Lookup AD */
4338040SBaban.Kenkre@Sun.COM 	stat = ad_lookup(searchfilter, be->attrs, dname, &be->result);
4348040SBaban.Kenkre@Sun.COM 	if (stat != NSS_SUCCESS) {
4358040SBaban.Kenkre@Sun.COM 		argp->returnval = 0;
4368040SBaban.Kenkre@Sun.COM 		*try_idmap = 1;
4378040SBaban.Kenkre@Sun.COM 		return (stat);
4388040SBaban.Kenkre@Sun.COM 	}
4398040SBaban.Kenkre@Sun.COM 
4408040SBaban.Kenkre@Sun.COM 	/* Map AD object(s) to string in native file format */
4418040SBaban.Kenkre@Sun.COM 	stat = be->adobj2str(be, argp);
4428040SBaban.Kenkre@Sun.COM 	if (stat == NSS_STR_PARSE_SUCCESS)
4438040SBaban.Kenkre@Sun.COM 		stat = _nss_ad_marshall_data(be, argp);
4448040SBaban.Kenkre@Sun.COM 	return (_nss_ad_sanitize_status(be, argp, stat));
4458040SBaban.Kenkre@Sun.COM }
4468040SBaban.Kenkre@Sun.COM 
4478040SBaban.Kenkre@Sun.COM static
4488040SBaban.Kenkre@Sun.COM void
clean_state()4498040SBaban.Kenkre@Sun.COM clean_state()
4508040SBaban.Kenkre@Sun.COM {
4518040SBaban.Kenkre@Sun.COM 	nssad_cfg_t	*cp, *curr;
4528040SBaban.Kenkre@Sun.COM 
4538040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&statelock);
4548040SBaban.Kenkre@Sun.COM 	for (cp = state.qtail; cp != NULL; ) {
4558040SBaban.Kenkre@Sun.COM 		curr = cp;
4568040SBaban.Kenkre@Sun.COM 		cp = cp->qnext;
4578040SBaban.Kenkre@Sun.COM 		nssad_cfg_destroy(curr);
4588040SBaban.Kenkre@Sun.COM 	}
4598040SBaban.Kenkre@Sun.COM 	(void) memset(&state, 0, sizeof (state));
4608040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&statelock);
4618040SBaban.Kenkre@Sun.COM }
4628040SBaban.Kenkre@Sun.COM 
4638040SBaban.Kenkre@Sun.COM static
4648040SBaban.Kenkre@Sun.COM void
_clean_ad_backend(ad_backend_ptr be)4658040SBaban.Kenkre@Sun.COM _clean_ad_backend(ad_backend_ptr be)
4668040SBaban.Kenkre@Sun.COM {
4678040SBaban.Kenkre@Sun.COM 	if (be->tablename != NULL)
4688040SBaban.Kenkre@Sun.COM 		free(be->tablename);
4698040SBaban.Kenkre@Sun.COM 	if (be->buffer != NULL) {
4708040SBaban.Kenkre@Sun.COM 		free(be->buffer);
4718040SBaban.Kenkre@Sun.COM 		be->buffer = NULL;
4728040SBaban.Kenkre@Sun.COM 	}
4738040SBaban.Kenkre@Sun.COM 	free(be);
4748040SBaban.Kenkre@Sun.COM }
4758040SBaban.Kenkre@Sun.COM 
4768040SBaban.Kenkre@Sun.COM 
4778040SBaban.Kenkre@Sun.COM /*
4788040SBaban.Kenkre@Sun.COM  * _nss_ad_destr frees allocated memory before exiting this nsswitch shared
4798040SBaban.Kenkre@Sun.COM  * backend library. This function is called before returning control back to
4808040SBaban.Kenkre@Sun.COM  * nsswitch.
4818040SBaban.Kenkre@Sun.COM  */
4828040SBaban.Kenkre@Sun.COM /*ARGSUSED*/
4838040SBaban.Kenkre@Sun.COM nss_status_t
_nss_ad_destr(ad_backend_ptr be,void * a)4848040SBaban.Kenkre@Sun.COM _nss_ad_destr(ad_backend_ptr be, void *a)
4858040SBaban.Kenkre@Sun.COM {
4868040SBaban.Kenkre@Sun.COM 	(void) _clean_ad_backend(be);
4878040SBaban.Kenkre@Sun.COM 	clean_state();
4888040SBaban.Kenkre@Sun.COM 	return ((nss_status_t)NSS_SUCCESS);
4898040SBaban.Kenkre@Sun.COM }
4908040SBaban.Kenkre@Sun.COM 
4918040SBaban.Kenkre@Sun.COM 
4928040SBaban.Kenkre@Sun.COM /*ARGSUSED*/
4938040SBaban.Kenkre@Sun.COM nss_status_t
_nss_ad_setent(ad_backend_ptr be,void * a)4948040SBaban.Kenkre@Sun.COM _nss_ad_setent(ad_backend_ptr be, void *a)
4958040SBaban.Kenkre@Sun.COM {
4968040SBaban.Kenkre@Sun.COM 	return ((nss_status_t)NSS_UNAVAIL);
4978040SBaban.Kenkre@Sun.COM }
4988040SBaban.Kenkre@Sun.COM 
4998040SBaban.Kenkre@Sun.COM 
5008040SBaban.Kenkre@Sun.COM /*ARGSUSED*/
5018040SBaban.Kenkre@Sun.COM nss_status_t
_nss_ad_endent(ad_backend_ptr be,void * a)5028040SBaban.Kenkre@Sun.COM _nss_ad_endent(ad_backend_ptr be, void *a)
5038040SBaban.Kenkre@Sun.COM {
5048040SBaban.Kenkre@Sun.COM 	return ((nss_status_t)NSS_UNAVAIL);
5058040SBaban.Kenkre@Sun.COM }
5068040SBaban.Kenkre@Sun.COM 
5078040SBaban.Kenkre@Sun.COM 
5088040SBaban.Kenkre@Sun.COM /*ARGSUSED*/
5098040SBaban.Kenkre@Sun.COM nss_status_t
_nss_ad_getent(ad_backend_ptr be,void * a)5108040SBaban.Kenkre@Sun.COM _nss_ad_getent(ad_backend_ptr be, void *a)
5118040SBaban.Kenkre@Sun.COM {
5128040SBaban.Kenkre@Sun.COM 	return ((nss_status_t)NSS_UNAVAIL);
5138040SBaban.Kenkre@Sun.COM }
5148040SBaban.Kenkre@Sun.COM 
5158040SBaban.Kenkre@Sun.COM 
5168040SBaban.Kenkre@Sun.COM nss_backend_t *
_nss_ad_constr(ad_backend_op_t ops[],int nops,char * tablename,const char ** attrs,fnf adobj2str)5178040SBaban.Kenkre@Sun.COM _nss_ad_constr(ad_backend_op_t ops[], int nops, char *tablename,
5188040SBaban.Kenkre@Sun.COM 		const char **attrs, fnf adobj2str)
5198040SBaban.Kenkre@Sun.COM {
5208040SBaban.Kenkre@Sun.COM 	ad_backend_ptr	be;
5218040SBaban.Kenkre@Sun.COM 
5228040SBaban.Kenkre@Sun.COM 	if ((be = (ad_backend_ptr) calloc(1, sizeof (*be))) == NULL)
5238040SBaban.Kenkre@Sun.COM 		return (NULL);
5248040SBaban.Kenkre@Sun.COM 	if ((be->tablename = (char *)strdup(tablename)) == NULL) {
5258040SBaban.Kenkre@Sun.COM 		free(be);
5268040SBaban.Kenkre@Sun.COM 		return (NULL);
5278040SBaban.Kenkre@Sun.COM 	}
5288040SBaban.Kenkre@Sun.COM 	be->ops = ops;
5298040SBaban.Kenkre@Sun.COM 	be->nops = (nss_dbop_t)nops;
5308040SBaban.Kenkre@Sun.COM 	be->attrs = attrs;
5318040SBaban.Kenkre@Sun.COM 	be->adobj2str = adobj2str;
5328040SBaban.Kenkre@Sun.COM 	(void) memset(&state, 0, sizeof (state));
5338040SBaban.Kenkre@Sun.COM 	return ((nss_backend_t *)be);
5348040SBaban.Kenkre@Sun.COM }
535