xref: /titanic_50/usr/src/cmd/idmap/idmapd/adutils.c (revision 4d61c878ad5fbf36c5338bef5994cc5fe88a589a)
1c5c4113dSnw141292 /*
2c5c4113dSnw141292  * CDDL HEADER START
3c5c4113dSnw141292  *
4c5c4113dSnw141292  * The contents of this file are subject to the terms of the
5c5c4113dSnw141292  * Common Development and Distribution License (the "License").
6c5c4113dSnw141292  * You may not use this file except in compliance with the License.
7c5c4113dSnw141292  *
8c5c4113dSnw141292  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c5c4113dSnw141292  * or http://www.opensolaris.org/os/licensing.
10c5c4113dSnw141292  * See the License for the specific language governing permissions
11c5c4113dSnw141292  * and limitations under the License.
12c5c4113dSnw141292  *
13c5c4113dSnw141292  * When distributing Covered Code, include this CDDL HEADER in each
14c5c4113dSnw141292  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c5c4113dSnw141292  * If applicable, add the following below this CDDL HEADER, with the
16c5c4113dSnw141292  * fields enclosed by brackets "[]" replaced with your own identifying
17c5c4113dSnw141292  * information: Portions Copyright [yyyy] [name of copyright owner]
18c5c4113dSnw141292  *
19c5c4113dSnw141292  * CDDL HEADER END
20c5c4113dSnw141292  */
21c5c4113dSnw141292 
22c5c4113dSnw141292 /*
234edd44c5Sjp151216  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24c5c4113dSnw141292  * Use is subject to license terms.
25c5c4113dSnw141292  */
26c5c4113dSnw141292 
27c5c4113dSnw141292 /*
28c5c4113dSnw141292  * Processes name2sid & sid2name batched lookups for a given user or
29c5c4113dSnw141292  * computer from an AD Directory server using GSSAPI authentication
30c5c4113dSnw141292  */
31c5c4113dSnw141292 
32c5c4113dSnw141292 #include <stdio.h>
33c5c4113dSnw141292 #include <stdlib.h>
34c5c4113dSnw141292 #include <alloca.h>
35c5c4113dSnw141292 #include <string.h>
36c5c4113dSnw141292 #include <strings.h>
37c5c4113dSnw141292 #include <lber.h>
38c5c4113dSnw141292 #include <ldap.h>
39c5c4113dSnw141292 #include <sasl/sasl.h>
40c5c4113dSnw141292 #include <string.h>
41c5c4113dSnw141292 #include <ctype.h>
42c5c4113dSnw141292 #include <pthread.h>
43c5c4113dSnw141292 #include <synch.h>
44c5c4113dSnw141292 #include <atomic.h>
45c5c4113dSnw141292 #include <errno.h>
46c5c4113dSnw141292 #include <assert.h>
47c5c4113dSnw141292 #include <limits.h>
482b4a7802SBaban Kenkre #include <time.h>
49cd37da74Snw141292 #include <sys/u8_textprep.h>
502b4a7802SBaban Kenkre #include "libadutils.h"
51479ac375Sdm199847 #include "nldaputils.h"
52c5c4113dSnw141292 #include "idmapd.h"
53c5c4113dSnw141292 
54c5c4113dSnw141292 /* Attribute names and filter format strings */
55e3c2d6aaSnw141292 #define	SAN		"sAMAccountName"
56e3c2d6aaSnw141292 #define	OBJSID		"objectSid"
57e3c2d6aaSnw141292 #define	OBJCLASS	"objectClass"
58c5c4113dSnw141292 #define	SANFILTER	"(sAMAccountName=%.*s)"
59e3c2d6aaSnw141292 #define	OBJSIDFILTER	"(objectSid=%s)"
60c5c4113dSnw141292 
612b4a7802SBaban Kenkre void	idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc,
622b4a7802SBaban Kenkre 		int qid, void *argp);
63c5c4113dSnw141292 
64c5c4113dSnw141292 /*
65c5c4113dSnw141292  * A place to put the results of a batched (async) query
66c5c4113dSnw141292  *
67c5c4113dSnw141292  * There is one of these for every query added to a batch object
68c5c4113dSnw141292  * (idmap_query_state, see below).
69c5c4113dSnw141292  */
70c5c4113dSnw141292 typedef struct idmap_q {
71e3c2d6aaSnw141292 	/*
72e3c2d6aaSnw141292 	 * data used for validating search result entries for name->SID
73e8c27ec8Sbaban 	 * lookups
74e3c2d6aaSnw141292 	 */
75cd37da74Snw141292 	char			*ecanonname;	/* expected canon name */
76cd37da74Snw141292 	char			*edomain;	/* expected domain name */
77e8c27ec8Sbaban 	int			eunixtype;	/* expected unix type */
78e3c2d6aaSnw141292 	/* results */
79cd37da74Snw141292 	char			**canonname;	/* actual canon name */
80c5c4113dSnw141292 	char			**domain;	/* name of domain of object */
81e8c27ec8Sbaban 	char			**sid;		/* stringified SID */
82e8c27ec8Sbaban 	rid_t			*rid;		/* RID */
83e8c27ec8Sbaban 	int			*sid_type;	/* user or group SID? */
84e8c27ec8Sbaban 	char			**unixname;	/* unixname for name mapping */
8548258c6bSjp151216 	char			**dn;		/* DN of entry */
8648258c6bSjp151216 	char			**attr;		/* Attr for name mapping */
8748258c6bSjp151216 	char			**value;	/* value for name mapping */
88c5c4113dSnw141292 	idmap_retcode		*rc;
892b4a7802SBaban Kenkre 	adutils_rc		ad_rc;
902b4a7802SBaban Kenkre 	adutils_result_t	*result;
91e3c2d6aaSnw141292 
92bcced03bSjp151216 	/*
93bcced03bSjp151216 	 * The LDAP search entry result is placed here to be processed
94bcced03bSjp151216 	 * when the search done result is received.
95bcced03bSjp151216 	 */
96bcced03bSjp151216 	LDAPMessage		*search_res;	/* The LDAP search result */
97c5c4113dSnw141292 } idmap_q_t;
98c5c4113dSnw141292 
99c5c4113dSnw141292 /* Batch context structure; typedef is in header file */
100c5c4113dSnw141292 struct idmap_query_state {
1012b4a7802SBaban Kenkre 	adutils_query_state_t	*qs;
102*4d61c878SJulian Pullen 	int			qsize;		/* Queue size */
103*4d61c878SJulian Pullen 	uint32_t		qcount;		/* Number of queued requests */
104e8c27ec8Sbaban 	const char		*ad_unixuser_attr;
105e8c27ec8Sbaban 	const char		*ad_unixgroup_attr;
106c5c4113dSnw141292 	idmap_q_t		queries[1];	/* array of query results */
107c5c4113dSnw141292 };
108c5c4113dSnw141292 
109651c0131Sbaban static pthread_t	reaperid = 0;
110c5c4113dSnw141292 
111c5c4113dSnw141292 /*
112c5c4113dSnw141292  * Keep connection management simple for now, extend or replace later
113c5c4113dSnw141292  * with updated libsldap code.
114c5c4113dSnw141292  */
115c5c4113dSnw141292 #define	ADREAPERSLEEP	60
116c5c4113dSnw141292 
117c5c4113dSnw141292 /*
118c5c4113dSnw141292  * Idle connection reaping side of connection management
119c5c4113dSnw141292  *
120c5c4113dSnw141292  * Every minute wake up and look for connections that have been idle for
121c5c4113dSnw141292  * five minutes or more and close them.
122c5c4113dSnw141292  */
123c5c4113dSnw141292 /*ARGSUSED*/
124c5c4113dSnw141292 static
125c5c4113dSnw141292 void
126c5c4113dSnw141292 adreaper(void *arg)
127c5c4113dSnw141292 {
128c5c4113dSnw141292 	timespec_t	ts;
129c5c4113dSnw141292 
130c5c4113dSnw141292 	ts.tv_sec = ADREAPERSLEEP;
131c5c4113dSnw141292 	ts.tv_nsec = 0;
132c5c4113dSnw141292 
133c5c4113dSnw141292 	for (;;) {
134c5c4113dSnw141292 		/*
135c5c4113dSnw141292 		 * nanosleep(3RT) is thead-safe (no SIGALRM) and more
136c5c4113dSnw141292 		 * portable than usleep(3C)
137c5c4113dSnw141292 		 */
138c5c4113dSnw141292 		(void) nanosleep(&ts, NULL);
1392b4a7802SBaban Kenkre 		adutils_reap_idle_connections();
140c5c4113dSnw141292 	}
141c5c4113dSnw141292 }
142c5c4113dSnw141292 
143c5c4113dSnw141292 /*
144c5c4113dSnw141292  * Take ad_host_config_t information, create a ad_host_t,
145c5c4113dSnw141292  * populate it and add it to the list of hosts.
146c5c4113dSnw141292  */
147c5c4113dSnw141292 
148c5c4113dSnw141292 int
1492b4a7802SBaban Kenkre idmap_add_ds(adutils_ad_t *ad, const char *host, int port)
150c5c4113dSnw141292 {
151c5c4113dSnw141292 	int	ret = -1;
152c5c4113dSnw141292 
1532b4a7802SBaban Kenkre 	if (adutils_add_ds(ad, host, port) == ADUTILS_SUCCESS)
154c8e26105Sjp151216 		ret = 0;
155c5c4113dSnw141292 
156c5c4113dSnw141292 	/* Start reaper if it doesn't exist */
1572b4a7802SBaban Kenkre 	if (ret == 0 && reaperid == 0)
158c5c4113dSnw141292 		(void) pthread_create(&reaperid, NULL,
159c5c4113dSnw141292 		    (void *(*)(void *))adreaper, (void *)NULL);
160c5c4113dSnw141292 	return (ret);
161c5c4113dSnw141292 }
162c5c4113dSnw141292 
163c5c4113dSnw141292 static
1642b4a7802SBaban Kenkre idmap_retcode
1652b4a7802SBaban Kenkre map_adrc2idmaprc(adutils_rc adrc)
166c5c4113dSnw141292 {
1672b4a7802SBaban Kenkre 	switch (adrc) {
1682b4a7802SBaban Kenkre 	case ADUTILS_SUCCESS:
1692b4a7802SBaban Kenkre 		return (IDMAP_SUCCESS);
1702b4a7802SBaban Kenkre 	case ADUTILS_ERR_NOTFOUND:
1712b4a7802SBaban Kenkre 		return (IDMAP_ERR_NOTFOUND);
1722b4a7802SBaban Kenkre 	case ADUTILS_ERR_MEMORY:
1732b4a7802SBaban Kenkre 		return (IDMAP_ERR_MEMORY);
1742b4a7802SBaban Kenkre 	case ADUTILS_ERR_DOMAIN:
1752b4a7802SBaban Kenkre 		return (IDMAP_ERR_DOMAIN);
1762b4a7802SBaban Kenkre 	case ADUTILS_ERR_OTHER:
1772b4a7802SBaban Kenkre 		return (IDMAP_ERR_OTHER);
1782b4a7802SBaban Kenkre 	case ADUTILS_ERR_RETRIABLE_NET_ERR:
1792b4a7802SBaban Kenkre 		return (IDMAP_ERR_RETRIABLE_NET_ERR);
1802b4a7802SBaban Kenkre 	default:
1812b4a7802SBaban Kenkre 		return (IDMAP_ERR_INTERNAL);
182c5c4113dSnw141292 	}
1832b4a7802SBaban Kenkre 	/* NOTREACHED */
184c5c4113dSnw141292 }
185c5c4113dSnw141292 
186c5c4113dSnw141292 idmap_retcode
1872b4a7802SBaban Kenkre idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
1882b4a7802SBaban Kenkre 	idmap_query_state_t **state)
189c5c4113dSnw141292 {
190c5c4113dSnw141292 	idmap_query_state_t	*new_state;
1912b4a7802SBaban Kenkre 	adutils_rc		rc;
192c5c4113dSnw141292 
193c5c4113dSnw141292 	*state = NULL;
194c5c4113dSnw141292 
195*4d61c878SJulian Pullen 	assert(ad != NULL);
196c5c4113dSnw141292 
197c5c4113dSnw141292 	new_state = calloc(1, sizeof (idmap_query_state_t) +
198c5c4113dSnw141292 	    (nqueries - 1) * sizeof (idmap_q_t));
199c5c4113dSnw141292 	if (new_state == NULL)
200c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
201c5c4113dSnw141292 
2022b4a7802SBaban Kenkre 	if ((rc = adutils_lookup_batch_start(ad, nqueries,
2032b4a7802SBaban Kenkre 	    idmap_ldap_res_search_cb, new_state, &new_state->qs))
2042b4a7802SBaban Kenkre 	    != ADUTILS_SUCCESS) {
2052b4a7802SBaban Kenkre 		free(new_state);
2062b4a7802SBaban Kenkre 		return (map_adrc2idmaprc(rc));
2072b4a7802SBaban Kenkre 	}
2082b4a7802SBaban Kenkre 
209*4d61c878SJulian Pullen 	new_state->qsize = nqueries;
210c5c4113dSnw141292 	*state = new_state;
211c5c4113dSnw141292 	return (IDMAP_SUCCESS);
212c5c4113dSnw141292 }
213c5c4113dSnw141292 
214c5c4113dSnw141292 /*
215e8c27ec8Sbaban  * Set unixuser_attr and unixgroup_attr for AD-based name mapping
216e8c27ec8Sbaban  */
217e8c27ec8Sbaban void
218e8c27ec8Sbaban idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
2194edd44c5Sjp151216 		const char *unixuser_attr, const char *unixgroup_attr)
2204edd44c5Sjp151216 {
221e8c27ec8Sbaban 	state->ad_unixuser_attr = unixuser_attr;
222e8c27ec8Sbaban 	state->ad_unixgroup_attr = unixgroup_attr;
223e8c27ec8Sbaban }
224e8c27ec8Sbaban 
225e8c27ec8Sbaban /*
226cd37da74Snw141292  * Take parsed attribute values from a search result entry and check if
227cd37da74Snw141292  * it is the result that was desired and, if so, set the result fields
228cd37da74Snw141292  * of the given idmap_q_t.
229cd37da74Snw141292  *
230e8c27ec8Sbaban  * Frees the unused char * values.
231c5c4113dSnw141292  */
232c5c4113dSnw141292 static
233cd37da74Snw141292 void
23448258c6bSjp151216 idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
23548258c6bSjp151216 	char *sid, rid_t rid, int sid_type, char *unixname)
236c5c4113dSnw141292 {
237cd37da74Snw141292 	char *domain;
238e8c27ec8Sbaban 	int err1, err2;
239cd37da74Snw141292 
240cd37da74Snw141292 	assert(dn != NULL);
241cd37da74Snw141292 
2422b4a7802SBaban Kenkre 	if ((domain = adutils_dn2dns(dn)) == NULL)
243cd37da74Snw141292 		goto out;
244cd37da74Snw141292 
245e8c27ec8Sbaban 	if (q->ecanonname != NULL && san != NULL) {
246e8c27ec8Sbaban 		/* Check that this is the canonname that we were looking for */
247cd37da74Snw141292 		if (u8_strcmp(q->ecanonname, san, 0,
248cd37da74Snw141292 		    U8_STRCMP_CI_LOWER, /* no normalization, for now */
249e8c27ec8Sbaban 		    U8_UNICODE_LATEST, &err1) != 0 || err1 != 0)
250e8c27ec8Sbaban 			goto out;
251e8c27ec8Sbaban 	}
252e8c27ec8Sbaban 
253e8c27ec8Sbaban 	if (q->edomain != NULL) {
254e8c27ec8Sbaban 		/* Check that this is the domain that we were looking for */
255e8c27ec8Sbaban 		if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER,
256cd37da74Snw141292 		    U8_UNICODE_LATEST, &err2) != 0 || err2 != 0)
257cd37da74Snw141292 			goto out;
258e8c27ec8Sbaban 	}
259cd37da74Snw141292 
26048258c6bSjp151216 	/* Copy the DN and attr and value */
26148258c6bSjp151216 	if (q->dn != NULL)
26248258c6bSjp151216 		*q->dn = strdup(dn);
26348258c6bSjp151216 
26448258c6bSjp151216 	if (q->attr != NULL && attr != NULL)
26548258c6bSjp151216 		*q->attr = strdup(attr);
26648258c6bSjp151216 
26748258c6bSjp151216 	if (q->value != NULL && unixname != NULL)
26848258c6bSjp151216 		*q->value = strdup(unixname);
26948258c6bSjp151216 
270e8c27ec8Sbaban 	/* Set results */
271e8c27ec8Sbaban 	if (q->sid) {
272e8c27ec8Sbaban 		*q->sid = sid;
273cd37da74Snw141292 		sid = NULL;
274e8c27ec8Sbaban 	}
275e8c27ec8Sbaban 	if (q->rid)
276e8c27ec8Sbaban 		*q->rid = rid;
277e8c27ec8Sbaban 	if (q->sid_type)
278cd37da74Snw141292 		*q->sid_type = sid_type;
279e8c27ec8Sbaban 	if (q->unixname) {
280e8c27ec8Sbaban 		*q->unixname = unixname;
281e8c27ec8Sbaban 		unixname = NULL;
282e8c27ec8Sbaban 	}
283cd37da74Snw141292 	if (q->domain != NULL) {
284cd37da74Snw141292 		*q->domain = domain;
285cd37da74Snw141292 		domain = NULL;
286e8c27ec8Sbaban 	}
287e8c27ec8Sbaban 	if (q->canonname != NULL) {
288479ac375Sdm199847 		/*
289479ac375Sdm199847 		 * The caller may be replacing the given winname by its
290479ac375Sdm199847 		 * canonical name and therefore free any old name before
291479ac375Sdm199847 		 * overwriting the field by the canonical name.
292479ac375Sdm199847 		 */
293479ac375Sdm199847 		free(*q->canonname);
294e8c27ec8Sbaban 		*q->canonname = san;
295cd37da74Snw141292 		san = NULL;
296cd37da74Snw141292 	}
297cd37da74Snw141292 
2982b4a7802SBaban Kenkre 	q->ad_rc = ADUTILS_SUCCESS;
299cd37da74Snw141292 
300cd37da74Snw141292 out:
301cd37da74Snw141292 	/* Free unused attribute values */
302cd37da74Snw141292 	free(san);
303cd37da74Snw141292 	free(sid);
304cd37da74Snw141292 	free(domain);
305e8c27ec8Sbaban 	free(unixname);
306c5c4113dSnw141292 }
307c5c4113dSnw141292 
308c5c4113dSnw141292 #define	BVAL_CASEEQ(bv, str) \
309c5c4113dSnw141292 		(((*(bv))->bv_len == (sizeof (str) - 1)) && \
310c5c4113dSnw141292 		    strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0)
311c5c4113dSnw141292 
312c5c4113dSnw141292 /*
313cd37da74Snw141292  * Extract the class of the result entry.  Returns 1 on success, 0 on
314cd37da74Snw141292  * failure.
315c5c4113dSnw141292  */
316c5c4113dSnw141292 static
317e3c2d6aaSnw141292 int
318cd37da74Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type)
319c5c4113dSnw141292 {
320c5c4113dSnw141292 	BerValue	**cbval;
321c5c4113dSnw141292 
322cd37da74Snw141292 	*sid_type = _IDMAP_T_OTHER;
323c5c4113dSnw141292 	if (bvalues == NULL)
324e3c2d6aaSnw141292 		return (0);
325c5c4113dSnw141292 
326cd37da74Snw141292 	/*
327cd37da74Snw141292 	 * We iterate over all the values because computer is a
328cd37da74Snw141292 	 * sub-class of user.
329cd37da74Snw141292 	 */
330c5c4113dSnw141292 	for (cbval = bvalues; *cbval != NULL; cbval++) {
331c5c4113dSnw141292 		if (BVAL_CASEEQ(cbval, "Computer")) {
332cd37da74Snw141292 			*sid_type = _IDMAP_T_COMPUTER;
333cd37da74Snw141292 			break;
334c5c4113dSnw141292 		} else if (BVAL_CASEEQ(cbval, "Group")) {
335cd37da74Snw141292 			*sid_type = _IDMAP_T_GROUP;
336cd37da74Snw141292 			break;
337c5c4113dSnw141292 		} else if (BVAL_CASEEQ(cbval, "USER")) {
338cd37da74Snw141292 			*sid_type = _IDMAP_T_USER;
339cd37da74Snw141292 			/* Continue looping -- this may be a computer yet */
340cd37da74Snw141292 		}
341cd37da74Snw141292 		/*
342cd37da74Snw141292 		 * "else if (*sid_type = _IDMAP_T_USER)" then this is a
343cd37da74Snw141292 		 * new sub-class of user -- what to do with it??
344cd37da74Snw141292 		 */
345c5c4113dSnw141292 	}
346e3c2d6aaSnw141292 
347e3c2d6aaSnw141292 	return (1);
348c5c4113dSnw141292 }
349c5c4113dSnw141292 
350c5c4113dSnw141292 /*
351c5c4113dSnw141292  * Handle a given search result entry
352c5c4113dSnw141292  */
353c5c4113dSnw141292 static
354c5c4113dSnw141292 void
3552b4a7802SBaban Kenkre idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q,
3562b4a7802SBaban Kenkre 	LDAPMessage *res, LDAP *ld)
357c5c4113dSnw141292 {
358c5c4113dSnw141292 	BerElement		*ber = NULL;
359c5c4113dSnw141292 	BerValue		**bvalues;
360cd37da74Snw141292 	char			*attr;
361e8c27ec8Sbaban 	const char		*unixuser_attr = NULL;
362e8c27ec8Sbaban 	const char		*unixgroup_attr = NULL;
363e8c27ec8Sbaban 	char			*unixuser = NULL;
364e8c27ec8Sbaban 	char			*unixgroup = NULL;
365cd37da74Snw141292 	char			*dn = NULL;
366cd37da74Snw141292 	char			*san = NULL;
367cd37da74Snw141292 	char			*sid = NULL;
368cd37da74Snw141292 	rid_t			rid = 0;
369e8c27ec8Sbaban 	int			sid_type = _IDMAP_T_UNDEF;
370e3c2d6aaSnw141292 	int			has_class, has_san, has_sid;
371e8c27ec8Sbaban 	int			has_unixuser, has_unixgroup;
372e3c2d6aaSnw141292 
373e8c27ec8Sbaban 	assert(q->rc != NULL);
374e8c27ec8Sbaban 
3752b4a7802SBaban Kenkre 	if ((dn = ldap_get_dn(ld, res)) == NULL)
376c5c4113dSnw141292 		return;
377c5c4113dSnw141292 
378e3c2d6aaSnw141292 	assert(q->domain == NULL || *q->domain == NULL);
379c5c4113dSnw141292 
380e8c27ec8Sbaban 	/*
381e8c27ec8Sbaban 	 * If the caller has requested unixname then determine the
382e8c27ec8Sbaban 	 * AD attribute name that will have the unixname.
383e8c27ec8Sbaban 	 */
384e8c27ec8Sbaban 	if (q->unixname != NULL) {
385e8c27ec8Sbaban 		if (q->eunixtype == _IDMAP_T_USER)
386e8c27ec8Sbaban 			unixuser_attr = state->ad_unixuser_attr;
387e8c27ec8Sbaban 		else if (q->eunixtype == _IDMAP_T_GROUP)
388e8c27ec8Sbaban 			unixgroup_attr = state->ad_unixgroup_attr;
389e8c27ec8Sbaban 		else if (q->eunixtype == _IDMAP_T_UNDEF) {
390e8c27ec8Sbaban 			/*
391e8c27ec8Sbaban 			 * This is the case where we don't know
392e8c27ec8Sbaban 			 * before hand whether we need unixuser
393e8c27ec8Sbaban 			 * or unixgroup. This will be determined
394e8c27ec8Sbaban 			 * by the "sid_type" (i.e whether the given
395e8c27ec8Sbaban 			 * winname is user or group). If sid_type
396e8c27ec8Sbaban 			 * turns out to be user we will return
397e8c27ec8Sbaban 			 * unixuser (if found) and if it is a group
398e8c27ec8Sbaban 			 * we will return unixgroup (if found). We
399e8c27ec8Sbaban 			 * lookup for both ad_unixuser_attr and
400e8c27ec8Sbaban 			 * ad_unixgroup_attr and discard one of them
401e8c27ec8Sbaban 			 * after we know the "sidtype". This
402e8c27ec8Sbaban 			 * supports the following type of lookups.
403e8c27ec8Sbaban 			 *
404e8c27ec8Sbaban 			 * Example:
405e8c27ec8Sbaban 			 *   $idmap show -c winname:foo
406e8c27ec8Sbaban 			 * In the above example, idmap will
407e8c27ec8Sbaban 			 * return uid if winname is winuser
408e8c27ec8Sbaban 			 * and gid if winname is wingroup.
409e8c27ec8Sbaban 			 */
410e8c27ec8Sbaban 			unixuser_attr = state->ad_unixuser_attr;
411e8c27ec8Sbaban 			unixgroup_attr = state->ad_unixgroup_attr;
412e8c27ec8Sbaban 		}
413e8c27ec8Sbaban 	}
414e8c27ec8Sbaban 
415e8c27ec8Sbaban 	has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0;
4162b4a7802SBaban Kenkre 	for (attr = ldap_first_attribute(ld, res, &ber); attr != NULL;
4172b4a7802SBaban Kenkre 	    attr = ldap_next_attribute(ld, res, ber)) {
418c5c4113dSnw141292 		bvalues = NULL;	/* for memory management below */
419c5c4113dSnw141292 
420c5c4113dSnw141292 		/*
421c5c4113dSnw141292 		 * If this is an attribute we are looking for and
422c5c4113dSnw141292 		 * haven't seen it yet, parse it
423c5c4113dSnw141292 		 */
424e8c27ec8Sbaban 		if (q->sid != NULL && !has_sid &&
425e3c2d6aaSnw141292 		    strcasecmp(attr, OBJSID) == 0) {
4262b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
4272b4a7802SBaban Kenkre 			if (bvalues != NULL) {
4282b4a7802SBaban Kenkre 				sid = adutils_bv_objsid2sidstr(
4292b4a7802SBaban Kenkre 				    bvalues[0], &rid);
430cd37da74Snw141292 				has_sid = (sid != NULL);
4312b4a7802SBaban Kenkre 			}
432e3c2d6aaSnw141292 		} else if (!has_san && strcasecmp(attr, SAN) == 0) {
4332b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
4342b4a7802SBaban Kenkre 			if (bvalues != NULL) {
4352b4a7802SBaban Kenkre 				san = adutils_bv_name2str(bvalues[0]);
436cd37da74Snw141292 				has_san = (san != NULL);
4372b4a7802SBaban Kenkre 			}
438e3c2d6aaSnw141292 		} else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) {
4392b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
440cd37da74Snw141292 			has_class = idmap_bv_objclass2sidtype(bvalues,
441cd37da74Snw141292 			    &sid_type);
442e8c27ec8Sbaban 			if (has_class && q->unixname != NULL &&
443e8c27ec8Sbaban 			    q->eunixtype == _IDMAP_T_UNDEF) {
444e8c27ec8Sbaban 				/*
445e8c27ec8Sbaban 				 * This is the case where we didn't
446e8c27ec8Sbaban 				 * know whether we wanted unixuser or
447e8c27ec8Sbaban 				 * unixgroup as described above.
448e8c27ec8Sbaban 				 * Now since we know the "sid_type"
449e8c27ec8Sbaban 				 * we discard the unwanted value
450e8c27ec8Sbaban 				 * if it was retrieved before we
451e8c27ec8Sbaban 				 * got here.
452e8c27ec8Sbaban 				 */
453e8c27ec8Sbaban 				if (sid_type == _IDMAP_T_USER) {
454e8c27ec8Sbaban 					free(unixgroup);
455e8c27ec8Sbaban 					unixgroup_attr = unixgroup = NULL;
456e8c27ec8Sbaban 				} else if (sid_type == _IDMAP_T_GROUP) {
457e8c27ec8Sbaban 					free(unixuser);
458e8c27ec8Sbaban 					unixuser_attr = unixuser = NULL;
459e8c27ec8Sbaban 				} else {
460e8c27ec8Sbaban 					free(unixuser);
461e8c27ec8Sbaban 					free(unixgroup);
462e8c27ec8Sbaban 					unixuser_attr = unixuser = NULL;
463e8c27ec8Sbaban 					unixgroup_attr = unixgroup = NULL;
464e8c27ec8Sbaban 				}
465e8c27ec8Sbaban 			}
466e8c27ec8Sbaban 		} else if (!has_unixuser && unixuser_attr != NULL &&
467e8c27ec8Sbaban 		    strcasecmp(attr, unixuser_attr) == 0) {
4682b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
4692b4a7802SBaban Kenkre 			if (bvalues != NULL) {
4702b4a7802SBaban Kenkre 				unixuser = adutils_bv_name2str(bvalues[0]);
471e8c27ec8Sbaban 				has_unixuser = (unixuser != NULL);
4722b4a7802SBaban Kenkre 			}
47348258c6bSjp151216 
474e8c27ec8Sbaban 		} else if (!has_unixgroup && unixgroup_attr != NULL &&
475e8c27ec8Sbaban 		    strcasecmp(attr, unixgroup_attr) == 0) {
4762b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
4772b4a7802SBaban Kenkre 			if (bvalues != NULL) {
4782b4a7802SBaban Kenkre 				unixgroup = adutils_bv_name2str(bvalues[0]);
479e8c27ec8Sbaban 				has_unixgroup = (unixgroup != NULL);
480c5c4113dSnw141292 			}
4812b4a7802SBaban Kenkre 		}
482c5c4113dSnw141292 
483c5c4113dSnw141292 		if (bvalues != NULL)
484c5c4113dSnw141292 			ldap_value_free_len(bvalues);
485c5c4113dSnw141292 		ldap_memfree(attr);
486c5c4113dSnw141292 
487cd37da74Snw141292 		if (has_class && has_san &&
488e8c27ec8Sbaban 		    (q->sid == NULL || has_sid) &&
489e8c27ec8Sbaban 		    (unixuser_attr == NULL || has_unixuser) &&
490e8c27ec8Sbaban 		    (unixgroup_attr == NULL || has_unixgroup)) {
491e8c27ec8Sbaban 			/* Got what we need */
492e3c2d6aaSnw141292 			break;
493c5c4113dSnw141292 		}
494e3c2d6aaSnw141292 	}
495e3c2d6aaSnw141292 
496e8c27ec8Sbaban 	if (!has_class) {
497e8c27ec8Sbaban 		/*
498e8c27ec8Sbaban 		 * Didn't find objectclass. Something's wrong with our
499e8c27ec8Sbaban 		 * AD data.
500e8c27ec8Sbaban 		 */
501e8c27ec8Sbaban 		free(san);
502e8c27ec8Sbaban 		free(sid);
503e8c27ec8Sbaban 		free(unixuser);
504e8c27ec8Sbaban 		free(unixgroup);
505e8c27ec8Sbaban 	} else {
506e8c27ec8Sbaban 		/*
507e8c27ec8Sbaban 		 * Either we got what we needed and came out of the loop
508e8c27ec8Sbaban 		 * early OR we completed the loop in which case we didn't
509e8c27ec8Sbaban 		 * find some attributes that we were looking for. In either
510e8c27ec8Sbaban 		 * case set the result with what we got.
511e8c27ec8Sbaban 		 */
51248258c6bSjp151216 		idmap_setqresults(q, san, dn,
51348258c6bSjp151216 		    (unixuser != NULL) ? unixuser_attr : unixgroup_attr,
51448258c6bSjp151216 		    sid, rid, sid_type,
515e8c27ec8Sbaban 		    (unixuser != NULL) ? unixuser : unixgroup);
516e8c27ec8Sbaban 	}
517e8c27ec8Sbaban 
518c5c4113dSnw141292 	if (ber != NULL)
519c5c4113dSnw141292 		ber_free(ber, 0);
520c5c4113dSnw141292 
521c5c4113dSnw141292 	ldap_memfree(dn);
522c5c4113dSnw141292 }
523c5c4113dSnw141292 
5242b4a7802SBaban Kenkre void
5252b4a7802SBaban Kenkre idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid,
5262b4a7802SBaban Kenkre 		void *argp)
527c5c4113dSnw141292 {
5282b4a7802SBaban Kenkre 	idmap_query_state_t	*state = (idmap_query_state_t *)argp;
5292b4a7802SBaban Kenkre 	idmap_q_t		*q = &(state->queries[qid]);
530c5c4113dSnw141292 
531c5c4113dSnw141292 	switch (rc) {
532c5c4113dSnw141292 	case LDAP_RES_SEARCH_RESULT:
5332b4a7802SBaban Kenkre 		if (q->search_res != NULL) {
5342b4a7802SBaban Kenkre 			idmap_extract_object(state, q, q->search_res, ld);
5352b4a7802SBaban Kenkre 			(void) ldap_msgfree(q->search_res);
5362b4a7802SBaban Kenkre 			q->search_res = NULL;
537bcced03bSjp151216 		} else
5382b4a7802SBaban Kenkre 			q->ad_rc = ADUTILS_ERR_NOTFOUND;
539c5c4113dSnw141292 		break;
540c5c4113dSnw141292 	case LDAP_RES_SEARCH_ENTRY:
5412b4a7802SBaban Kenkre 		if (q->search_res == NULL) {
5422b4a7802SBaban Kenkre 			q->search_res = *res;
5432b4a7802SBaban Kenkre 			*res = NULL;
544bcced03bSjp151216 		}
545c5c4113dSnw141292 		break;
546c5c4113dSnw141292 	default:
547c5c4113dSnw141292 		break;
548c5c4113dSnw141292 	}
54984decf41Sjp151216 }
55084decf41Sjp151216 
551e3c2d6aaSnw141292 static
552e3c2d6aaSnw141292 void
553e3c2d6aaSnw141292 idmap_cleanup_batch(idmap_query_state_t *batch)
554e3c2d6aaSnw141292 {
555e3c2d6aaSnw141292 	int i;
556e3c2d6aaSnw141292 
557e3c2d6aaSnw141292 	for (i = 0; i < batch->qcount; i++) {
558cd37da74Snw141292 		if (batch->queries[i].ecanonname != NULL)
559cd37da74Snw141292 			free(batch->queries[i].ecanonname);
560cd37da74Snw141292 		batch->queries[i].ecanonname = NULL;
561cd37da74Snw141292 		if (batch->queries[i].edomain != NULL)
562cd37da74Snw141292 			free(batch->queries[i].edomain);
563cd37da74Snw141292 		batch->queries[i].edomain = NULL;
564e3c2d6aaSnw141292 	}
565e3c2d6aaSnw141292 }
566e3c2d6aaSnw141292 
56784decf41Sjp151216 /*
56884decf41Sjp151216  * This routine frees the idmap_query_state_t structure
56984decf41Sjp151216  */
570c5c4113dSnw141292 void
57184decf41Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state)
572c5c4113dSnw141292 {
5732b4a7802SBaban Kenkre 	if (state == NULL || *state == NULL)
5742b4a7802SBaban Kenkre 		return;
5752b4a7802SBaban Kenkre 	adutils_lookup_batch_release(&(*state)->qs);
576e3c2d6aaSnw141292 	idmap_cleanup_batch(*state);
577c5c4113dSnw141292 	free(*state);
578c5c4113dSnw141292 	*state = NULL;
579c5c4113dSnw141292 }
580c5c4113dSnw141292 
581c5c4113dSnw141292 idmap_retcode
5820dcc7149Snw141292 idmap_lookup_batch_end(idmap_query_state_t **state)
583c5c4113dSnw141292 {
5842b4a7802SBaban Kenkre 	adutils_rc		ad_rc;
5852b4a7802SBaban Kenkre 	int			i;
5862b4a7802SBaban Kenkre 	idmap_query_state_t	*id_qs = *state;
587c5c4113dSnw141292 
5882b4a7802SBaban Kenkre 	ad_rc = adutils_lookup_batch_end(&id_qs->qs);
589c5c4113dSnw141292 
5902b4a7802SBaban Kenkre 	/*
5912b4a7802SBaban Kenkre 	 * Map adutils rc to idmap_retcode in each
5922b4a7802SBaban Kenkre 	 * query because consumers in dbutils.c
5932b4a7802SBaban Kenkre 	 * expects idmap_retcode.
5942b4a7802SBaban Kenkre 	 */
5952b4a7802SBaban Kenkre 	for (i = 0; i < id_qs->qcount; i++) {
5962b4a7802SBaban Kenkre 		*id_qs->queries[i].rc =
5972b4a7802SBaban Kenkre 		    map_adrc2idmaprc(id_qs->queries[i].ad_rc);
598c5c4113dSnw141292 	}
59984decf41Sjp151216 	idmap_lookup_release_batch(state);
6002b4a7802SBaban Kenkre 	return (map_adrc2idmaprc(ad_rc));
601c5c4113dSnw141292 }
602c5c4113dSnw141292 
603c5c4113dSnw141292 /*
604c5c4113dSnw141292  * Send one prepared search, queue up msgid, process what results are
605c5c4113dSnw141292  * available
606c5c4113dSnw141292  */
607c5c4113dSnw141292 static
608c5c4113dSnw141292 idmap_retcode
60948258c6bSjp151216 idmap_batch_add1(idmap_query_state_t *state, const char *filter,
61048258c6bSjp151216 	char *ecanonname, char *edomain, int eunixtype,
61148258c6bSjp151216 	char **dn, char **attr, char **value,
61248258c6bSjp151216 	char **canonname, char **dname,
61348258c6bSjp151216 	char **sid, rid_t *rid, int *sid_type, char **unixname,
61448258c6bSjp151216 	idmap_retcode *rc)
615c5c4113dSnw141292 {
6162b4a7802SBaban Kenkre 	adutils_rc	ad_rc;
6172b4a7802SBaban Kenkre 	int		qid, i;
618c5c4113dSnw141292 	idmap_q_t	*q;
619cd37da74Snw141292 	static char	*attrs[] = {
620cd37da74Snw141292 		SAN,
621cd37da74Snw141292 		OBJSID,
622cd37da74Snw141292 		OBJCLASS,
623e8c27ec8Sbaban 		NULL,	/* placeholder for unixname attr */
624e8c27ec8Sbaban 		NULL,	/* placeholder for unixname attr */
625cd37da74Snw141292 		NULL
626cd37da74Snw141292 	};
627c5c4113dSnw141292 
628*4d61c878SJulian Pullen 	qid = atomic_inc_32_nv(&state->qcount) - 1;
629c5c4113dSnw141292 	q = &(state->queries[qid]);
630c5c4113dSnw141292 
631*4d61c878SJulian Pullen 	assert(qid < state->qsize);
632*4d61c878SJulian Pullen 
633cd37da74Snw141292 	/*
6342b4a7802SBaban Kenkre 	 * Remember the expected canonname, domainname and unix type
6352b4a7802SBaban Kenkre 	 * so we can check the results * against it
636cd37da74Snw141292 	 */
637cd37da74Snw141292 	q->ecanonname = ecanonname;
638cd37da74Snw141292 	q->edomain = edomain;
639e8c27ec8Sbaban 	q->eunixtype = eunixtype;
640e3c2d6aaSnw141292 
641c5c4113dSnw141292 	/* Remember where to put the results */
642cd37da74Snw141292 	q->canonname = canonname;
643e8c27ec8Sbaban 	q->sid = sid;
644c5c4113dSnw141292 	q->domain = dname;
645c5c4113dSnw141292 	q->rid = rid;
646c5c4113dSnw141292 	q->sid_type = sid_type;
647c5c4113dSnw141292 	q->rc = rc;
648e8c27ec8Sbaban 	q->unixname = unixname;
64948258c6bSjp151216 	q->dn = dn;
65048258c6bSjp151216 	q->attr = attr;
65148258c6bSjp151216 	q->value = value;
652e8c27ec8Sbaban 
653e8c27ec8Sbaban 	/* Add unixuser/unixgroup attribute names to the attrs list */
654e8c27ec8Sbaban 	if (unixname != NULL) {
655e8c27ec8Sbaban 		i = 3;
656e8c27ec8Sbaban 		if (eunixtype != _IDMAP_T_GROUP &&
657e8c27ec8Sbaban 		    state->ad_unixuser_attr != NULL)
658e8c27ec8Sbaban 			attrs[i++] = (char *)state->ad_unixuser_attr;
659e8c27ec8Sbaban 		if (eunixtype != _IDMAP_T_USER &&
660e8c27ec8Sbaban 		    state->ad_unixgroup_attr != NULL)
661e8c27ec8Sbaban 			attrs[i] = (char *)state->ad_unixgroup_attr;
662e8c27ec8Sbaban 	}
663c5c4113dSnw141292 
664c5c4113dSnw141292 	/*
665c5c4113dSnw141292 	 * Provide sane defaults for the results in case we never hear
666c5c4113dSnw141292 	 * back from the DS before closing the connection.
667e3c2d6aaSnw141292 	 *
668e3c2d6aaSnw141292 	 * In particular we default the result to indicate a retriable
669e3c2d6aaSnw141292 	 * error.  The first complete matching result entry will cause
670e3c2d6aaSnw141292 	 * this to be set to IDMAP_SUCCESS, and the end of the results
671e3c2d6aaSnw141292 	 * for this search will cause this to indicate "not found" if no
672e3c2d6aaSnw141292 	 * result entries arrived or no complete ones matched the lookup
673e3c2d6aaSnw141292 	 * we were doing.
674c5c4113dSnw141292 	 */
675c5c4113dSnw141292 	*rc = IDMAP_ERR_RETRIABLE_NET_ERR;
676e8c27ec8Sbaban 	if (sid_type != NULL)
677c5c4113dSnw141292 		*sid_type = _IDMAP_T_OTHER;
678e8c27ec8Sbaban 	if (sid != NULL)
679e8c27ec8Sbaban 		*sid = NULL;
680c5c4113dSnw141292 	if (dname != NULL)
681c5c4113dSnw141292 		*dname = NULL;
682c5c4113dSnw141292 	if (rid != NULL)
683c5c4113dSnw141292 		*rid = 0;
68448258c6bSjp151216 	if (dn != NULL)
68548258c6bSjp151216 		*dn = NULL;
68648258c6bSjp151216 	if (attr != NULL)
68748258c6bSjp151216 		*attr = NULL;
68848258c6bSjp151216 	if (value != NULL)
68948258c6bSjp151216 		*value = NULL;
690c5c4113dSnw141292 
691479ac375Sdm199847 	/*
692479ac375Sdm199847 	 * Don't set *canonname to NULL because it may be pointing to the
693479ac375Sdm199847 	 * given winname. Later on if we get a canonical name from AD the
694479ac375Sdm199847 	 * old name if any will be freed before assigning the new name.
695479ac375Sdm199847 	 */
696479ac375Sdm199847 
697c5c4113dSnw141292 	/*
6982b4a7802SBaban Kenkre 	 * Invoke the mother of all APIs i.e. the adutils API
699c5c4113dSnw141292 	 */
7002b4a7802SBaban Kenkre 	ad_rc = adutils_lookup_batch_add(state->qs, filter,
7012b4a7802SBaban Kenkre 	    (const char **)attrs,
7022b4a7802SBaban Kenkre 	    edomain, &q->result, &q->ad_rc);
7032b4a7802SBaban Kenkre 	return (map_adrc2idmaprc(ad_rc));
704c5c4113dSnw141292 }
705c5c4113dSnw141292 
706c5c4113dSnw141292 idmap_retcode
707c5c4113dSnw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state,
708e8c27ec8Sbaban 	const char *name, const char *dname, int eunixtype,
70948258c6bSjp151216 	char **dn, char **attr, char **value,
71048258c6bSjp151216 	char **canonname, char **sid, rid_t *rid,
71148258c6bSjp151216 	int *sid_type, char **unixname, idmap_retcode *rc)
712c5c4113dSnw141292 {
713c5c4113dSnw141292 	idmap_retcode	retcode;
714e3c2d6aaSnw141292 	int		len, samAcctNameLen;
715479ac375Sdm199847 	char		*filter = NULL, *s_name;
716cd37da74Snw141292 	char		*ecanonname, *edomain; /* expected canonname */
717c5c4113dSnw141292 
718c5c4113dSnw141292 	/*
719e3c2d6aaSnw141292 	 * Strategy: search the global catalog for user/group by
720e3c2d6aaSnw141292 	 * sAMAccountName = user/groupname with "" as the base DN and by
721e3c2d6aaSnw141292 	 * userPrincipalName = user/groupname@domain.  The result
722e3c2d6aaSnw141292 	 * entries will be checked to conform to the name and domain
723e3c2d6aaSnw141292 	 * name given here.  The DN, sAMAccountName, userPrincipalName,
724e3c2d6aaSnw141292 	 * objectSid and objectClass of the result entries are all we
725e3c2d6aaSnw141292 	 * need to figure out which entries match the lookup, the SID of
726e3c2d6aaSnw141292 	 * the user/group and whether it is a user or a group.
727c5c4113dSnw141292 	 */
728c5c4113dSnw141292 
729c5c4113dSnw141292 	/*
730e3c2d6aaSnw141292 	 * We need the name and the domain name separately and as
731e3c2d6aaSnw141292 	 * name@domain.  We also allow the domain to be provided
732e3c2d6aaSnw141292 	 * separately.
733c5c4113dSnw141292 	 */
734d3a612caSnw141292 	samAcctNameLen = strlen(name);
735e3c2d6aaSnw141292 
736cd37da74Snw141292 	if ((ecanonname = strdup(name)) == NULL)
737e3c2d6aaSnw141292 		return (IDMAP_ERR_MEMORY);
738cd37da74Snw141292 
739cd37da74Snw141292 	if (dname == NULL || *dname == '\0') {
740cd37da74Snw141292 		if ((dname = strchr(name, '@')) != NULL) {
741cd37da74Snw141292 			/* 'name' is qualified with a domain name */
742cd37da74Snw141292 			if ((edomain = strdup(dname + 1)) == NULL) {
743cd37da74Snw141292 				free(ecanonname);
744cd37da74Snw141292 				return (IDMAP_ERR_MEMORY);
745cd37da74Snw141292 			}
746cd37da74Snw141292 			*strchr(ecanonname, '@') = '\0';
747c5c4113dSnw141292 		} else {
7482b4a7802SBaban Kenkre 			/* 'name' not qualified and dname not given */
749*4d61c878SJulian Pullen 			dname = adutils_lookup_batch_getdefdomain(state->qs);
7502b4a7802SBaban Kenkre 			assert(dname != NULL);
7512b4a7802SBaban Kenkre 			if (*dname == '\0') {
752cd37da74Snw141292 				free(ecanonname);
753e3c2d6aaSnw141292 				return (IDMAP_ERR_DOMAIN);
754e3c2d6aaSnw141292 			}
7552b4a7802SBaban Kenkre 			edomain = strdup(dname);
756cd37da74Snw141292 			if (edomain == NULL) {
757cd37da74Snw141292 				free(ecanonname);
758e3c2d6aaSnw141292 				return (IDMAP_ERR_MEMORY);
759cd37da74Snw141292 			}
760cd37da74Snw141292 		}
761cd37da74Snw141292 	} else {
762cd37da74Snw141292 		if ((edomain = strdup(dname)) == NULL) {
763cd37da74Snw141292 			free(ecanonname);
764cd37da74Snw141292 			return (IDMAP_ERR_MEMORY);
765cd37da74Snw141292 		}
766e3c2d6aaSnw141292 	}
767c5c4113dSnw141292 
768*4d61c878SJulian Pullen 	if (!adutils_lookup_check_domain(state->qs, dname)) {
769*4d61c878SJulian Pullen 		free(ecanonname);
770*4d61c878SJulian Pullen 		free(edomain);
771*4d61c878SJulian Pullen 		return (IDMAP_ERR_DOMAIN_NOTFOUND);
772*4d61c878SJulian Pullen 	}
773*4d61c878SJulian Pullen 
774479ac375Sdm199847 	s_name = sanitize_for_ldap_filter(name);
775479ac375Sdm199847 	if (s_name == NULL) {
776cd37da74Snw141292 		free(ecanonname);
777479ac375Sdm199847 		free(edomain);
778c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
779c5c4113dSnw141292 	}
780479ac375Sdm199847 
781479ac375Sdm199847 	/* Assemble filter */
782479ac375Sdm199847 	len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, s_name) + 1;
783479ac375Sdm199847 	if ((filter = (char *)malloc(len)) == NULL) {
784479ac375Sdm199847 		free(ecanonname);
785479ac375Sdm199847 		free(edomain);
786479ac375Sdm199847 		if (s_name != name)
787479ac375Sdm199847 			free(s_name);
788479ac375Sdm199847 		return (IDMAP_ERR_MEMORY);
789479ac375Sdm199847 	}
790479ac375Sdm199847 	(void) snprintf(filter, len, SANFILTER, samAcctNameLen, s_name);
791479ac375Sdm199847 	if (s_name != name)
792479ac375Sdm199847 		free(s_name);
793c5c4113dSnw141292 
794cd37da74Snw141292 	retcode = idmap_batch_add1(state, filter, ecanonname, edomain,
79548258c6bSjp151216 	    eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type,
79648258c6bSjp151216 	    unixname, rc);
797c5c4113dSnw141292 
798c5c4113dSnw141292 	free(filter);
799c5c4113dSnw141292 
800c5c4113dSnw141292 	return (retcode);
801c5c4113dSnw141292 }
802c5c4113dSnw141292 
803c5c4113dSnw141292 idmap_retcode
804c5c4113dSnw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state,
805e8c27ec8Sbaban 	const char *sid, const rid_t *rid, int eunixtype,
80648258c6bSjp151216 	char **dn, char **attr, char **value,
80748258c6bSjp151216 	char **name, char **dname, int *sid_type,
80848258c6bSjp151216 	char **unixname, idmap_retcode *rc)
809c5c4113dSnw141292 {
810c5c4113dSnw141292 	idmap_retcode	retcode;
811c5c4113dSnw141292 	int		flen, ret;
812c5c4113dSnw141292 	char		*filter = NULL;
8132b4a7802SBaban Kenkre 	char		cbinsid[ADUTILS_MAXHEXBINSID + 1];
814c5c4113dSnw141292 
815c5c4113dSnw141292 	/*
816c5c4113dSnw141292 	 * Strategy: search [the global catalog] for user/group by
817c5c4113dSnw141292 	 * objectSid = SID with empty base DN.  The DN, sAMAccountName
818c5c4113dSnw141292 	 * and objectClass of the result are all we need to figure out
819c5c4113dSnw141292 	 * the name of the SID and whether it is a user, a group or a
820c5c4113dSnw141292 	 * computer.
821c5c4113dSnw141292 	 */
822c5c4113dSnw141292 
823*4d61c878SJulian Pullen 	if (!adutils_lookup_check_sid_prefix(state->qs, sid))
824*4d61c878SJulian Pullen 		return (IDMAP_ERR_DOMAIN_NOTFOUND);
825*4d61c878SJulian Pullen 
8262b4a7802SBaban Kenkre 	ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid));
827c5c4113dSnw141292 	if (ret != 0)
828c5c4113dSnw141292 		return (IDMAP_ERR_SID);
829c5c4113dSnw141292 
830c5c4113dSnw141292 	/* Assemble filter */
831e3c2d6aaSnw141292 	flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1;
832c5c4113dSnw141292 	if ((filter = (char *)malloc(flen)) == NULL)
833c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
834e3c2d6aaSnw141292 	(void) snprintf(filter, flen, OBJSIDFILTER, cbinsid);
835c5c4113dSnw141292 
836e8c27ec8Sbaban 	retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype,
83748258c6bSjp151216 	    dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, rc);
838e8c27ec8Sbaban 
839e8c27ec8Sbaban 	free(filter);
840e8c27ec8Sbaban 
841e8c27ec8Sbaban 	return (retcode);
842e8c27ec8Sbaban }
843e8c27ec8Sbaban 
844e8c27ec8Sbaban idmap_retcode
845e8c27ec8Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
846e8c27ec8Sbaban 	const char *unixname, int is_user, int is_wuser,
84748258c6bSjp151216 	char **dn, char **attr, char **value,
84848258c6bSjp151216 	char **sid, rid_t *rid, char **name,
84948258c6bSjp151216 	char **dname, int *sid_type, idmap_retcode *rc)
850e8c27ec8Sbaban {
851e8c27ec8Sbaban 	idmap_retcode	retcode;
852e8c27ec8Sbaban 	int		len, ulen;
853479ac375Sdm199847 	char		*filter = NULL, *s_unixname;
854e8c27ec8Sbaban 	const char	*attrname = NULL;
855e8c27ec8Sbaban 
856e8c27ec8Sbaban 	/* Get unixuser or unixgroup AD attribute name */
857e8c27ec8Sbaban 	attrname = (is_user) ?
858e8c27ec8Sbaban 	    state->ad_unixuser_attr : state->ad_unixgroup_attr;
859e8c27ec8Sbaban 	if (attrname == NULL)
860e8c27ec8Sbaban 		return (IDMAP_ERR_NOTFOUND);
861e8c27ec8Sbaban 
862479ac375Sdm199847 	s_unixname = sanitize_for_ldap_filter(unixname);
863479ac375Sdm199847 	if (s_unixname == NULL)
864479ac375Sdm199847 		return (IDMAP_ERR_MEMORY);
865479ac375Sdm199847 
866e8c27ec8Sbaban 	/*  Assemble filter */
867e8c27ec8Sbaban 	ulen = strlen(unixname);
868e8c27ec8Sbaban 	len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))",
869479ac375Sdm199847 	    is_wuser ? "user" : "group", attrname, ulen, s_unixname) + 1;
870479ac375Sdm199847 	if ((filter = (char *)malloc(len)) == NULL) {
871479ac375Sdm199847 		if (s_unixname != unixname)
872479ac375Sdm199847 			free(s_unixname);
873e8c27ec8Sbaban 		return (IDMAP_ERR_MEMORY);
874479ac375Sdm199847 	}
875e8c27ec8Sbaban 	(void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))",
876479ac375Sdm199847 	    is_wuser ? "user" : "group", attrname, ulen, s_unixname);
877479ac375Sdm199847 	if (s_unixname != unixname)
878479ac375Sdm199847 		free(s_unixname);
879e8c27ec8Sbaban 
880e8c27ec8Sbaban 	retcode = idmap_batch_add1(state, filter, NULL, NULL,
88148258c6bSjp151216 	    _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type,
88248258c6bSjp151216 	    NULL, rc);
88348258c6bSjp151216 
88448258c6bSjp151216 	if (retcode == IDMAP_SUCCESS && attr != NULL) {
88548258c6bSjp151216 		if ((*attr = strdup(attrname)) == NULL)
88648258c6bSjp151216 			retcode = IDMAP_ERR_MEMORY;
88748258c6bSjp151216 	}
88848258c6bSjp151216 
88948258c6bSjp151216 	if (retcode == IDMAP_SUCCESS && value != NULL) {
89048258c6bSjp151216 		if (ulen > 0) {
89148258c6bSjp151216 			if ((*value = strdup(unixname)) == NULL)
89248258c6bSjp151216 				retcode = IDMAP_ERR_MEMORY;
89348258c6bSjp151216 		}
89448258c6bSjp151216 		else
89548258c6bSjp151216 			*value = NULL;
89648258c6bSjp151216 	}
897c5c4113dSnw141292 
898c5c4113dSnw141292 	free(filter);
899c5c4113dSnw141292 
900c5c4113dSnw141292 	return (retcode);
901c5c4113dSnw141292 }
902