xref: /titanic_50/usr/src/cmd/idmap/idmapd/adutils.c (revision 2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1f)
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>
48*2b4a7802SBaban Kenkre #include <time.h>
49cd37da74Snw141292 #include <sys/u8_textprep.h>
50*2b4a7802SBaban 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 
61*2b4a7802SBaban Kenkre void	idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc,
62*2b4a7802SBaban 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;
89*2b4a7802SBaban Kenkre 	adutils_rc		ad_rc;
90*2b4a7802SBaban 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 {
101*2b4a7802SBaban Kenkre 	adutils_query_state_t	*qs;
102c5c4113dSnw141292 	int			qcount;		/* how many queries */
103c5c4113dSnw141292 	uint32_t		qlastsent;
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);
139*2b4a7802SBaban 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
149*2b4a7802SBaban Kenkre idmap_add_ds(adutils_ad_t *ad, const char *host, int port)
150c5c4113dSnw141292 {
151c5c4113dSnw141292 	int	ret = -1;
152c5c4113dSnw141292 
153*2b4a7802SBaban Kenkre 	if (adutils_add_ds(ad, host, port) == ADUTILS_SUCCESS)
154c8e26105Sjp151216 		ret = 0;
155c5c4113dSnw141292 
156c5c4113dSnw141292 	/* Start reaper if it doesn't exist */
157*2b4a7802SBaban 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
164*2b4a7802SBaban Kenkre idmap_retcode
165*2b4a7802SBaban Kenkre map_adrc2idmaprc(adutils_rc adrc)
166c5c4113dSnw141292 {
167*2b4a7802SBaban Kenkre 	switch (adrc) {
168*2b4a7802SBaban Kenkre 	case ADUTILS_SUCCESS:
169*2b4a7802SBaban Kenkre 		return (IDMAP_SUCCESS);
170*2b4a7802SBaban Kenkre 	case ADUTILS_ERR_NOTFOUND:
171*2b4a7802SBaban Kenkre 		return (IDMAP_ERR_NOTFOUND);
172*2b4a7802SBaban Kenkre 	case ADUTILS_ERR_MEMORY:
173*2b4a7802SBaban Kenkre 		return (IDMAP_ERR_MEMORY);
174*2b4a7802SBaban Kenkre 	case ADUTILS_ERR_DOMAIN:
175*2b4a7802SBaban Kenkre 		return (IDMAP_ERR_DOMAIN);
176*2b4a7802SBaban Kenkre 	case ADUTILS_ERR_OTHER:
177*2b4a7802SBaban Kenkre 		return (IDMAP_ERR_OTHER);
178*2b4a7802SBaban Kenkre 	case ADUTILS_ERR_RETRIABLE_NET_ERR:
179*2b4a7802SBaban Kenkre 		return (IDMAP_ERR_RETRIABLE_NET_ERR);
180*2b4a7802SBaban Kenkre 	default:
181*2b4a7802SBaban Kenkre 		return (IDMAP_ERR_INTERNAL);
182c5c4113dSnw141292 	}
183*2b4a7802SBaban Kenkre 	/* NOTREACHED */
184c5c4113dSnw141292 }
185c5c4113dSnw141292 
186c5c4113dSnw141292 idmap_retcode
187*2b4a7802SBaban Kenkre idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
188*2b4a7802SBaban Kenkre 	idmap_query_state_t **state)
189c5c4113dSnw141292 {
190c5c4113dSnw141292 	idmap_query_state_t	*new_state;
191*2b4a7802SBaban Kenkre 	adutils_rc		rc;
192c5c4113dSnw141292 
193c5c4113dSnw141292 	*state = NULL;
194c5c4113dSnw141292 
195349d5d8fSnw141292 	if (ad == NULL)
196e8c27ec8Sbaban 		return (IDMAP_ERR_INTERNAL);
197c5c4113dSnw141292 
198c5c4113dSnw141292 	new_state = calloc(1, sizeof (idmap_query_state_t) +
199c5c4113dSnw141292 	    (nqueries - 1) * sizeof (idmap_q_t));
200c5c4113dSnw141292 	if (new_state == NULL)
201c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
202c5c4113dSnw141292 
203*2b4a7802SBaban Kenkre 	if ((rc = adutils_lookup_batch_start(ad, nqueries,
204*2b4a7802SBaban Kenkre 	    idmap_ldap_res_search_cb, new_state, &new_state->qs))
205*2b4a7802SBaban Kenkre 	    != ADUTILS_SUCCESS) {
206*2b4a7802SBaban Kenkre 		free(new_state);
207*2b4a7802SBaban Kenkre 		return (map_adrc2idmaprc(rc));
208*2b4a7802SBaban Kenkre 	}
209*2b4a7802SBaban Kenkre 
210c5c4113dSnw141292 	new_state->qcount = nqueries;
211c5c4113dSnw141292 	*state = new_state;
212c5c4113dSnw141292 	return (IDMAP_SUCCESS);
213c5c4113dSnw141292 }
214c5c4113dSnw141292 
215c5c4113dSnw141292 /*
216e8c27ec8Sbaban  * Set unixuser_attr and unixgroup_attr for AD-based name mapping
217e8c27ec8Sbaban  */
218e8c27ec8Sbaban void
219e8c27ec8Sbaban idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
2204edd44c5Sjp151216 		const char *unixuser_attr, const char *unixgroup_attr)
2214edd44c5Sjp151216 {
222e8c27ec8Sbaban 	state->ad_unixuser_attr = unixuser_attr;
223e8c27ec8Sbaban 	state->ad_unixgroup_attr = unixgroup_attr;
224e8c27ec8Sbaban }
225e8c27ec8Sbaban 
226e8c27ec8Sbaban /*
227cd37da74Snw141292  * Take parsed attribute values from a search result entry and check if
228cd37da74Snw141292  * it is the result that was desired and, if so, set the result fields
229cd37da74Snw141292  * of the given idmap_q_t.
230cd37da74Snw141292  *
231e8c27ec8Sbaban  * Frees the unused char * values.
232c5c4113dSnw141292  */
233c5c4113dSnw141292 static
234cd37da74Snw141292 void
23548258c6bSjp151216 idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
23648258c6bSjp151216 	char *sid, rid_t rid, int sid_type, char *unixname)
237c5c4113dSnw141292 {
238cd37da74Snw141292 	char *domain;
239e8c27ec8Sbaban 	int err1, err2;
240cd37da74Snw141292 
241cd37da74Snw141292 	assert(dn != NULL);
242cd37da74Snw141292 
243*2b4a7802SBaban Kenkre 	if ((domain = adutils_dn2dns(dn)) == NULL)
244cd37da74Snw141292 		goto out;
245cd37da74Snw141292 
246e8c27ec8Sbaban 	if (q->ecanonname != NULL && san != NULL) {
247e8c27ec8Sbaban 		/* Check that this is the canonname that we were looking for */
248cd37da74Snw141292 		if (u8_strcmp(q->ecanonname, san, 0,
249cd37da74Snw141292 		    U8_STRCMP_CI_LOWER, /* no normalization, for now */
250e8c27ec8Sbaban 		    U8_UNICODE_LATEST, &err1) != 0 || err1 != 0)
251e8c27ec8Sbaban 			goto out;
252e8c27ec8Sbaban 	}
253e8c27ec8Sbaban 
254e8c27ec8Sbaban 	if (q->edomain != NULL) {
255e8c27ec8Sbaban 		/* Check that this is the domain that we were looking for */
256e8c27ec8Sbaban 		if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER,
257cd37da74Snw141292 		    U8_UNICODE_LATEST, &err2) != 0 || err2 != 0)
258cd37da74Snw141292 			goto out;
259e8c27ec8Sbaban 	}
260cd37da74Snw141292 
26148258c6bSjp151216 	/* Copy the DN and attr and value */
26248258c6bSjp151216 	if (q->dn != NULL)
26348258c6bSjp151216 		*q->dn = strdup(dn);
26448258c6bSjp151216 
26548258c6bSjp151216 	if (q->attr != NULL && attr != NULL)
26648258c6bSjp151216 		*q->attr = strdup(attr);
26748258c6bSjp151216 
26848258c6bSjp151216 	if (q->value != NULL && unixname != NULL)
26948258c6bSjp151216 		*q->value = strdup(unixname);
27048258c6bSjp151216 
271e8c27ec8Sbaban 	/* Set results */
272e8c27ec8Sbaban 	if (q->sid) {
273e8c27ec8Sbaban 		*q->sid = sid;
274cd37da74Snw141292 		sid = NULL;
275e8c27ec8Sbaban 	}
276e8c27ec8Sbaban 	if (q->rid)
277e8c27ec8Sbaban 		*q->rid = rid;
278e8c27ec8Sbaban 	if (q->sid_type)
279cd37da74Snw141292 		*q->sid_type = sid_type;
280e8c27ec8Sbaban 	if (q->unixname) {
281e8c27ec8Sbaban 		*q->unixname = unixname;
282e8c27ec8Sbaban 		unixname = NULL;
283e8c27ec8Sbaban 	}
284cd37da74Snw141292 	if (q->domain != NULL) {
285cd37da74Snw141292 		*q->domain = domain;
286cd37da74Snw141292 		domain = NULL;
287e8c27ec8Sbaban 	}
288e8c27ec8Sbaban 	if (q->canonname != NULL) {
289479ac375Sdm199847 		/*
290479ac375Sdm199847 		 * The caller may be replacing the given winname by its
291479ac375Sdm199847 		 * canonical name and therefore free any old name before
292479ac375Sdm199847 		 * overwriting the field by the canonical name.
293479ac375Sdm199847 		 */
294479ac375Sdm199847 		free(*q->canonname);
295e8c27ec8Sbaban 		*q->canonname = san;
296cd37da74Snw141292 		san = NULL;
297cd37da74Snw141292 	}
298cd37da74Snw141292 
299*2b4a7802SBaban Kenkre 	q->ad_rc = ADUTILS_SUCCESS;
300cd37da74Snw141292 
301cd37da74Snw141292 out:
302cd37da74Snw141292 	/* Free unused attribute values */
303cd37da74Snw141292 	free(san);
304cd37da74Snw141292 	free(sid);
305cd37da74Snw141292 	free(domain);
306e8c27ec8Sbaban 	free(unixname);
307c5c4113dSnw141292 }
308c5c4113dSnw141292 
309c5c4113dSnw141292 #define	BVAL_CASEEQ(bv, str) \
310c5c4113dSnw141292 		(((*(bv))->bv_len == (sizeof (str) - 1)) && \
311c5c4113dSnw141292 		    strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0)
312c5c4113dSnw141292 
313c5c4113dSnw141292 /*
314cd37da74Snw141292  * Extract the class of the result entry.  Returns 1 on success, 0 on
315cd37da74Snw141292  * failure.
316c5c4113dSnw141292  */
317c5c4113dSnw141292 static
318e3c2d6aaSnw141292 int
319cd37da74Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type)
320c5c4113dSnw141292 {
321c5c4113dSnw141292 	BerValue	**cbval;
322c5c4113dSnw141292 
323cd37da74Snw141292 	*sid_type = _IDMAP_T_OTHER;
324c5c4113dSnw141292 	if (bvalues == NULL)
325e3c2d6aaSnw141292 		return (0);
326c5c4113dSnw141292 
327cd37da74Snw141292 	/*
328cd37da74Snw141292 	 * We iterate over all the values because computer is a
329cd37da74Snw141292 	 * sub-class of user.
330cd37da74Snw141292 	 */
331c5c4113dSnw141292 	for (cbval = bvalues; *cbval != NULL; cbval++) {
332c5c4113dSnw141292 		if (BVAL_CASEEQ(cbval, "Computer")) {
333cd37da74Snw141292 			*sid_type = _IDMAP_T_COMPUTER;
334cd37da74Snw141292 			break;
335c5c4113dSnw141292 		} else if (BVAL_CASEEQ(cbval, "Group")) {
336cd37da74Snw141292 			*sid_type = _IDMAP_T_GROUP;
337cd37da74Snw141292 			break;
338c5c4113dSnw141292 		} else if (BVAL_CASEEQ(cbval, "USER")) {
339cd37da74Snw141292 			*sid_type = _IDMAP_T_USER;
340cd37da74Snw141292 			/* Continue looping -- this may be a computer yet */
341cd37da74Snw141292 		}
342cd37da74Snw141292 		/*
343cd37da74Snw141292 		 * "else if (*sid_type = _IDMAP_T_USER)" then this is a
344cd37da74Snw141292 		 * new sub-class of user -- what to do with it??
345cd37da74Snw141292 		 */
346c5c4113dSnw141292 	}
347e3c2d6aaSnw141292 
348e3c2d6aaSnw141292 	return (1);
349c5c4113dSnw141292 }
350c5c4113dSnw141292 
351c5c4113dSnw141292 /*
352c5c4113dSnw141292  * Handle a given search result entry
353c5c4113dSnw141292  */
354c5c4113dSnw141292 static
355c5c4113dSnw141292 void
356*2b4a7802SBaban Kenkre idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q,
357*2b4a7802SBaban Kenkre 	LDAPMessage *res, LDAP *ld)
358c5c4113dSnw141292 {
359c5c4113dSnw141292 	BerElement		*ber = NULL;
360c5c4113dSnw141292 	BerValue		**bvalues;
361cd37da74Snw141292 	char			*attr;
362e8c27ec8Sbaban 	const char		*unixuser_attr = NULL;
363e8c27ec8Sbaban 	const char		*unixgroup_attr = NULL;
364e8c27ec8Sbaban 	char			*unixuser = NULL;
365e8c27ec8Sbaban 	char			*unixgroup = NULL;
366cd37da74Snw141292 	char			*dn = NULL;
367cd37da74Snw141292 	char			*san = NULL;
368cd37da74Snw141292 	char			*sid = NULL;
369cd37da74Snw141292 	rid_t			rid = 0;
370e8c27ec8Sbaban 	int			sid_type = _IDMAP_T_UNDEF;
371e3c2d6aaSnw141292 	int			has_class, has_san, has_sid;
372e8c27ec8Sbaban 	int			has_unixuser, has_unixgroup;
373e3c2d6aaSnw141292 
374e8c27ec8Sbaban 	assert(q->rc != NULL);
375e8c27ec8Sbaban 
376*2b4a7802SBaban Kenkre 	if ((dn = ldap_get_dn(ld, res)) == NULL)
377c5c4113dSnw141292 		return;
378c5c4113dSnw141292 
379e3c2d6aaSnw141292 	assert(q->domain == NULL || *q->domain == NULL);
380c5c4113dSnw141292 
381e8c27ec8Sbaban 	/*
382e8c27ec8Sbaban 	 * If the caller has requested unixname then determine the
383e8c27ec8Sbaban 	 * AD attribute name that will have the unixname.
384e8c27ec8Sbaban 	 */
385e8c27ec8Sbaban 	if (q->unixname != NULL) {
386e8c27ec8Sbaban 		if (q->eunixtype == _IDMAP_T_USER)
387e8c27ec8Sbaban 			unixuser_attr = state->ad_unixuser_attr;
388e8c27ec8Sbaban 		else if (q->eunixtype == _IDMAP_T_GROUP)
389e8c27ec8Sbaban 			unixgroup_attr = state->ad_unixgroup_attr;
390e8c27ec8Sbaban 		else if (q->eunixtype == _IDMAP_T_UNDEF) {
391e8c27ec8Sbaban 			/*
392e8c27ec8Sbaban 			 * This is the case where we don't know
393e8c27ec8Sbaban 			 * before hand whether we need unixuser
394e8c27ec8Sbaban 			 * or unixgroup. This will be determined
395e8c27ec8Sbaban 			 * by the "sid_type" (i.e whether the given
396e8c27ec8Sbaban 			 * winname is user or group). If sid_type
397e8c27ec8Sbaban 			 * turns out to be user we will return
398e8c27ec8Sbaban 			 * unixuser (if found) and if it is a group
399e8c27ec8Sbaban 			 * we will return unixgroup (if found). We
400e8c27ec8Sbaban 			 * lookup for both ad_unixuser_attr and
401e8c27ec8Sbaban 			 * ad_unixgroup_attr and discard one of them
402e8c27ec8Sbaban 			 * after we know the "sidtype". This
403e8c27ec8Sbaban 			 * supports the following type of lookups.
404e8c27ec8Sbaban 			 *
405e8c27ec8Sbaban 			 * Example:
406e8c27ec8Sbaban 			 *   $idmap show -c winname:foo
407e8c27ec8Sbaban 			 * In the above example, idmap will
408e8c27ec8Sbaban 			 * return uid if winname is winuser
409e8c27ec8Sbaban 			 * and gid if winname is wingroup.
410e8c27ec8Sbaban 			 */
411e8c27ec8Sbaban 			unixuser_attr = state->ad_unixuser_attr;
412e8c27ec8Sbaban 			unixgroup_attr = state->ad_unixgroup_attr;
413e8c27ec8Sbaban 		}
414e8c27ec8Sbaban 	}
415e8c27ec8Sbaban 
416e8c27ec8Sbaban 	has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0;
417*2b4a7802SBaban Kenkre 	for (attr = ldap_first_attribute(ld, res, &ber); attr != NULL;
418*2b4a7802SBaban Kenkre 	    attr = ldap_next_attribute(ld, res, ber)) {
419c5c4113dSnw141292 		bvalues = NULL;	/* for memory management below */
420c5c4113dSnw141292 
421c5c4113dSnw141292 		/*
422c5c4113dSnw141292 		 * If this is an attribute we are looking for and
423c5c4113dSnw141292 		 * haven't seen it yet, parse it
424c5c4113dSnw141292 		 */
425e8c27ec8Sbaban 		if (q->sid != NULL && !has_sid &&
426e3c2d6aaSnw141292 		    strcasecmp(attr, OBJSID) == 0) {
427*2b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
428*2b4a7802SBaban Kenkre 			if (bvalues != NULL) {
429*2b4a7802SBaban Kenkre 				sid = adutils_bv_objsid2sidstr(
430*2b4a7802SBaban Kenkre 				    bvalues[0], &rid);
431cd37da74Snw141292 				has_sid = (sid != NULL);
432*2b4a7802SBaban Kenkre 			}
433e3c2d6aaSnw141292 		} else if (!has_san && strcasecmp(attr, SAN) == 0) {
434*2b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
435*2b4a7802SBaban Kenkre 			if (bvalues != NULL) {
436*2b4a7802SBaban Kenkre 				san = adutils_bv_name2str(bvalues[0]);
437cd37da74Snw141292 				has_san = (san != NULL);
438*2b4a7802SBaban Kenkre 			}
439e3c2d6aaSnw141292 		} else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) {
440*2b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
441cd37da74Snw141292 			has_class = idmap_bv_objclass2sidtype(bvalues,
442cd37da74Snw141292 			    &sid_type);
443e8c27ec8Sbaban 			if (has_class && q->unixname != NULL &&
444e8c27ec8Sbaban 			    q->eunixtype == _IDMAP_T_UNDEF) {
445e8c27ec8Sbaban 				/*
446e8c27ec8Sbaban 				 * This is the case where we didn't
447e8c27ec8Sbaban 				 * know whether we wanted unixuser or
448e8c27ec8Sbaban 				 * unixgroup as described above.
449e8c27ec8Sbaban 				 * Now since we know the "sid_type"
450e8c27ec8Sbaban 				 * we discard the unwanted value
451e8c27ec8Sbaban 				 * if it was retrieved before we
452e8c27ec8Sbaban 				 * got here.
453e8c27ec8Sbaban 				 */
454e8c27ec8Sbaban 				if (sid_type == _IDMAP_T_USER) {
455e8c27ec8Sbaban 					free(unixgroup);
456e8c27ec8Sbaban 					unixgroup_attr = unixgroup = NULL;
457e8c27ec8Sbaban 				} else if (sid_type == _IDMAP_T_GROUP) {
458e8c27ec8Sbaban 					free(unixuser);
459e8c27ec8Sbaban 					unixuser_attr = unixuser = NULL;
460e8c27ec8Sbaban 				} else {
461e8c27ec8Sbaban 					free(unixuser);
462e8c27ec8Sbaban 					free(unixgroup);
463e8c27ec8Sbaban 					unixuser_attr = unixuser = NULL;
464e8c27ec8Sbaban 					unixgroup_attr = unixgroup = NULL;
465e8c27ec8Sbaban 				}
466e8c27ec8Sbaban 			}
467e8c27ec8Sbaban 		} else if (!has_unixuser && unixuser_attr != NULL &&
468e8c27ec8Sbaban 		    strcasecmp(attr, unixuser_attr) == 0) {
469*2b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
470*2b4a7802SBaban Kenkre 			if (bvalues != NULL) {
471*2b4a7802SBaban Kenkre 				unixuser = adutils_bv_name2str(bvalues[0]);
472e8c27ec8Sbaban 				has_unixuser = (unixuser != NULL);
473*2b4a7802SBaban Kenkre 			}
47448258c6bSjp151216 
475e8c27ec8Sbaban 		} else if (!has_unixgroup && unixgroup_attr != NULL &&
476e8c27ec8Sbaban 		    strcasecmp(attr, unixgroup_attr) == 0) {
477*2b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
478*2b4a7802SBaban Kenkre 			if (bvalues != NULL) {
479*2b4a7802SBaban Kenkre 				unixgroup = adutils_bv_name2str(bvalues[0]);
480e8c27ec8Sbaban 				has_unixgroup = (unixgroup != NULL);
481c5c4113dSnw141292 			}
482*2b4a7802SBaban Kenkre 		}
483c5c4113dSnw141292 
484c5c4113dSnw141292 		if (bvalues != NULL)
485c5c4113dSnw141292 			ldap_value_free_len(bvalues);
486c5c4113dSnw141292 		ldap_memfree(attr);
487c5c4113dSnw141292 
488cd37da74Snw141292 		if (has_class && has_san &&
489e8c27ec8Sbaban 		    (q->sid == NULL || has_sid) &&
490e8c27ec8Sbaban 		    (unixuser_attr == NULL || has_unixuser) &&
491e8c27ec8Sbaban 		    (unixgroup_attr == NULL || has_unixgroup)) {
492e8c27ec8Sbaban 			/* Got what we need */
493e3c2d6aaSnw141292 			break;
494c5c4113dSnw141292 		}
495e3c2d6aaSnw141292 	}
496e3c2d6aaSnw141292 
497e8c27ec8Sbaban 	if (!has_class) {
498e8c27ec8Sbaban 		/*
499e8c27ec8Sbaban 		 * Didn't find objectclass. Something's wrong with our
500e8c27ec8Sbaban 		 * AD data.
501e8c27ec8Sbaban 		 */
502e8c27ec8Sbaban 		free(san);
503e8c27ec8Sbaban 		free(sid);
504e8c27ec8Sbaban 		free(unixuser);
505e8c27ec8Sbaban 		free(unixgroup);
506e8c27ec8Sbaban 	} else {
507e8c27ec8Sbaban 		/*
508e8c27ec8Sbaban 		 * Either we got what we needed and came out of the loop
509e8c27ec8Sbaban 		 * early OR we completed the loop in which case we didn't
510e8c27ec8Sbaban 		 * find some attributes that we were looking for. In either
511e8c27ec8Sbaban 		 * case set the result with what we got.
512e8c27ec8Sbaban 		 */
51348258c6bSjp151216 		idmap_setqresults(q, san, dn,
51448258c6bSjp151216 		    (unixuser != NULL) ? unixuser_attr : unixgroup_attr,
51548258c6bSjp151216 		    sid, rid, sid_type,
516e8c27ec8Sbaban 		    (unixuser != NULL) ? unixuser : unixgroup);
517e8c27ec8Sbaban 	}
518e8c27ec8Sbaban 
519c5c4113dSnw141292 	if (ber != NULL)
520c5c4113dSnw141292 		ber_free(ber, 0);
521c5c4113dSnw141292 
522c5c4113dSnw141292 	ldap_memfree(dn);
523c5c4113dSnw141292 }
524c5c4113dSnw141292 
525*2b4a7802SBaban Kenkre void
526*2b4a7802SBaban Kenkre idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid,
527*2b4a7802SBaban Kenkre 		void *argp)
528c5c4113dSnw141292 {
529*2b4a7802SBaban Kenkre 	idmap_query_state_t	*state = (idmap_query_state_t *)argp;
530*2b4a7802SBaban Kenkre 	idmap_q_t		*q = &(state->queries[qid]);
531c5c4113dSnw141292 
532c5c4113dSnw141292 	switch (rc) {
533c5c4113dSnw141292 	case LDAP_RES_SEARCH_RESULT:
534*2b4a7802SBaban Kenkre 		if (q->search_res != NULL) {
535*2b4a7802SBaban Kenkre 			idmap_extract_object(state, q, q->search_res, ld);
536*2b4a7802SBaban Kenkre 			(void) ldap_msgfree(q->search_res);
537*2b4a7802SBaban Kenkre 			q->search_res = NULL;
538bcced03bSjp151216 		} else
539*2b4a7802SBaban Kenkre 			q->ad_rc = ADUTILS_ERR_NOTFOUND;
540c5c4113dSnw141292 		break;
541c5c4113dSnw141292 	case LDAP_RES_SEARCH_ENTRY:
542*2b4a7802SBaban Kenkre 		if (q->search_res == NULL) {
543*2b4a7802SBaban Kenkre 			q->search_res = *res;
544*2b4a7802SBaban Kenkre 			*res = NULL;
545bcced03bSjp151216 		}
546c5c4113dSnw141292 		break;
547c5c4113dSnw141292 	default:
548c5c4113dSnw141292 		break;
549c5c4113dSnw141292 	}
55084decf41Sjp151216 }
55184decf41Sjp151216 
552e3c2d6aaSnw141292 static
553e3c2d6aaSnw141292 void
554e3c2d6aaSnw141292 idmap_cleanup_batch(idmap_query_state_t *batch)
555e3c2d6aaSnw141292 {
556e3c2d6aaSnw141292 	int i;
557e3c2d6aaSnw141292 
558e3c2d6aaSnw141292 	for (i = 0; i < batch->qcount; i++) {
559cd37da74Snw141292 		if (batch->queries[i].ecanonname != NULL)
560cd37da74Snw141292 			free(batch->queries[i].ecanonname);
561cd37da74Snw141292 		batch->queries[i].ecanonname = NULL;
562cd37da74Snw141292 		if (batch->queries[i].edomain != NULL)
563cd37da74Snw141292 			free(batch->queries[i].edomain);
564cd37da74Snw141292 		batch->queries[i].edomain = NULL;
565e3c2d6aaSnw141292 	}
566e3c2d6aaSnw141292 }
567e3c2d6aaSnw141292 
56884decf41Sjp151216 /*
56984decf41Sjp151216  * This routine frees the idmap_query_state_t structure
57084decf41Sjp151216  */
571c5c4113dSnw141292 void
57284decf41Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state)
573c5c4113dSnw141292 {
574*2b4a7802SBaban Kenkre 	if (state == NULL || *state == NULL)
575*2b4a7802SBaban Kenkre 		return;
576*2b4a7802SBaban Kenkre 	adutils_lookup_batch_release(&(*state)->qs);
577e3c2d6aaSnw141292 	idmap_cleanup_batch(*state);
578c5c4113dSnw141292 	free(*state);
579c5c4113dSnw141292 	*state = NULL;
580c5c4113dSnw141292 }
581c5c4113dSnw141292 
582c5c4113dSnw141292 idmap_retcode
5830dcc7149Snw141292 idmap_lookup_batch_end(idmap_query_state_t **state)
584c5c4113dSnw141292 {
585*2b4a7802SBaban Kenkre 	adutils_rc		ad_rc;
586*2b4a7802SBaban Kenkre 	int			i;
587*2b4a7802SBaban Kenkre 	idmap_query_state_t	*id_qs = *state;
588c5c4113dSnw141292 
589*2b4a7802SBaban Kenkre 	ad_rc = adutils_lookup_batch_end(&id_qs->qs);
590c5c4113dSnw141292 
591*2b4a7802SBaban Kenkre 	/*
592*2b4a7802SBaban Kenkre 	 * Map adutils rc to idmap_retcode in each
593*2b4a7802SBaban Kenkre 	 * query because consumers in dbutils.c
594*2b4a7802SBaban Kenkre 	 * expects idmap_retcode.
595*2b4a7802SBaban Kenkre 	 */
596*2b4a7802SBaban Kenkre 	for (i = 0; i < id_qs->qcount; i++) {
597*2b4a7802SBaban Kenkre 		*id_qs->queries[i].rc =
598*2b4a7802SBaban Kenkre 		    map_adrc2idmaprc(id_qs->queries[i].ad_rc);
599c5c4113dSnw141292 	}
60084decf41Sjp151216 	idmap_lookup_release_batch(state);
601*2b4a7802SBaban Kenkre 	return (map_adrc2idmaprc(ad_rc));
602c5c4113dSnw141292 }
603c5c4113dSnw141292 
604c5c4113dSnw141292 /*
605c5c4113dSnw141292  * Send one prepared search, queue up msgid, process what results are
606c5c4113dSnw141292  * available
607c5c4113dSnw141292  */
608c5c4113dSnw141292 static
609c5c4113dSnw141292 idmap_retcode
61048258c6bSjp151216 idmap_batch_add1(idmap_query_state_t *state, const char *filter,
61148258c6bSjp151216 	char *ecanonname, char *edomain, int eunixtype,
61248258c6bSjp151216 	char **dn, char **attr, char **value,
61348258c6bSjp151216 	char **canonname, char **dname,
61448258c6bSjp151216 	char **sid, rid_t *rid, int *sid_type, char **unixname,
61548258c6bSjp151216 	idmap_retcode *rc)
616c5c4113dSnw141292 {
617*2b4a7802SBaban Kenkre 	adutils_rc	ad_rc;
618*2b4a7802SBaban Kenkre 	int		qid, i;
619c5c4113dSnw141292 	idmap_q_t	*q;
620cd37da74Snw141292 	static char	*attrs[] = {
621cd37da74Snw141292 		SAN,
622cd37da74Snw141292 		OBJSID,
623cd37da74Snw141292 		OBJCLASS,
624e8c27ec8Sbaban 		NULL,	/* placeholder for unixname attr */
625e8c27ec8Sbaban 		NULL,	/* placeholder for unixname attr */
626cd37da74Snw141292 		NULL
627cd37da74Snw141292 	};
628c5c4113dSnw141292 
629c5c4113dSnw141292 	qid = atomic_inc_32_nv(&state->qlastsent) - 1;
630c5c4113dSnw141292 	q = &(state->queries[qid]);
631c5c4113dSnw141292 
632cd37da74Snw141292 	/*
633*2b4a7802SBaban Kenkre 	 * Remember the expected canonname, domainname and unix type
634*2b4a7802SBaban Kenkre 	 * so we can check the results * against it
635cd37da74Snw141292 	 */
636cd37da74Snw141292 	q->ecanonname = ecanonname;
637cd37da74Snw141292 	q->edomain = edomain;
638e8c27ec8Sbaban 	q->eunixtype = eunixtype;
639e3c2d6aaSnw141292 
640c5c4113dSnw141292 	/* Remember where to put the results */
641cd37da74Snw141292 	q->canonname = canonname;
642e8c27ec8Sbaban 	q->sid = sid;
643c5c4113dSnw141292 	q->domain = dname;
644c5c4113dSnw141292 	q->rid = rid;
645c5c4113dSnw141292 	q->sid_type = sid_type;
646c5c4113dSnw141292 	q->rc = rc;
647e8c27ec8Sbaban 	q->unixname = unixname;
64848258c6bSjp151216 	q->dn = dn;
64948258c6bSjp151216 	q->attr = attr;
65048258c6bSjp151216 	q->value = value;
651e8c27ec8Sbaban 
652e8c27ec8Sbaban 	/* Add unixuser/unixgroup attribute names to the attrs list */
653e8c27ec8Sbaban 	if (unixname != NULL) {
654e8c27ec8Sbaban 		i = 3;
655e8c27ec8Sbaban 		if (eunixtype != _IDMAP_T_GROUP &&
656e8c27ec8Sbaban 		    state->ad_unixuser_attr != NULL)
657e8c27ec8Sbaban 			attrs[i++] = (char *)state->ad_unixuser_attr;
658e8c27ec8Sbaban 		if (eunixtype != _IDMAP_T_USER &&
659e8c27ec8Sbaban 		    state->ad_unixgroup_attr != NULL)
660e8c27ec8Sbaban 			attrs[i] = (char *)state->ad_unixgroup_attr;
661e8c27ec8Sbaban 	}
662c5c4113dSnw141292 
663c5c4113dSnw141292 	/*
664c5c4113dSnw141292 	 * Provide sane defaults for the results in case we never hear
665c5c4113dSnw141292 	 * back from the DS before closing the connection.
666e3c2d6aaSnw141292 	 *
667e3c2d6aaSnw141292 	 * In particular we default the result to indicate a retriable
668e3c2d6aaSnw141292 	 * error.  The first complete matching result entry will cause
669e3c2d6aaSnw141292 	 * this to be set to IDMAP_SUCCESS, and the end of the results
670e3c2d6aaSnw141292 	 * for this search will cause this to indicate "not found" if no
671e3c2d6aaSnw141292 	 * result entries arrived or no complete ones matched the lookup
672e3c2d6aaSnw141292 	 * we were doing.
673c5c4113dSnw141292 	 */
674c5c4113dSnw141292 	*rc = IDMAP_ERR_RETRIABLE_NET_ERR;
675e8c27ec8Sbaban 	if (sid_type != NULL)
676c5c4113dSnw141292 		*sid_type = _IDMAP_T_OTHER;
677e8c27ec8Sbaban 	if (sid != NULL)
678e8c27ec8Sbaban 		*sid = NULL;
679c5c4113dSnw141292 	if (dname != NULL)
680c5c4113dSnw141292 		*dname = NULL;
681c5c4113dSnw141292 	if (rid != NULL)
682c5c4113dSnw141292 		*rid = 0;
68348258c6bSjp151216 	if (dn != NULL)
68448258c6bSjp151216 		*dn = NULL;
68548258c6bSjp151216 	if (attr != NULL)
68648258c6bSjp151216 		*attr = NULL;
68748258c6bSjp151216 	if (value != NULL)
68848258c6bSjp151216 		*value = NULL;
689c5c4113dSnw141292 
690479ac375Sdm199847 	/*
691479ac375Sdm199847 	 * Don't set *canonname to NULL because it may be pointing to the
692479ac375Sdm199847 	 * given winname. Later on if we get a canonical name from AD the
693479ac375Sdm199847 	 * old name if any will be freed before assigning the new name.
694479ac375Sdm199847 	 */
695479ac375Sdm199847 
696c5c4113dSnw141292 	/*
697*2b4a7802SBaban Kenkre 	 * Invoke the mother of all APIs i.e. the adutils API
698c5c4113dSnw141292 	 */
699*2b4a7802SBaban Kenkre 	ad_rc = adutils_lookup_batch_add(state->qs, filter,
700*2b4a7802SBaban Kenkre 	    (const char **)attrs,
701*2b4a7802SBaban Kenkre 	    edomain, &q->result, &q->ad_rc);
702*2b4a7802SBaban Kenkre 	return (map_adrc2idmaprc(ad_rc));
703c5c4113dSnw141292 }
704c5c4113dSnw141292 
705c5c4113dSnw141292 idmap_retcode
706c5c4113dSnw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state,
707e8c27ec8Sbaban 	const char *name, const char *dname, int eunixtype,
70848258c6bSjp151216 	char **dn, char **attr, char **value,
70948258c6bSjp151216 	char **canonname, char **sid, rid_t *rid,
71048258c6bSjp151216 	int *sid_type, char **unixname, idmap_retcode *rc)
711c5c4113dSnw141292 {
712c5c4113dSnw141292 	idmap_retcode	retcode;
713e3c2d6aaSnw141292 	int		len, samAcctNameLen;
714479ac375Sdm199847 	char		*filter = NULL, *s_name;
715cd37da74Snw141292 	char		*ecanonname, *edomain; /* expected canonname */
716c5c4113dSnw141292 
717c5c4113dSnw141292 	/*
718e3c2d6aaSnw141292 	 * Strategy: search the global catalog for user/group by
719e3c2d6aaSnw141292 	 * sAMAccountName = user/groupname with "" as the base DN and by
720e3c2d6aaSnw141292 	 * userPrincipalName = user/groupname@domain.  The result
721e3c2d6aaSnw141292 	 * entries will be checked to conform to the name and domain
722e3c2d6aaSnw141292 	 * name given here.  The DN, sAMAccountName, userPrincipalName,
723e3c2d6aaSnw141292 	 * objectSid and objectClass of the result entries are all we
724e3c2d6aaSnw141292 	 * need to figure out which entries match the lookup, the SID of
725e3c2d6aaSnw141292 	 * the user/group and whether it is a user or a group.
726c5c4113dSnw141292 	 */
727c5c4113dSnw141292 
728c5c4113dSnw141292 	/*
729e3c2d6aaSnw141292 	 * We need the name and the domain name separately and as
730e3c2d6aaSnw141292 	 * name@domain.  We also allow the domain to be provided
731e3c2d6aaSnw141292 	 * separately.
732c5c4113dSnw141292 	 */
733d3a612caSnw141292 	samAcctNameLen = strlen(name);
734e3c2d6aaSnw141292 
735cd37da74Snw141292 	if ((ecanonname = strdup(name)) == NULL)
736e3c2d6aaSnw141292 		return (IDMAP_ERR_MEMORY);
737cd37da74Snw141292 
738cd37da74Snw141292 	if (dname == NULL || *dname == '\0') {
739cd37da74Snw141292 		if ((dname = strchr(name, '@')) != NULL) {
740cd37da74Snw141292 			/* 'name' is qualified with a domain name */
741cd37da74Snw141292 			if ((edomain = strdup(dname + 1)) == NULL) {
742cd37da74Snw141292 				free(ecanonname);
743cd37da74Snw141292 				return (IDMAP_ERR_MEMORY);
744cd37da74Snw141292 			}
745cd37da74Snw141292 			*strchr(ecanonname, '@') = '\0';
746c5c4113dSnw141292 		} else {
747*2b4a7802SBaban Kenkre 			/* 'name' not qualified and dname not given */
748*2b4a7802SBaban Kenkre 			dname = adutils_lookup_batch_getdefdomain(
749*2b4a7802SBaban Kenkre 			    state->qs);
750*2b4a7802SBaban Kenkre 			assert(dname != NULL);
751*2b4a7802SBaban Kenkre 			if (*dname == '\0') {
752cd37da74Snw141292 				free(ecanonname);
753e3c2d6aaSnw141292 				return (IDMAP_ERR_DOMAIN);
754e3c2d6aaSnw141292 			}
755*2b4a7802SBaban 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 
768479ac375Sdm199847 	s_name = sanitize_for_ldap_filter(name);
769479ac375Sdm199847 	if (s_name == NULL) {
770cd37da74Snw141292 		free(ecanonname);
771479ac375Sdm199847 		free(edomain);
772c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
773c5c4113dSnw141292 	}
774479ac375Sdm199847 
775479ac375Sdm199847 	/* Assemble filter */
776479ac375Sdm199847 	len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, s_name) + 1;
777479ac375Sdm199847 	if ((filter = (char *)malloc(len)) == NULL) {
778479ac375Sdm199847 		free(ecanonname);
779479ac375Sdm199847 		free(edomain);
780479ac375Sdm199847 		if (s_name != name)
781479ac375Sdm199847 			free(s_name);
782479ac375Sdm199847 		return (IDMAP_ERR_MEMORY);
783479ac375Sdm199847 	}
784479ac375Sdm199847 	(void) snprintf(filter, len, SANFILTER, samAcctNameLen, s_name);
785479ac375Sdm199847 	if (s_name != name)
786479ac375Sdm199847 		free(s_name);
787c5c4113dSnw141292 
788cd37da74Snw141292 	retcode = idmap_batch_add1(state, filter, ecanonname, edomain,
78948258c6bSjp151216 	    eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type,
79048258c6bSjp151216 	    unixname, rc);
791c5c4113dSnw141292 
792c5c4113dSnw141292 	free(filter);
793c5c4113dSnw141292 
794c5c4113dSnw141292 	return (retcode);
795c5c4113dSnw141292 }
796c5c4113dSnw141292 
797c5c4113dSnw141292 idmap_retcode
798c5c4113dSnw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state,
799e8c27ec8Sbaban 	const char *sid, const rid_t *rid, int eunixtype,
80048258c6bSjp151216 	char **dn, char **attr, char **value,
80148258c6bSjp151216 	char **name, char **dname, int *sid_type,
80248258c6bSjp151216 	char **unixname, idmap_retcode *rc)
803c5c4113dSnw141292 {
804c5c4113dSnw141292 	idmap_retcode	retcode;
805c5c4113dSnw141292 	int		flen, ret;
806c5c4113dSnw141292 	char		*filter = NULL;
807*2b4a7802SBaban Kenkre 	char		cbinsid[ADUTILS_MAXHEXBINSID + 1];
808c5c4113dSnw141292 
809c5c4113dSnw141292 	/*
810c5c4113dSnw141292 	 * Strategy: search [the global catalog] for user/group by
811c5c4113dSnw141292 	 * objectSid = SID with empty base DN.  The DN, sAMAccountName
812c5c4113dSnw141292 	 * and objectClass of the result are all we need to figure out
813c5c4113dSnw141292 	 * the name of the SID and whether it is a user, a group or a
814c5c4113dSnw141292 	 * computer.
815c5c4113dSnw141292 	 */
816c5c4113dSnw141292 
817*2b4a7802SBaban Kenkre 	ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid));
818c5c4113dSnw141292 	if (ret != 0)
819c5c4113dSnw141292 		return (IDMAP_ERR_SID);
820c5c4113dSnw141292 
821c5c4113dSnw141292 	/* Assemble filter */
822e3c2d6aaSnw141292 	flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1;
823c5c4113dSnw141292 	if ((filter = (char *)malloc(flen)) == NULL)
824c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
825e3c2d6aaSnw141292 	(void) snprintf(filter, flen, OBJSIDFILTER, cbinsid);
826c5c4113dSnw141292 
827e8c27ec8Sbaban 	retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype,
82848258c6bSjp151216 	    dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, rc);
829e8c27ec8Sbaban 
830e8c27ec8Sbaban 	free(filter);
831e8c27ec8Sbaban 
832e8c27ec8Sbaban 	return (retcode);
833e8c27ec8Sbaban }
834e8c27ec8Sbaban 
835e8c27ec8Sbaban idmap_retcode
836e8c27ec8Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
837e8c27ec8Sbaban 	const char *unixname, int is_user, int is_wuser,
83848258c6bSjp151216 	char **dn, char **attr, char **value,
83948258c6bSjp151216 	char **sid, rid_t *rid, char **name,
84048258c6bSjp151216 	char **dname, int *sid_type, idmap_retcode *rc)
841e8c27ec8Sbaban {
842e8c27ec8Sbaban 	idmap_retcode	retcode;
843e8c27ec8Sbaban 	int		len, ulen;
844479ac375Sdm199847 	char		*filter = NULL, *s_unixname;
845e8c27ec8Sbaban 	const char	*attrname = NULL;
846e8c27ec8Sbaban 
847e8c27ec8Sbaban 	/* Get unixuser or unixgroup AD attribute name */
848e8c27ec8Sbaban 	attrname = (is_user) ?
849e8c27ec8Sbaban 	    state->ad_unixuser_attr : state->ad_unixgroup_attr;
850e8c27ec8Sbaban 	if (attrname == NULL)
851e8c27ec8Sbaban 		return (IDMAP_ERR_NOTFOUND);
852e8c27ec8Sbaban 
853479ac375Sdm199847 	s_unixname = sanitize_for_ldap_filter(unixname);
854479ac375Sdm199847 	if (s_unixname == NULL)
855479ac375Sdm199847 		return (IDMAP_ERR_MEMORY);
856479ac375Sdm199847 
857e8c27ec8Sbaban 	/*  Assemble filter */
858e8c27ec8Sbaban 	ulen = strlen(unixname);
859e8c27ec8Sbaban 	len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))",
860479ac375Sdm199847 	    is_wuser ? "user" : "group", attrname, ulen, s_unixname) + 1;
861479ac375Sdm199847 	if ((filter = (char *)malloc(len)) == NULL) {
862479ac375Sdm199847 		if (s_unixname != unixname)
863479ac375Sdm199847 			free(s_unixname);
864e8c27ec8Sbaban 		return (IDMAP_ERR_MEMORY);
865479ac375Sdm199847 	}
866e8c27ec8Sbaban 	(void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))",
867479ac375Sdm199847 	    is_wuser ? "user" : "group", attrname, ulen, s_unixname);
868479ac375Sdm199847 	if (s_unixname != unixname)
869479ac375Sdm199847 		free(s_unixname);
870e8c27ec8Sbaban 
871e8c27ec8Sbaban 	retcode = idmap_batch_add1(state, filter, NULL, NULL,
87248258c6bSjp151216 	    _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type,
87348258c6bSjp151216 	    NULL, rc);
87448258c6bSjp151216 
87548258c6bSjp151216 	if (retcode == IDMAP_SUCCESS && attr != NULL) {
87648258c6bSjp151216 		if ((*attr = strdup(attrname)) == NULL)
87748258c6bSjp151216 			retcode = IDMAP_ERR_MEMORY;
87848258c6bSjp151216 	}
87948258c6bSjp151216 
88048258c6bSjp151216 	if (retcode == IDMAP_SUCCESS && value != NULL) {
88148258c6bSjp151216 		if (ulen > 0) {
88248258c6bSjp151216 			if ((*value = strdup(unixname)) == NULL)
88348258c6bSjp151216 				retcode = IDMAP_ERR_MEMORY;
88448258c6bSjp151216 		}
88548258c6bSjp151216 		else
88648258c6bSjp151216 			*value = NULL;
88748258c6bSjp151216 	}
888c5c4113dSnw141292 
889c5c4113dSnw141292 	free(filter);
890c5c4113dSnw141292 
891c5c4113dSnw141292 	return (retcode);
892c5c4113dSnw141292 }
893