xref: /illumos-gate/usr/src/lib/nsswitch/ad/common/ad_common.c (revision b3700b074e637f8c6991b70754c88a2cfffb246b)
12b4a7802SBaban Kenkre /*
22b4a7802SBaban Kenkre  * CDDL HEADER START
32b4a7802SBaban Kenkre  *
42b4a7802SBaban Kenkre  * The contents of this file are subject to the terms of the
52b4a7802SBaban Kenkre  * Common Development and Distribution License (the "License").
62b4a7802SBaban Kenkre  * You may not use this file except in compliance with the License.
72b4a7802SBaban Kenkre  *
82b4a7802SBaban Kenkre  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92b4a7802SBaban Kenkre  * or http://www.opensolaris.org/os/licensing.
102b4a7802SBaban Kenkre  * See the License for the specific language governing permissions
112b4a7802SBaban Kenkre  * and limitations under the License.
122b4a7802SBaban Kenkre  *
132b4a7802SBaban Kenkre  * When distributing Covered Code, include this CDDL HEADER in each
142b4a7802SBaban Kenkre  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152b4a7802SBaban Kenkre  * If applicable, add the following below this CDDL HEADER, with the
162b4a7802SBaban Kenkre  * fields enclosed by brackets "[]" replaced with your own identifying
172b4a7802SBaban Kenkre  * information: Portions Copyright [yyyy] [name of copyright owner]
182b4a7802SBaban Kenkre  *
192b4a7802SBaban Kenkre  * CDDL HEADER END
202b4a7802SBaban Kenkre  */
212b4a7802SBaban Kenkre /*
227a8a68f5SJulian Pullen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
232b4a7802SBaban Kenkre  * Use is subject to license terms.
24*b3700b07SGordon Ross  *
25*b3700b07SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
262b4a7802SBaban Kenkre  */
272b4a7802SBaban Kenkre 
282b4a7802SBaban Kenkre #include <malloc.h>
292b4a7802SBaban Kenkre #include <synch.h>
302b4a7802SBaban Kenkre #include <syslog.h>
312b4a7802SBaban Kenkre #include <rpcsvc/ypclnt.h>
322b4a7802SBaban Kenkre #include <rpcsvc/yp_prot.h>
332b4a7802SBaban Kenkre #include <pthread.h>
342b4a7802SBaban Kenkre #include <ctype.h>
352b4a7802SBaban Kenkre #include <stdlib.h>
362b4a7802SBaban Kenkre #include <stdio.h>
372b4a7802SBaban Kenkre #include <signal.h>
382b4a7802SBaban Kenkre #include <sys/stat.h>
392b4a7802SBaban Kenkre #include <assert.h>
402b4a7802SBaban Kenkre #include "ad_common.h"
412b4a7802SBaban Kenkre 
422b4a7802SBaban Kenkre static pthread_mutex_t	statelock = PTHREAD_MUTEX_INITIALIZER;
432b4a7802SBaban Kenkre static nssad_state_t	state = {0};
442b4a7802SBaban Kenkre 
452b4a7802SBaban Kenkre static void
nssad_cfg_free_props(nssad_prop_t * props)462b4a7802SBaban Kenkre nssad_cfg_free_props(nssad_prop_t *props)
472b4a7802SBaban Kenkre {
482b4a7802SBaban Kenkre 	if (props->domain_name != NULL) {
492b4a7802SBaban Kenkre 		free(props->domain_name);
502b4a7802SBaban Kenkre 		props->domain_name = NULL;
512b4a7802SBaban Kenkre 	}
522b4a7802SBaban Kenkre 	if (props->domain_controller != NULL) {
532b4a7802SBaban Kenkre 		free(props->domain_controller);
542b4a7802SBaban Kenkre 		props->domain_controller = NULL;
552b4a7802SBaban Kenkre 	}
562b4a7802SBaban Kenkre }
572b4a7802SBaban Kenkre 
582b4a7802SBaban Kenkre static int
nssad_cfg_discover_props(const char * domain,ad_disc_t ad_ctx,nssad_prop_t * props)592b4a7802SBaban Kenkre nssad_cfg_discover_props(const char *domain, ad_disc_t ad_ctx,
602b4a7802SBaban Kenkre 	nssad_prop_t *props)
612b4a7802SBaban Kenkre {
622b4a7802SBaban Kenkre 	ad_disc_refresh(ad_ctx);
632b4a7802SBaban Kenkre 	if (ad_disc_set_DomainName(ad_ctx, domain) != 0)
642b4a7802SBaban Kenkre 		return (-1);
652b4a7802SBaban Kenkre 	if (props->domain_controller == NULL)
662b4a7802SBaban Kenkre 		props->domain_controller =
674d61c878SJulian Pullen 		    ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE,
684d61c878SJulian Pullen 		    NULL);
692b4a7802SBaban Kenkre 	return (0);
702b4a7802SBaban Kenkre }
712b4a7802SBaban Kenkre 
722b4a7802SBaban Kenkre static int
nssad_cfg_reload_ad(nssad_prop_t * props,adutils_ad_t ** ad)732b4a7802SBaban Kenkre nssad_cfg_reload_ad(nssad_prop_t *props, adutils_ad_t **ad)
742b4a7802SBaban Kenkre {
752b4a7802SBaban Kenkre 	int		i;
762b4a7802SBaban Kenkre 	adutils_ad_t	*new;
772b4a7802SBaban Kenkre 
782b4a7802SBaban Kenkre 	if (props->domain_controller == NULL ||
792b4a7802SBaban Kenkre 	    props->domain_controller[0].host[0] == '\0')
802b4a7802SBaban Kenkre 		return (0);
812b4a7802SBaban Kenkre 	if (adutils_ad_alloc(&new, props->domain_name,
822b4a7802SBaban Kenkre 	    ADUTILS_AD_DATA) != ADUTILS_SUCCESS)
832b4a7802SBaban Kenkre 		return (-1);
842b4a7802SBaban Kenkre 	for (i = 0; props->domain_controller[i].host[0] != '\0'; i++) {
852b4a7802SBaban Kenkre 		if (adutils_add_ds(new,
862b4a7802SBaban Kenkre 		    props->domain_controller[i].host,
872b4a7802SBaban Kenkre 		    props->domain_controller[i].port) != ADUTILS_SUCCESS) {
882b4a7802SBaban Kenkre 			adutils_ad_free(&new);
892b4a7802SBaban Kenkre 			return (-1);
902b4a7802SBaban Kenkre 		}
912b4a7802SBaban Kenkre 	}
922b4a7802SBaban Kenkre 
932b4a7802SBaban Kenkre 	if (*ad != NULL)
942b4a7802SBaban Kenkre 		adutils_ad_free(ad);
952b4a7802SBaban Kenkre 	*ad = new;
962b4a7802SBaban Kenkre 	return (0);
972b4a7802SBaban Kenkre }
982b4a7802SBaban Kenkre 
992b4a7802SBaban Kenkre static
1002b4a7802SBaban Kenkre int
update_dirs(ad_disc_ds_t ** value,ad_disc_ds_t ** new)101*b3700b07SGordon Ross update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new)
1022b4a7802SBaban Kenkre {
1032b4a7802SBaban Kenkre 	if (*value == *new)
1042b4a7802SBaban Kenkre 		return (0);
1052b4a7802SBaban Kenkre 
1062b4a7802SBaban Kenkre 	if (*value != NULL && *new != NULL &&
1072b4a7802SBaban Kenkre 	    ad_disc_compare_ds(*value, *new) == 0) {
1082b4a7802SBaban Kenkre 		free(*new);
1092b4a7802SBaban Kenkre 		*new = NULL;
1102b4a7802SBaban Kenkre 		return (0);
1112b4a7802SBaban Kenkre 	}
1122b4a7802SBaban Kenkre 
1132b4a7802SBaban Kenkre 	if (*value)
1142b4a7802SBaban Kenkre 		free(*value);
1152b4a7802SBaban Kenkre 	*value = *new;
1162b4a7802SBaban Kenkre 	*new = NULL;
1172b4a7802SBaban Kenkre 	return (1);
1182b4a7802SBaban Kenkre }
1192b4a7802SBaban Kenkre 
1202b4a7802SBaban Kenkre static
1212b4a7802SBaban Kenkre int
nssad_cfg_refresh(nssad_cfg_t * cp)1222b4a7802SBaban Kenkre nssad_cfg_refresh(nssad_cfg_t *cp)
1232b4a7802SBaban Kenkre {
1242b4a7802SBaban Kenkre 	nssad_prop_t	props;
1252b4a7802SBaban Kenkre 
1262b4a7802SBaban Kenkre 	(void) ad_disc_SubnetChanged(cp->ad_ctx);
1272b4a7802SBaban Kenkre 	(void) memset(&props, 0, sizeof (props));
1282b4a7802SBaban Kenkre 	if (nssad_cfg_discover_props(cp->props.domain_name, cp->ad_ctx,
1292b4a7802SBaban Kenkre 	    &props) < 0)
1302b4a7802SBaban Kenkre 		return (-1);
1312b4a7802SBaban Kenkre 	if (update_dirs(&cp->props.domain_controller,
1322b4a7802SBaban Kenkre 	    &props.domain_controller)) {
1332b4a7802SBaban Kenkre 		if (cp->props.domain_controller != NULL &&
1342b4a7802SBaban Kenkre 		    cp->props.domain_controller[0].host[0] != '\0')
1352b4a7802SBaban Kenkre 			(void) nssad_cfg_reload_ad(&cp->props, &cp->ad);
1362b4a7802SBaban Kenkre 	}
1372b4a7802SBaban Kenkre 	return (0);
1382b4a7802SBaban Kenkre }
1392b4a7802SBaban Kenkre 
1402b4a7802SBaban Kenkre static void
nssad_cfg_destroy(nssad_cfg_t * cp)1412b4a7802SBaban Kenkre nssad_cfg_destroy(nssad_cfg_t *cp)
1422b4a7802SBaban Kenkre {
1432b4a7802SBaban Kenkre 	if (cp != NULL) {
1442b4a7802SBaban Kenkre 		(void) pthread_rwlock_destroy(&cp->lock);
1452b4a7802SBaban Kenkre 		ad_disc_fini(cp->ad_ctx);
1462b4a7802SBaban Kenkre 		nssad_cfg_free_props(&cp->props);
1472b4a7802SBaban Kenkre 		adutils_ad_free(&cp->ad);
1482b4a7802SBaban Kenkre 		free(cp);
1492b4a7802SBaban Kenkre 	}
1502b4a7802SBaban Kenkre }
1512b4a7802SBaban Kenkre 
1522b4a7802SBaban Kenkre static nssad_cfg_t *
nssad_cfg_create(const char * domain)1532b4a7802SBaban Kenkre nssad_cfg_create(const char *domain)
1542b4a7802SBaban Kenkre {
1552b4a7802SBaban Kenkre 	nssad_cfg_t	*cp;
1562b4a7802SBaban Kenkre 
1572b4a7802SBaban Kenkre 	if ((cp = calloc(1, sizeof (*cp))) == NULL)
1582b4a7802SBaban Kenkre 		return (NULL);
1592b4a7802SBaban Kenkre 	if (pthread_rwlock_init(&cp->lock, NULL) != 0) {
1602b4a7802SBaban Kenkre 		free(cp);
1612b4a7802SBaban Kenkre 		return (NULL);
1622b4a7802SBaban Kenkre 	}
1632b4a7802SBaban Kenkre 	if ((cp->ad_ctx = ad_disc_init()) == NULL)
1642b4a7802SBaban Kenkre 		goto errout;
1652b4a7802SBaban Kenkre 	if ((cp->props.domain_name = strdup(domain)) == NULL)
1662b4a7802SBaban Kenkre 		goto errout;
1672b4a7802SBaban Kenkre 	if (nssad_cfg_discover_props(domain, cp->ad_ctx, &cp->props) < 0)
1682b4a7802SBaban Kenkre 		goto errout;
1692b4a7802SBaban Kenkre 	if (nssad_cfg_reload_ad(&cp->props, &cp->ad) < 0)
1702b4a7802SBaban Kenkre 		goto errout;
1712b4a7802SBaban Kenkre 	return (cp);
1722b4a7802SBaban Kenkre errout:
1732b4a7802SBaban Kenkre 	nssad_cfg_destroy(cp);
1742b4a7802SBaban Kenkre 	return (NULL);
1752b4a7802SBaban Kenkre }
1762b4a7802SBaban Kenkre 
1772b4a7802SBaban Kenkre #define	hex_char(n)	"0123456789abcdef"[n & 0xf]
1782b4a7802SBaban Kenkre 
1792b4a7802SBaban Kenkre int
_ldap_filter_name(char * filter_name,const char * name,int filter_name_size)1802b4a7802SBaban Kenkre _ldap_filter_name(char *filter_name, const char *name, int filter_name_size)
1812b4a7802SBaban Kenkre {
1822b4a7802SBaban Kenkre 	char *end = filter_name + filter_name_size;
1832b4a7802SBaban Kenkre 	char c;
1842b4a7802SBaban Kenkre 
1852b4a7802SBaban Kenkre 	for (; *name; name++) {
1862b4a7802SBaban Kenkre 		c = *name;
1872b4a7802SBaban Kenkre 		switch (c) {
1882b4a7802SBaban Kenkre 			case '*':
1892b4a7802SBaban Kenkre 			case '(':
1902b4a7802SBaban Kenkre 			case ')':
1912b4a7802SBaban Kenkre 			case '\\':
1922b4a7802SBaban Kenkre 				if (end <= filter_name + 3)
1932b4a7802SBaban Kenkre 					return (-1);
1942b4a7802SBaban Kenkre 				*filter_name++ = '\\';
1952b4a7802SBaban Kenkre 				*filter_name++ = hex_char(c >> 4);
1962b4a7802SBaban Kenkre 				*filter_name++ = hex_char(c & 0xf);
1972b4a7802SBaban Kenkre 				break;
1982b4a7802SBaban Kenkre 			default:
1992b4a7802SBaban Kenkre 				if (end <= filter_name + 1)
2002b4a7802SBaban Kenkre 					return (-1);
2012b4a7802SBaban Kenkre 				*filter_name++ = c;
2022b4a7802SBaban Kenkre 				break;
2032b4a7802SBaban Kenkre 		}
2042b4a7802SBaban Kenkre 	}
2052b4a7802SBaban Kenkre 	if (end <= filter_name)
2062b4a7802SBaban Kenkre 		return (-1);
2072b4a7802SBaban Kenkre 	*filter_name = '\0';
2082b4a7802SBaban Kenkre 	return (0);
2092b4a7802SBaban Kenkre }
2102b4a7802SBaban Kenkre 
2112b4a7802SBaban Kenkre static
2122b4a7802SBaban Kenkre nss_status_t
map_adrc2nssrc(adutils_rc adrc)2132b4a7802SBaban Kenkre map_adrc2nssrc(adutils_rc adrc)
2142b4a7802SBaban Kenkre {
2152b4a7802SBaban Kenkre 	if (adrc == ADUTILS_SUCCESS)
2162b4a7802SBaban Kenkre 		return ((nss_status_t)NSS_SUCCESS);
2172b4a7802SBaban Kenkre 	if (adrc == ADUTILS_ERR_NOTFOUND)
2182b4a7802SBaban Kenkre 		errno = 0;
2192b4a7802SBaban Kenkre 	return ((nss_status_t)NSS_NOTFOUND);
2202b4a7802SBaban Kenkre }
2212b4a7802SBaban Kenkre 
2222b4a7802SBaban Kenkre /* ARGSUSED */
2232b4a7802SBaban Kenkre nss_status_t
_nss_ad_marshall_data(ad_backend_ptr be,nss_XbyY_args_t * argp)2242b4a7802SBaban Kenkre _nss_ad_marshall_data(ad_backend_ptr be, nss_XbyY_args_t *argp)
2252b4a7802SBaban Kenkre {
2262b4a7802SBaban Kenkre 	int	stat;
2272b4a7802SBaban Kenkre 
2282b4a7802SBaban Kenkre 	if (argp->buf.result == NULL) {
2292b4a7802SBaban Kenkre 		/*
2302b4a7802SBaban Kenkre 		 * This suggests that the process (e.g. nscd) expects
2312b4a7802SBaban Kenkre 		 * nssad to return the data in native file format in
2322b4a7802SBaban Kenkre 		 * argp->buf.buffer i.e. no need to marshall the data.
2332b4a7802SBaban Kenkre 		 */
2342b4a7802SBaban Kenkre 		argp->returnval = argp->buf.buffer;
2352b4a7802SBaban Kenkre 		argp->returnlen = strlen(argp->buf.buffer);
2362b4a7802SBaban Kenkre 		return ((nss_status_t)NSS_STR_PARSE_SUCCESS);
2372b4a7802SBaban Kenkre 	}
2382b4a7802SBaban Kenkre 
2392b4a7802SBaban Kenkre 	if (argp->str2ent == NULL)
2402b4a7802SBaban Kenkre 		return ((nss_status_t)NSS_STR_PARSE_PARSE);
2412b4a7802SBaban Kenkre 
2422b4a7802SBaban Kenkre 	stat = (*argp->str2ent)(be->buffer, be->buflen,
2432b4a7802SBaban Kenkre 	    argp->buf.result, argp->buf.buffer, argp->buf.buflen);
2442b4a7802SBaban Kenkre 
2452b4a7802SBaban Kenkre 	if (stat == NSS_STR_PARSE_SUCCESS) {
2462b4a7802SBaban Kenkre 		argp->returnval = argp->buf.result;
2472b4a7802SBaban Kenkre 		argp->returnlen = 1; /* irrelevant */
2482b4a7802SBaban Kenkre 	}
2492b4a7802SBaban Kenkre 	return ((nss_status_t)stat);
2502b4a7802SBaban Kenkre }
2512b4a7802SBaban Kenkre 
2522b4a7802SBaban Kenkre nss_status_t
_nss_ad_sanitize_status(ad_backend_ptr be,nss_XbyY_args_t * argp,nss_status_t stat)2532b4a7802SBaban Kenkre _nss_ad_sanitize_status(ad_backend_ptr be, nss_XbyY_args_t *argp,
2542b4a7802SBaban Kenkre 		nss_status_t stat)
2552b4a7802SBaban Kenkre {
2562b4a7802SBaban Kenkre 	if (be->buffer != NULL) {
2572b4a7802SBaban Kenkre 		free(be->buffer);
2582b4a7802SBaban Kenkre 		be->buffer = NULL;
2592b4a7802SBaban Kenkre 		be->buflen = 0;
2602b4a7802SBaban Kenkre 		be->db_type = NSS_AD_DB_NONE;
2612b4a7802SBaban Kenkre 	}
2622b4a7802SBaban Kenkre 
2632b4a7802SBaban Kenkre 	if (stat == NSS_STR_PARSE_SUCCESS) {
2642b4a7802SBaban Kenkre 		return ((nss_status_t)NSS_SUCCESS);
2652b4a7802SBaban Kenkre 	} else if (stat == NSS_STR_PARSE_PARSE) {
2662b4a7802SBaban Kenkre 		argp->returnval = 0;
2672b4a7802SBaban Kenkre 		return ((nss_status_t)NSS_NOTFOUND);
2682b4a7802SBaban Kenkre 	} else if (stat == NSS_STR_PARSE_ERANGE) {
2692b4a7802SBaban Kenkre 		argp->erange = 1;
2702b4a7802SBaban Kenkre 		return ((nss_status_t)NSS_NOTFOUND);
2712b4a7802SBaban Kenkre 	}
2722b4a7802SBaban Kenkre 	return ((nss_status_t)NSS_UNAVAIL);
2732b4a7802SBaban Kenkre }
2742b4a7802SBaban Kenkre 
2752b4a7802SBaban Kenkre /* ARGSUSED */
2762b4a7802SBaban Kenkre static
2772b4a7802SBaban Kenkre nssad_cfg_t *
get_cfg(const char * domain)2782b4a7802SBaban Kenkre get_cfg(const char *domain)
2792b4a7802SBaban Kenkre {
2802b4a7802SBaban Kenkre 	nssad_cfg_t	*cp, *lru, *prev;
2812b4a7802SBaban Kenkre 
2822b4a7802SBaban Kenkre 	/*
2832b4a7802SBaban Kenkre 	 * Note about the queue:
2842b4a7802SBaban Kenkre 	 *
2852b4a7802SBaban Kenkre 	 * The queue is used to hold our per domain
2862b4a7802SBaban Kenkre 	 * configs. The queue is limited to CFG_QUEUE_MAX_SIZE.
2872b4a7802SBaban Kenkre 	 * If the queue increases beyond that point we toss
2882b4a7802SBaban Kenkre 	 * out the LRU entry. The entries are inserted into
2892b4a7802SBaban Kenkre 	 * the queue at state.qtail and the LRU entry is
2902b4a7802SBaban Kenkre 	 * removed from state.qhead. state.qnext points
2912b4a7802SBaban Kenkre 	 * from the qtail to the qhead. Everytime a config
2922b4a7802SBaban Kenkre 	 * is accessed it is moved to qtail.
2932b4a7802SBaban Kenkre 	 */
2942b4a7802SBaban Kenkre 
2952b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&statelock);
2962b4a7802SBaban Kenkre 
2972b4a7802SBaban Kenkre 	for (cp = state.qtail, prev = NULL; cp != NULL;
2982b4a7802SBaban Kenkre 	    prev = cp, cp = cp->qnext) {
2992b4a7802SBaban Kenkre 		if (cp->props.domain_name == NULL ||
3002b4a7802SBaban Kenkre 		    strcasecmp(cp->props.domain_name, domain) != 0)
3012b4a7802SBaban Kenkre 			continue;
3022b4a7802SBaban Kenkre 
3032b4a7802SBaban Kenkre 		/* Found config for the given domain. */
3042b4a7802SBaban Kenkre 
3052b4a7802SBaban Kenkre 		if (state.qtail != cp) {
3062b4a7802SBaban Kenkre 			/*
3072b4a7802SBaban Kenkre 			 * Move the entry to the tail of the queue.
3082b4a7802SBaban Kenkre 			 * This way the LRU entry can be found at
3092b4a7802SBaban Kenkre 			 * the head of the queue.
3102b4a7802SBaban Kenkre 			 */
3112b4a7802SBaban Kenkre 			prev->qnext = cp->qnext;
3122b4a7802SBaban Kenkre 			if (state.qhead == cp)
3132b4a7802SBaban Kenkre 				state.qhead = prev;
3142b4a7802SBaban Kenkre 			cp->qnext = state.qtail;
3152b4a7802SBaban Kenkre 			state.qtail = cp;
3162b4a7802SBaban Kenkre 		}
3172b4a7802SBaban Kenkre 
3182b4a7802SBaban Kenkre 		if (ad_disc_get_TTL(cp->ad_ctx) == 0) {
3192b4a7802SBaban Kenkre 			/*
3202b4a7802SBaban Kenkre 			 * If there are expired items in the
3212b4a7802SBaban Kenkre 			 * config, grab the write lock and
3222b4a7802SBaban Kenkre 			 * refresh the config.
3232b4a7802SBaban Kenkre 			 */
3242b4a7802SBaban Kenkre 			(void) pthread_rwlock_wrlock(&cp->lock);
3252b4a7802SBaban Kenkre 			if (nssad_cfg_refresh(cp) < 0) {
3262b4a7802SBaban Kenkre 				(void) pthread_rwlock_unlock(&cp->lock);
3272b4a7802SBaban Kenkre 				(void) pthread_mutex_unlock(&statelock);
3282b4a7802SBaban Kenkre 				return (NULL);
3292b4a7802SBaban Kenkre 			}
3302b4a7802SBaban Kenkre 			(void) pthread_rwlock_unlock(&cp->lock);
3312b4a7802SBaban Kenkre 		}
3322b4a7802SBaban Kenkre 
3332b4a7802SBaban Kenkre 		/* Return the config found */
3342b4a7802SBaban Kenkre 		(void) pthread_rwlock_rdlock(&cp->lock);
3352b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&statelock);
3362b4a7802SBaban Kenkre 		return (cp);
3372b4a7802SBaban Kenkre 	}
3382b4a7802SBaban Kenkre 
3392b4a7802SBaban Kenkre 	/* Create new config entry for the domain */
3402b4a7802SBaban Kenkre 	if ((cp = nssad_cfg_create(domain)) == NULL) {
3412b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&statelock);
3422b4a7802SBaban Kenkre 		return (NULL);
3432b4a7802SBaban Kenkre 	}
3442b4a7802SBaban Kenkre 
3452b4a7802SBaban Kenkre 	/* Add it to the queue */
3462b4a7802SBaban Kenkre 	state.qcount++;
3472b4a7802SBaban Kenkre 	if (state.qtail == NULL) {
3482b4a7802SBaban Kenkre 		state.qtail = state.qhead = cp;
3492b4a7802SBaban Kenkre 		(void) pthread_rwlock_rdlock(&cp->lock);
3502b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&statelock);
3512b4a7802SBaban Kenkre 		return (cp);
3522b4a7802SBaban Kenkre 	}
3532b4a7802SBaban Kenkre 	cp->qnext = state.qtail;
3542b4a7802SBaban Kenkre 	state.qtail = cp;
3552b4a7802SBaban Kenkre 
3562b4a7802SBaban Kenkre 	/* If the queue has exceeded its size, remove the LRU entry */
3572b4a7802SBaban Kenkre 	if (state.qcount >= CFG_QUEUE_MAX_SIZE) {
3582b4a7802SBaban Kenkre 		/* Detach the lru entry and destroy */
3592b4a7802SBaban Kenkre 		lru = state.qhead;
3602b4a7802SBaban Kenkre 		if (pthread_rwlock_trywrlock(&lru->lock) == 0) {
3612b4a7802SBaban Kenkre 			for (prev = state.qtail; prev != NULL;
3622b4a7802SBaban Kenkre 			    prev = prev->qnext) {
3632b4a7802SBaban Kenkre 				if (prev->qnext != lru)
3642b4a7802SBaban Kenkre 					continue;
3652b4a7802SBaban Kenkre 				state.qhead = prev;
3662b4a7802SBaban Kenkre 				prev->qnext = NULL;
3672b4a7802SBaban Kenkre 				state.qcount--;
3682b4a7802SBaban Kenkre 				(void) pthread_rwlock_unlock(&lru->lock);
3692b4a7802SBaban Kenkre 				nssad_cfg_destroy(lru);
3702b4a7802SBaban Kenkre 				break;
3712b4a7802SBaban Kenkre 			}
3722b4a7802SBaban Kenkre 			(void) assert(prev != NULL);
3732b4a7802SBaban Kenkre 		}
3742b4a7802SBaban Kenkre 	}
3752b4a7802SBaban Kenkre 
3762b4a7802SBaban Kenkre 	(void) pthread_rwlock_rdlock(&cp->lock);
3772b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&statelock);
3782b4a7802SBaban Kenkre 	return (cp);
3792b4a7802SBaban Kenkre }
3802b4a7802SBaban Kenkre 
3812b4a7802SBaban Kenkre 
3822b4a7802SBaban Kenkre /* ARGSUSED */
3832b4a7802SBaban Kenkre static
3842b4a7802SBaban Kenkre nss_status_t
ad_lookup(const char * filter,const char ** attrs,const char * domain,adutils_result_t ** result)3852b4a7802SBaban Kenkre ad_lookup(const char *filter, const char **attrs,
3862b4a7802SBaban Kenkre 	const char *domain, adutils_result_t **result)
3872b4a7802SBaban Kenkre {
3882b4a7802SBaban Kenkre 	int			retries = 0;
3892b4a7802SBaban Kenkre 	adutils_rc		rc, brc;
3902b4a7802SBaban Kenkre 	adutils_query_state_t	*qs;
3912b4a7802SBaban Kenkre 	nssad_cfg_t		*cp;
3922b4a7802SBaban Kenkre 
3932b4a7802SBaban Kenkre retry:
3942b4a7802SBaban Kenkre 	if ((cp = get_cfg(domain)) == NULL)
3952b4a7802SBaban Kenkre 		return ((nss_status_t)NSS_NOTFOUND);
3962b4a7802SBaban Kenkre 
3972b4a7802SBaban Kenkre 	rc = adutils_lookup_batch_start(cp->ad, 1, NULL, NULL, &qs);
3982b4a7802SBaban Kenkre 	(void) pthread_rwlock_unlock(&cp->lock);
3992b4a7802SBaban Kenkre 	if (rc != ADUTILS_SUCCESS)
4002b4a7802SBaban Kenkre 		goto out;
4012b4a7802SBaban Kenkre 
4022b4a7802SBaban Kenkre 	rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc);
4032b4a7802SBaban Kenkre 	if (rc != ADUTILS_SUCCESS) {
4042b4a7802SBaban Kenkre 		adutils_lookup_batch_release(&qs);
4052b4a7802SBaban Kenkre 		goto out;
4062b4a7802SBaban Kenkre 	}
4072b4a7802SBaban Kenkre 
4082b4a7802SBaban Kenkre 	rc = adutils_lookup_batch_end(&qs);
4092b4a7802SBaban Kenkre 	if (rc != ADUTILS_SUCCESS)
4102b4a7802SBaban Kenkre 		goto out;
4112b4a7802SBaban Kenkre 	rc = brc;
4122b4a7802SBaban Kenkre 
4132b4a7802SBaban Kenkre out:
4142b4a7802SBaban Kenkre 	if (rc == ADUTILS_ERR_RETRIABLE_NET_ERR &&
4152b4a7802SBaban Kenkre 	    retries++ < ADUTILS_DEF_NUM_RETRIES)
4162b4a7802SBaban Kenkre 		goto retry;
4172b4a7802SBaban Kenkre 	return (map_adrc2nssrc(rc));
4182b4a7802SBaban Kenkre }
4192b4a7802SBaban Kenkre 
4202b4a7802SBaban Kenkre 
4212b4a7802SBaban Kenkre /* ARGSUSED */
4222b4a7802SBaban Kenkre 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)4232b4a7802SBaban Kenkre _nss_ad_lookup(ad_backend_ptr be, nss_XbyY_args_t *argp,
4242b4a7802SBaban Kenkre 		const char *database, const char *searchfilter,
4252b4a7802SBaban Kenkre 		const char *dname, int *try_idmap)
4262b4a7802SBaban Kenkre {
4272b4a7802SBaban Kenkre 	nss_status_t	stat;
4282b4a7802SBaban Kenkre 
4292b4a7802SBaban Kenkre 	*try_idmap = 0;
4302b4a7802SBaban Kenkre 
4312b4a7802SBaban Kenkre 	/* Clear up results if any */
4322b4a7802SBaban Kenkre 	(void) adutils_freeresult(&be->result);
4332b4a7802SBaban Kenkre 
4342b4a7802SBaban Kenkre 	/* Lookup AD */
4352b4a7802SBaban Kenkre 	stat = ad_lookup(searchfilter, be->attrs, dname, &be->result);
4362b4a7802SBaban Kenkre 	if (stat != NSS_SUCCESS) {
4372b4a7802SBaban Kenkre 		argp->returnval = 0;
4382b4a7802SBaban Kenkre 		*try_idmap = 1;
4392b4a7802SBaban Kenkre 		return (stat);
4402b4a7802SBaban Kenkre 	}
4412b4a7802SBaban Kenkre 
4422b4a7802SBaban Kenkre 	/* Map AD object(s) to string in native file format */
4432b4a7802SBaban Kenkre 	stat = be->adobj2str(be, argp);
4442b4a7802SBaban Kenkre 	if (stat == NSS_STR_PARSE_SUCCESS)
4452b4a7802SBaban Kenkre 		stat = _nss_ad_marshall_data(be, argp);
4462b4a7802SBaban Kenkre 	return (_nss_ad_sanitize_status(be, argp, stat));
4472b4a7802SBaban Kenkre }
4482b4a7802SBaban Kenkre 
4492b4a7802SBaban Kenkre static
4502b4a7802SBaban Kenkre void
clean_state()4512b4a7802SBaban Kenkre clean_state()
4522b4a7802SBaban Kenkre {
4532b4a7802SBaban Kenkre 	nssad_cfg_t	*cp, *curr;
4542b4a7802SBaban Kenkre 
4552b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&statelock);
4562b4a7802SBaban Kenkre 	for (cp = state.qtail; cp != NULL; ) {
4572b4a7802SBaban Kenkre 		curr = cp;
4582b4a7802SBaban Kenkre 		cp = cp->qnext;
4592b4a7802SBaban Kenkre 		nssad_cfg_destroy(curr);
4602b4a7802SBaban Kenkre 	}
4612b4a7802SBaban Kenkre 	(void) memset(&state, 0, sizeof (state));
4622b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&statelock);
4632b4a7802SBaban Kenkre }
4642b4a7802SBaban Kenkre 
4652b4a7802SBaban Kenkre static
4662b4a7802SBaban Kenkre void
_clean_ad_backend(ad_backend_ptr be)4672b4a7802SBaban Kenkre _clean_ad_backend(ad_backend_ptr be)
4682b4a7802SBaban Kenkre {
4692b4a7802SBaban Kenkre 	if (be->tablename != NULL)
4702b4a7802SBaban Kenkre 		free(be->tablename);
4712b4a7802SBaban Kenkre 	if (be->buffer != NULL) {
4722b4a7802SBaban Kenkre 		free(be->buffer);
4732b4a7802SBaban Kenkre 		be->buffer = NULL;
4742b4a7802SBaban Kenkre 	}
4752b4a7802SBaban Kenkre 	free(be);
4762b4a7802SBaban Kenkre }
4772b4a7802SBaban Kenkre 
4782b4a7802SBaban Kenkre 
4792b4a7802SBaban Kenkre /*
4802b4a7802SBaban Kenkre  * _nss_ad_destr frees allocated memory before exiting this nsswitch shared
4812b4a7802SBaban Kenkre  * backend library. This function is called before returning control back to
4822b4a7802SBaban Kenkre  * nsswitch.
4832b4a7802SBaban Kenkre  */
4842b4a7802SBaban Kenkre /*ARGSUSED*/
4852b4a7802SBaban Kenkre nss_status_t
_nss_ad_destr(ad_backend_ptr be,void * a)4862b4a7802SBaban Kenkre _nss_ad_destr(ad_backend_ptr be, void *a)
4872b4a7802SBaban Kenkre {
4882b4a7802SBaban Kenkre 	(void) _clean_ad_backend(be);
4892b4a7802SBaban Kenkre 	clean_state();
4902b4a7802SBaban Kenkre 	return ((nss_status_t)NSS_SUCCESS);
4912b4a7802SBaban Kenkre }
4922b4a7802SBaban Kenkre 
4932b4a7802SBaban Kenkre 
4942b4a7802SBaban Kenkre /*ARGSUSED*/
4952b4a7802SBaban Kenkre nss_status_t
_nss_ad_setent(ad_backend_ptr be,void * a)4962b4a7802SBaban Kenkre _nss_ad_setent(ad_backend_ptr be, void *a)
4972b4a7802SBaban Kenkre {
4982b4a7802SBaban Kenkre 	return ((nss_status_t)NSS_UNAVAIL);
4992b4a7802SBaban Kenkre }
5002b4a7802SBaban Kenkre 
5012b4a7802SBaban Kenkre 
5022b4a7802SBaban Kenkre /*ARGSUSED*/
5032b4a7802SBaban Kenkre nss_status_t
_nss_ad_endent(ad_backend_ptr be,void * a)5042b4a7802SBaban Kenkre _nss_ad_endent(ad_backend_ptr be, void *a)
5052b4a7802SBaban Kenkre {
5062b4a7802SBaban Kenkre 	return ((nss_status_t)NSS_UNAVAIL);
5072b4a7802SBaban Kenkre }
5082b4a7802SBaban Kenkre 
5092b4a7802SBaban Kenkre 
5102b4a7802SBaban Kenkre /*ARGSUSED*/
5112b4a7802SBaban Kenkre nss_status_t
_nss_ad_getent(ad_backend_ptr be,void * a)5122b4a7802SBaban Kenkre _nss_ad_getent(ad_backend_ptr be, void *a)
5132b4a7802SBaban Kenkre {
5142b4a7802SBaban Kenkre 	return ((nss_status_t)NSS_UNAVAIL);
5152b4a7802SBaban Kenkre }
5162b4a7802SBaban Kenkre 
5172b4a7802SBaban Kenkre 
5182b4a7802SBaban Kenkre nss_backend_t *
_nss_ad_constr(ad_backend_op_t ops[],int nops,char * tablename,const char ** attrs,fnf adobj2str)5192b4a7802SBaban Kenkre _nss_ad_constr(ad_backend_op_t ops[], int nops, char *tablename,
5202b4a7802SBaban Kenkre 		const char **attrs, fnf adobj2str)
5212b4a7802SBaban Kenkre {
5222b4a7802SBaban Kenkre 	ad_backend_ptr	be;
5232b4a7802SBaban Kenkre 
5242b4a7802SBaban Kenkre 	if ((be = (ad_backend_ptr) calloc(1, sizeof (*be))) == NULL)
5252b4a7802SBaban Kenkre 		return (NULL);
5262b4a7802SBaban Kenkre 	if ((be->tablename = (char *)strdup(tablename)) == NULL) {
5272b4a7802SBaban Kenkre 		free(be);
5282b4a7802SBaban Kenkre 		return (NULL);
5292b4a7802SBaban Kenkre 	}
5302b4a7802SBaban Kenkre 	be->ops = ops;
5312b4a7802SBaban Kenkre 	be->nops = (nss_dbop_t)nops;
5322b4a7802SBaban Kenkre 	be->attrs = attrs;
5332b4a7802SBaban Kenkre 	be->adobj2str = adobj2str;
5342b4a7802SBaban Kenkre 	(void) memset(&state, 0, sizeof (state));
5352b4a7802SBaban Kenkre 	return ((nss_backend_t *)be);
5362b4a7802SBaban Kenkre }
537