xref: /titanic_52/usr/src/cmd/idmap/idmapd/adutils.c (revision e3f2c991a8548408db0a2787bd8b43d5124821d3)
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 /*
231fcced4cSJordan Brown  * Copyright 2009 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"
58*e3f2c991SKeyur Desai #define	UIDNUMBER	"uidNumber"
59*e3f2c991SKeyur Desai #define	GIDNUMBER	"gidNumber"
60*e3f2c991SKeyur Desai #define	UIDNUMBERFILTER	"(&(objectclass=user)(uidNumber=%u))"
61*e3f2c991SKeyur Desai #define	GIDNUMBERFILTER	"(&(objectclass=group)(gidNumber=%u))"
62*e3f2c991SKeyur Desai #define	SANFILTER	"(sAMAccountName=%s)"
63e3c2d6aaSnw141292 #define	OBJSIDFILTER	"(objectSid=%s)"
64c5c4113dSnw141292 
652b4a7802SBaban Kenkre void	idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc,
662b4a7802SBaban Kenkre 		int qid, void *argp);
67c5c4113dSnw141292 
68c5c4113dSnw141292 /*
69c5c4113dSnw141292  * A place to put the results of a batched (async) query
70c5c4113dSnw141292  *
71c5c4113dSnw141292  * There is one of these for every query added to a batch object
72c5c4113dSnw141292  * (idmap_query_state, see below).
73c5c4113dSnw141292  */
74c5c4113dSnw141292 typedef struct idmap_q {
75e3c2d6aaSnw141292 	/*
76e3c2d6aaSnw141292 	 * data used for validating search result entries for name->SID
77e8c27ec8Sbaban 	 * lookups
78e3c2d6aaSnw141292 	 */
79cd37da74Snw141292 	char			*ecanonname;	/* expected canon name */
80cd37da74Snw141292 	char			*edomain;	/* expected domain name */
81e8c27ec8Sbaban 	int			eunixtype;	/* expected unix type */
82e3c2d6aaSnw141292 	/* results */
83cd37da74Snw141292 	char			**canonname;	/* actual canon name */
84c5c4113dSnw141292 	char			**domain;	/* name of domain of object */
85e8c27ec8Sbaban 	char			**sid;		/* stringified SID */
86e8c27ec8Sbaban 	rid_t			*rid;		/* RID */
87e8c27ec8Sbaban 	int			*sid_type;	/* user or group SID? */
88e8c27ec8Sbaban 	char			**unixname;	/* unixname for name mapping */
8948258c6bSjp151216 	char			**dn;		/* DN of entry */
9048258c6bSjp151216 	char			**attr;		/* Attr for name mapping */
9148258c6bSjp151216 	char			**value;	/* value for name mapping */
92*e3f2c991SKeyur Desai 	posix_id_t		*pid;		/* Posix ID found via IDMU */
93c5c4113dSnw141292 	idmap_retcode		*rc;
942b4a7802SBaban Kenkre 	adutils_rc		ad_rc;
952b4a7802SBaban Kenkre 	adutils_result_t	*result;
96e3c2d6aaSnw141292 
97bcced03bSjp151216 	/*
98bcced03bSjp151216 	 * The LDAP search entry result is placed here to be processed
99bcced03bSjp151216 	 * when the search done result is received.
100bcced03bSjp151216 	 */
101bcced03bSjp151216 	LDAPMessage		*search_res;	/* The LDAP search result */
102c5c4113dSnw141292 } idmap_q_t;
103c5c4113dSnw141292 
104c5c4113dSnw141292 /* Batch context structure; typedef is in header file */
105c5c4113dSnw141292 struct idmap_query_state {
1062b4a7802SBaban Kenkre 	adutils_query_state_t	*qs;
1074d61c878SJulian Pullen 	int			qsize;		/* Queue size */
1084d61c878SJulian Pullen 	uint32_t		qcount;		/* Number of queued requests */
109e8c27ec8Sbaban 	const char		*ad_unixuser_attr;
110e8c27ec8Sbaban 	const char		*ad_unixgroup_attr;
111*e3f2c991SKeyur Desai 	int			directory_based_mapping;	/* enum */
112*e3f2c991SKeyur Desai 	char			*default_domain;
113c5c4113dSnw141292 	idmap_q_t		queries[1];	/* array of query results */
114c5c4113dSnw141292 };
115c5c4113dSnw141292 
116651c0131Sbaban static pthread_t	reaperid = 0;
117c5c4113dSnw141292 
118c5c4113dSnw141292 /*
119c5c4113dSnw141292  * Keep connection management simple for now, extend or replace later
120c5c4113dSnw141292  * with updated libsldap code.
121c5c4113dSnw141292  */
122c5c4113dSnw141292 #define	ADREAPERSLEEP	60
123c5c4113dSnw141292 
124c5c4113dSnw141292 /*
125c5c4113dSnw141292  * Idle connection reaping side of connection management
126c5c4113dSnw141292  *
127c5c4113dSnw141292  * Every minute wake up and look for connections that have been idle for
128c5c4113dSnw141292  * five minutes or more and close them.
129c5c4113dSnw141292  */
130c5c4113dSnw141292 /*ARGSUSED*/
131c5c4113dSnw141292 static
132c5c4113dSnw141292 void
133c5c4113dSnw141292 adreaper(void *arg)
134c5c4113dSnw141292 {
135c5c4113dSnw141292 	timespec_t	ts;
136c5c4113dSnw141292 
137c5c4113dSnw141292 	ts.tv_sec = ADREAPERSLEEP;
138c5c4113dSnw141292 	ts.tv_nsec = 0;
139c5c4113dSnw141292 
140c5c4113dSnw141292 	for (;;) {
141c5c4113dSnw141292 		/*
142c5c4113dSnw141292 		 * nanosleep(3RT) is thead-safe (no SIGALRM) and more
143c5c4113dSnw141292 		 * portable than usleep(3C)
144c5c4113dSnw141292 		 */
145c5c4113dSnw141292 		(void) nanosleep(&ts, NULL);
1462b4a7802SBaban Kenkre 		adutils_reap_idle_connections();
147c5c4113dSnw141292 	}
148c5c4113dSnw141292 }
149c5c4113dSnw141292 
150c5c4113dSnw141292 /*
151c5c4113dSnw141292  * Take ad_host_config_t information, create a ad_host_t,
152c5c4113dSnw141292  * populate it and add it to the list of hosts.
153c5c4113dSnw141292  */
154c5c4113dSnw141292 
155c5c4113dSnw141292 int
1562b4a7802SBaban Kenkre idmap_add_ds(adutils_ad_t *ad, const char *host, int port)
157c5c4113dSnw141292 {
158c5c4113dSnw141292 	int	ret = -1;
159c5c4113dSnw141292 
1602b4a7802SBaban Kenkre 	if (adutils_add_ds(ad, host, port) == ADUTILS_SUCCESS)
161c8e26105Sjp151216 		ret = 0;
162c5c4113dSnw141292 
163c5c4113dSnw141292 	/* Start reaper if it doesn't exist */
1642b4a7802SBaban Kenkre 	if (ret == 0 && reaperid == 0)
165c5c4113dSnw141292 		(void) pthread_create(&reaperid, NULL,
166c5c4113dSnw141292 		    (void *(*)(void *))adreaper, (void *)NULL);
167c5c4113dSnw141292 	return (ret);
168c5c4113dSnw141292 }
169c5c4113dSnw141292 
170c5c4113dSnw141292 static
1712b4a7802SBaban Kenkre idmap_retcode
1722b4a7802SBaban Kenkre map_adrc2idmaprc(adutils_rc adrc)
173c5c4113dSnw141292 {
1742b4a7802SBaban Kenkre 	switch (adrc) {
1752b4a7802SBaban Kenkre 	case ADUTILS_SUCCESS:
1762b4a7802SBaban Kenkre 		return (IDMAP_SUCCESS);
1772b4a7802SBaban Kenkre 	case ADUTILS_ERR_NOTFOUND:
1782b4a7802SBaban Kenkre 		return (IDMAP_ERR_NOTFOUND);
1792b4a7802SBaban Kenkre 	case ADUTILS_ERR_MEMORY:
1802b4a7802SBaban Kenkre 		return (IDMAP_ERR_MEMORY);
1812b4a7802SBaban Kenkre 	case ADUTILS_ERR_DOMAIN:
1822b4a7802SBaban Kenkre 		return (IDMAP_ERR_DOMAIN);
1832b4a7802SBaban Kenkre 	case ADUTILS_ERR_OTHER:
1842b4a7802SBaban Kenkre 		return (IDMAP_ERR_OTHER);
1852b4a7802SBaban Kenkre 	case ADUTILS_ERR_RETRIABLE_NET_ERR:
1862b4a7802SBaban Kenkre 		return (IDMAP_ERR_RETRIABLE_NET_ERR);
1872b4a7802SBaban Kenkre 	default:
1882b4a7802SBaban Kenkre 		return (IDMAP_ERR_INTERNAL);
189c5c4113dSnw141292 	}
1902b4a7802SBaban Kenkre 	/* NOTREACHED */
191c5c4113dSnw141292 }
192c5c4113dSnw141292 
193c5c4113dSnw141292 idmap_retcode
1942b4a7802SBaban Kenkre idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
195*e3f2c991SKeyur Desai 	int directory_based_mapping, const char *default_domain,
1962b4a7802SBaban Kenkre 	idmap_query_state_t **state)
197c5c4113dSnw141292 {
198c5c4113dSnw141292 	idmap_query_state_t	*new_state;
1992b4a7802SBaban Kenkre 	adutils_rc		rc;
200c5c4113dSnw141292 
201c5c4113dSnw141292 	*state = NULL;
202c5c4113dSnw141292 
2034d61c878SJulian Pullen 	assert(ad != NULL);
204c5c4113dSnw141292 
205c5c4113dSnw141292 	new_state = calloc(1, sizeof (idmap_query_state_t) +
206c5c4113dSnw141292 	    (nqueries - 1) * sizeof (idmap_q_t));
207c5c4113dSnw141292 	if (new_state == NULL)
208c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
209c5c4113dSnw141292 
2102b4a7802SBaban Kenkre 	if ((rc = adutils_lookup_batch_start(ad, nqueries,
2112b4a7802SBaban Kenkre 	    idmap_ldap_res_search_cb, new_state, &new_state->qs))
2122b4a7802SBaban Kenkre 	    != ADUTILS_SUCCESS) {
213*e3f2c991SKeyur Desai 		idmap_lookup_release_batch(&new_state);
2142b4a7802SBaban Kenkre 		return (map_adrc2idmaprc(rc));
2152b4a7802SBaban Kenkre 	}
2162b4a7802SBaban Kenkre 
217*e3f2c991SKeyur Desai 	new_state->default_domain = strdup(default_domain);
218*e3f2c991SKeyur Desai 	if (new_state->default_domain == NULL) {
219*e3f2c991SKeyur Desai 		idmap_lookup_release_batch(&new_state);
220*e3f2c991SKeyur Desai 		return (IDMAP_ERR_MEMORY);
221*e3f2c991SKeyur Desai 	}
222*e3f2c991SKeyur Desai 
223*e3f2c991SKeyur Desai 	new_state->directory_based_mapping = directory_based_mapping;
2244d61c878SJulian Pullen 	new_state->qsize = nqueries;
225c5c4113dSnw141292 	*state = new_state;
226c5c4113dSnw141292 	return (IDMAP_SUCCESS);
227c5c4113dSnw141292 }
228c5c4113dSnw141292 
229c5c4113dSnw141292 /*
230e8c27ec8Sbaban  * Set unixuser_attr and unixgroup_attr for AD-based name mapping
231e8c27ec8Sbaban  */
232e8c27ec8Sbaban void
233e8c27ec8Sbaban idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
2344edd44c5Sjp151216 		const char *unixuser_attr, const char *unixgroup_attr)
2354edd44c5Sjp151216 {
236e8c27ec8Sbaban 	state->ad_unixuser_attr = unixuser_attr;
237e8c27ec8Sbaban 	state->ad_unixgroup_attr = unixgroup_attr;
238e8c27ec8Sbaban }
239e8c27ec8Sbaban 
240e8c27ec8Sbaban /*
241cd37da74Snw141292  * Take parsed attribute values from a search result entry and check if
242cd37da74Snw141292  * it is the result that was desired and, if so, set the result fields
243cd37da74Snw141292  * of the given idmap_q_t.
244cd37da74Snw141292  *
245*e3f2c991SKeyur Desai  * Except for dn and attr, all strings are consumed, either by transferring
246*e3f2c991SKeyur Desai  * them over into the request results (where the caller will eventually free
247*e3f2c991SKeyur Desai  * them) or by freeing them here.  Note that this aligns with the "const"
248*e3f2c991SKeyur Desai  * declarations below.
249c5c4113dSnw141292  */
250c5c4113dSnw141292 static
251cd37da74Snw141292 void
252*e3f2c991SKeyur Desai idmap_setqresults(
253*e3f2c991SKeyur Desai     idmap_q_t *q,
254*e3f2c991SKeyur Desai     char *san,
255*e3f2c991SKeyur Desai     const char *dn,
256*e3f2c991SKeyur Desai     const char *attr,
257*e3f2c991SKeyur Desai     char *value,
258*e3f2c991SKeyur Desai     char *sid,
259*e3f2c991SKeyur Desai     rid_t rid,
260*e3f2c991SKeyur Desai     int sid_type,
261*e3f2c991SKeyur Desai     char *unixname,
262*e3f2c991SKeyur Desai     posix_id_t pid)
263c5c4113dSnw141292 {
264cd37da74Snw141292 	char *domain;
2651fcced4cSJordan Brown 	int err1;
266cd37da74Snw141292 
267cd37da74Snw141292 	assert(dn != NULL);
268cd37da74Snw141292 
2692b4a7802SBaban Kenkre 	if ((domain = adutils_dn2dns(dn)) == NULL)
270cd37da74Snw141292 		goto out;
271cd37da74Snw141292 
272e8c27ec8Sbaban 	if (q->ecanonname != NULL && san != NULL) {
273e8c27ec8Sbaban 		/* Check that this is the canonname that we were looking for */
274cd37da74Snw141292 		if (u8_strcmp(q->ecanonname, san, 0,
275cd37da74Snw141292 		    U8_STRCMP_CI_LOWER, /* no normalization, for now */
276e8c27ec8Sbaban 		    U8_UNICODE_LATEST, &err1) != 0 || err1 != 0)
277e8c27ec8Sbaban 			goto out;
278e8c27ec8Sbaban 	}
279e8c27ec8Sbaban 
280e8c27ec8Sbaban 	if (q->edomain != NULL) {
281e8c27ec8Sbaban 		/* Check that this is the domain that we were looking for */
2821fcced4cSJordan Brown 		if (!domain_eq(q->edomain, domain))
283cd37da74Snw141292 			goto out;
284e8c27ec8Sbaban 	}
285cd37da74Snw141292 
28648258c6bSjp151216 	/* Copy the DN and attr and value */
28748258c6bSjp151216 	if (q->dn != NULL)
28848258c6bSjp151216 		*q->dn = strdup(dn);
28948258c6bSjp151216 
29048258c6bSjp151216 	if (q->attr != NULL && attr != NULL)
29148258c6bSjp151216 		*q->attr = strdup(attr);
29248258c6bSjp151216 
293*e3f2c991SKeyur Desai 	if (q->value != NULL && value != NULL) {
294*e3f2c991SKeyur Desai 		*q->value = value;
295*e3f2c991SKeyur Desai 		value = NULL;
296*e3f2c991SKeyur Desai 	}
29748258c6bSjp151216 
298e8c27ec8Sbaban 	/* Set results */
299e8c27ec8Sbaban 	if (q->sid) {
300e8c27ec8Sbaban 		*q->sid = sid;
301cd37da74Snw141292 		sid = NULL;
302e8c27ec8Sbaban 	}
303e8c27ec8Sbaban 	if (q->rid)
304e8c27ec8Sbaban 		*q->rid = rid;
305e8c27ec8Sbaban 	if (q->sid_type)
306cd37da74Snw141292 		*q->sid_type = sid_type;
307e8c27ec8Sbaban 	if (q->unixname) {
308e8c27ec8Sbaban 		*q->unixname = unixname;
309e8c27ec8Sbaban 		unixname = NULL;
310e8c27ec8Sbaban 	}
311cd37da74Snw141292 	if (q->domain != NULL) {
312cd37da74Snw141292 		*q->domain = domain;
313cd37da74Snw141292 		domain = NULL;
314e8c27ec8Sbaban 	}
315e8c27ec8Sbaban 	if (q->canonname != NULL) {
316479ac375Sdm199847 		/*
317479ac375Sdm199847 		 * The caller may be replacing the given winname by its
318479ac375Sdm199847 		 * canonical name and therefore free any old name before
319479ac375Sdm199847 		 * overwriting the field by the canonical name.
320479ac375Sdm199847 		 */
321479ac375Sdm199847 		free(*q->canonname);
322e8c27ec8Sbaban 		*q->canonname = san;
323cd37da74Snw141292 		san = NULL;
324cd37da74Snw141292 	}
325cd37da74Snw141292 
326*e3f2c991SKeyur Desai 	if (q->pid != NULL && pid != SENTINEL_PID) {
327*e3f2c991SKeyur Desai 		*q->pid = pid;
328*e3f2c991SKeyur Desai 	}
329*e3f2c991SKeyur Desai 
3302b4a7802SBaban Kenkre 	q->ad_rc = ADUTILS_SUCCESS;
331cd37da74Snw141292 
332cd37da74Snw141292 out:
333cd37da74Snw141292 	/* Free unused attribute values */
334cd37da74Snw141292 	free(san);
335cd37da74Snw141292 	free(sid);
336cd37da74Snw141292 	free(domain);
337e8c27ec8Sbaban 	free(unixname);
338*e3f2c991SKeyur Desai 	free(value);
339c5c4113dSnw141292 }
340c5c4113dSnw141292 
341c5c4113dSnw141292 #define	BVAL_CASEEQ(bv, str) \
342c5c4113dSnw141292 		(((*(bv))->bv_len == (sizeof (str) - 1)) && \
343c5c4113dSnw141292 		    strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0)
344c5c4113dSnw141292 
345c5c4113dSnw141292 /*
346cd37da74Snw141292  * Extract the class of the result entry.  Returns 1 on success, 0 on
347cd37da74Snw141292  * failure.
348c5c4113dSnw141292  */
349c5c4113dSnw141292 static
350e3c2d6aaSnw141292 int
351cd37da74Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type)
352c5c4113dSnw141292 {
353c5c4113dSnw141292 	BerValue	**cbval;
354c5c4113dSnw141292 
355cd37da74Snw141292 	*sid_type = _IDMAP_T_OTHER;
356c5c4113dSnw141292 	if (bvalues == NULL)
357e3c2d6aaSnw141292 		return (0);
358c5c4113dSnw141292 
359cd37da74Snw141292 	/*
360*e3f2c991SKeyur Desai 	 * We consider Computer to be a subclass of User, so we can just
361*e3f2c991SKeyur Desai 	 * ignore Computer entries and pay attention to the accompanying
362*e3f2c991SKeyur Desai 	 * User entries.
363cd37da74Snw141292 	 */
364c5c4113dSnw141292 	for (cbval = bvalues; *cbval != NULL; cbval++) {
365*e3f2c991SKeyur Desai 		if (BVAL_CASEEQ(cbval, "group")) {
366cd37da74Snw141292 			*sid_type = _IDMAP_T_GROUP;
367cd37da74Snw141292 			break;
368*e3f2c991SKeyur Desai 		} else if (BVAL_CASEEQ(cbval, "user")) {
369cd37da74Snw141292 			*sid_type = _IDMAP_T_USER;
370*e3f2c991SKeyur Desai 			break;
371cd37da74Snw141292 		}
372cd37da74Snw141292 		/*
373cd37da74Snw141292 		 * "else if (*sid_type = _IDMAP_T_USER)" then this is a
374cd37da74Snw141292 		 * new sub-class of user -- what to do with it??
375cd37da74Snw141292 		 */
376c5c4113dSnw141292 	}
377e3c2d6aaSnw141292 
378e3c2d6aaSnw141292 	return (1);
379c5c4113dSnw141292 }
380c5c4113dSnw141292 
381c5c4113dSnw141292 /*
382c5c4113dSnw141292  * Handle a given search result entry
383c5c4113dSnw141292  */
384c5c4113dSnw141292 static
385c5c4113dSnw141292 void
3862b4a7802SBaban Kenkre idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q,
3872b4a7802SBaban Kenkre 	LDAPMessage *res, LDAP *ld)
388c5c4113dSnw141292 {
389c5c4113dSnw141292 	BerValue		**bvalues;
390*e3f2c991SKeyur Desai 	const char		*attr = NULL;
391*e3f2c991SKeyur Desai 	char			*value = NULL;
392*e3f2c991SKeyur Desai 	char			*unix_name = NULL;
393*e3f2c991SKeyur Desai 	char			*dn;
394cd37da74Snw141292 	char			*san = NULL;
395cd37da74Snw141292 	char			*sid = NULL;
396cd37da74Snw141292 	rid_t			rid = 0;
397*e3f2c991SKeyur Desai 	int			sid_type;
398*e3f2c991SKeyur Desai 	int			ok;
399*e3f2c991SKeyur Desai 	posix_id_t		pid = SENTINEL_PID;
400e3c2d6aaSnw141292 
401e8c27ec8Sbaban 	assert(q->rc != NULL);
402*e3f2c991SKeyur Desai 	assert(q->domain == NULL || *q->domain == NULL);
403e8c27ec8Sbaban 
4042b4a7802SBaban Kenkre 	if ((dn = ldap_get_dn(ld, res)) == NULL)
405c5c4113dSnw141292 		return;
406c5c4113dSnw141292 
407*e3f2c991SKeyur Desai 	bvalues = ldap_get_values_len(ld, res, OBJCLASS);
408*e3f2c991SKeyur Desai 	if (bvalues == NULL) {
409e8c27ec8Sbaban 		/*
410e8c27ec8Sbaban 		 * Didn't find objectclass. Something's wrong with our
411e8c27ec8Sbaban 		 * AD data.
412e8c27ec8Sbaban 		 */
413*e3f2c991SKeyur Desai 		idmapdlog(LOG_ERR, "%s has no %s", dn, OBJCLASS);
414*e3f2c991SKeyur Desai 		goto out;
415*e3f2c991SKeyur Desai 	}
416*e3f2c991SKeyur Desai 	ok = idmap_bv_objclass2sidtype(bvalues, &sid_type);
417*e3f2c991SKeyur Desai 	ldap_value_free_len(bvalues);
418*e3f2c991SKeyur Desai 	if (!ok) {
419e8c27ec8Sbaban 		/*
420*e3f2c991SKeyur Desai 		 * Didn't understand objectclass. Something's wrong with our
421*e3f2c991SKeyur Desai 		 * AD data.
422e8c27ec8Sbaban 		 */
423*e3f2c991SKeyur Desai 		idmapdlog(LOG_ERR, "%s has unexpected %s", dn, OBJCLASS);
424*e3f2c991SKeyur Desai 		goto out;
425e8c27ec8Sbaban 	}
426e8c27ec8Sbaban 
427*e3f2c991SKeyur Desai 	if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU &&
428*e3f2c991SKeyur Desai 	    q->pid != NULL) {
429*e3f2c991SKeyur Desai 		if (sid_type == _IDMAP_T_USER)
430*e3f2c991SKeyur Desai 			attr = UIDNUMBER;
431*e3f2c991SKeyur Desai 		else if (sid_type == _IDMAP_T_GROUP)
432*e3f2c991SKeyur Desai 			attr = GIDNUMBER;
433*e3f2c991SKeyur Desai 		if (attr != NULL) {
434*e3f2c991SKeyur Desai 			bvalues = ldap_get_values_len(ld, res, attr);
435*e3f2c991SKeyur Desai 			if (bvalues != NULL) {
436*e3f2c991SKeyur Desai 				value = adutils_bv_str(bvalues[0]);
437*e3f2c991SKeyur Desai 				if (!adutils_bv_uint(bvalues[0], &pid)) {
438*e3f2c991SKeyur Desai 					idmapdlog(LOG_ERR,
439*e3f2c991SKeyur Desai 					    "%s has Invalid %s value \"%s\"",
440*e3f2c991SKeyur Desai 					    dn, attr, value);
441*e3f2c991SKeyur Desai 				}
442*e3f2c991SKeyur Desai 				ldap_value_free_len(bvalues);
443*e3f2c991SKeyur Desai 			}
444*e3f2c991SKeyur Desai 		}
445*e3f2c991SKeyur Desai 	}
446c5c4113dSnw141292 
447*e3f2c991SKeyur Desai 	if (state->directory_based_mapping == DIRECTORY_MAPPING_NAME &&
448*e3f2c991SKeyur Desai 	    q->unixname != NULL) {
449*e3f2c991SKeyur Desai 		/*
450*e3f2c991SKeyur Desai 		 * If the caller has requested unixname then determine the
451*e3f2c991SKeyur Desai 		 * AD attribute name that will have the unixname, and retrieve
452*e3f2c991SKeyur Desai 		 * its value.
453*e3f2c991SKeyur Desai 		 */
454*e3f2c991SKeyur Desai 		int unix_type;
455*e3f2c991SKeyur Desai 		/*
456*e3f2c991SKeyur Desai 		 * Determine the target UNIX type.
457*e3f2c991SKeyur Desai 		 *
458*e3f2c991SKeyur Desai 		 * If the caller specified one, use that.  Otherwise, give the
459*e3f2c991SKeyur Desai 		 * same type that as we found for the Windows user.
460*e3f2c991SKeyur Desai 		 */
461*e3f2c991SKeyur Desai 		unix_type = q->eunixtype;
462*e3f2c991SKeyur Desai 		if (unix_type == _IDMAP_T_UNDEF) {
463*e3f2c991SKeyur Desai 			if (sid_type == _IDMAP_T_USER)
464*e3f2c991SKeyur Desai 				unix_type = _IDMAP_T_USER;
465*e3f2c991SKeyur Desai 			else if (sid_type == _IDMAP_T_GROUP)
466*e3f2c991SKeyur Desai 				unix_type = _IDMAP_T_GROUP;
467*e3f2c991SKeyur Desai 		}
468*e3f2c991SKeyur Desai 
469*e3f2c991SKeyur Desai 		if (unix_type == _IDMAP_T_USER)
470*e3f2c991SKeyur Desai 			attr = state->ad_unixuser_attr;
471*e3f2c991SKeyur Desai 		else if (unix_type == _IDMAP_T_GROUP)
472*e3f2c991SKeyur Desai 			attr = state->ad_unixgroup_attr;
473*e3f2c991SKeyur Desai 
474*e3f2c991SKeyur Desai 		if (attr != NULL) {
475*e3f2c991SKeyur Desai 			bvalues = ldap_get_values_len(ld, res, attr);
476*e3f2c991SKeyur Desai 			if (bvalues != NULL) {
477*e3f2c991SKeyur Desai 				unix_name = adutils_bv_str(bvalues[0]);
478*e3f2c991SKeyur Desai 				ldap_value_free_len(bvalues);
479*e3f2c991SKeyur Desai 				value = strdup(unix_name);
480*e3f2c991SKeyur Desai 			}
481*e3f2c991SKeyur Desai 		}
482*e3f2c991SKeyur Desai 	}
483*e3f2c991SKeyur Desai 
484*e3f2c991SKeyur Desai 	bvalues = ldap_get_values_len(ld, res, SAN);
485*e3f2c991SKeyur Desai 	if (bvalues != NULL) {
486*e3f2c991SKeyur Desai 		san = adutils_bv_str(bvalues[0]);
487*e3f2c991SKeyur Desai 		ldap_value_free_len(bvalues);
488*e3f2c991SKeyur Desai 	}
489*e3f2c991SKeyur Desai 
490*e3f2c991SKeyur Desai 	if (q->sid != NULL) {
491*e3f2c991SKeyur Desai 		bvalues = ldap_get_values_len(ld, res, OBJSID);
492*e3f2c991SKeyur Desai 		if (bvalues != NULL) {
493*e3f2c991SKeyur Desai 			sid = adutils_bv_objsid2sidstr(bvalues[0], &rid);
494*e3f2c991SKeyur Desai 			ldap_value_free_len(bvalues);
495*e3f2c991SKeyur Desai 		}
496*e3f2c991SKeyur Desai 	}
497*e3f2c991SKeyur Desai 
498*e3f2c991SKeyur Desai 	idmap_setqresults(q, san, dn,
499*e3f2c991SKeyur Desai 	    attr, value,
500*e3f2c991SKeyur Desai 	    sid, rid, sid_type,
501*e3f2c991SKeyur Desai 	    unix_name, pid);
502*e3f2c991SKeyur Desai 
503*e3f2c991SKeyur Desai out:
504c5c4113dSnw141292 	ldap_memfree(dn);
505c5c4113dSnw141292 }
506c5c4113dSnw141292 
5072b4a7802SBaban Kenkre void
5082b4a7802SBaban Kenkre idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid,
5092b4a7802SBaban Kenkre 		void *argp)
510c5c4113dSnw141292 {
5112b4a7802SBaban Kenkre 	idmap_query_state_t	*state = (idmap_query_state_t *)argp;
5122b4a7802SBaban Kenkre 	idmap_q_t		*q = &(state->queries[qid]);
513c5c4113dSnw141292 
514c5c4113dSnw141292 	switch (rc) {
515c5c4113dSnw141292 	case LDAP_RES_SEARCH_RESULT:
5162b4a7802SBaban Kenkre 		if (q->search_res != NULL) {
5172b4a7802SBaban Kenkre 			idmap_extract_object(state, q, q->search_res, ld);
5182b4a7802SBaban Kenkre 			(void) ldap_msgfree(q->search_res);
5192b4a7802SBaban Kenkre 			q->search_res = NULL;
520bcced03bSjp151216 		} else
5212b4a7802SBaban Kenkre 			q->ad_rc = ADUTILS_ERR_NOTFOUND;
522c5c4113dSnw141292 		break;
523c5c4113dSnw141292 	case LDAP_RES_SEARCH_ENTRY:
5242b4a7802SBaban Kenkre 		if (q->search_res == NULL) {
5252b4a7802SBaban Kenkre 			q->search_res = *res;
5262b4a7802SBaban Kenkre 			*res = NULL;
527bcced03bSjp151216 		}
528c5c4113dSnw141292 		break;
529c5c4113dSnw141292 	default:
530c5c4113dSnw141292 		break;
531c5c4113dSnw141292 	}
53284decf41Sjp151216 }
53384decf41Sjp151216 
534e3c2d6aaSnw141292 static
535e3c2d6aaSnw141292 void
536e3c2d6aaSnw141292 idmap_cleanup_batch(idmap_query_state_t *batch)
537e3c2d6aaSnw141292 {
538e3c2d6aaSnw141292 	int i;
539e3c2d6aaSnw141292 
540e3c2d6aaSnw141292 	for (i = 0; i < batch->qcount; i++) {
541cd37da74Snw141292 		if (batch->queries[i].ecanonname != NULL)
542cd37da74Snw141292 			free(batch->queries[i].ecanonname);
543cd37da74Snw141292 		batch->queries[i].ecanonname = NULL;
544cd37da74Snw141292 		if (batch->queries[i].edomain != NULL)
545cd37da74Snw141292 			free(batch->queries[i].edomain);
546cd37da74Snw141292 		batch->queries[i].edomain = NULL;
547e3c2d6aaSnw141292 	}
548e3c2d6aaSnw141292 }
549e3c2d6aaSnw141292 
55084decf41Sjp151216 /*
55184decf41Sjp151216  * This routine frees the idmap_query_state_t structure
55284decf41Sjp151216  */
553c5c4113dSnw141292 void
55484decf41Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state)
555c5c4113dSnw141292 {
5562b4a7802SBaban Kenkre 	if (state == NULL || *state == NULL)
5572b4a7802SBaban Kenkre 		return;
5582b4a7802SBaban Kenkre 	adutils_lookup_batch_release(&(*state)->qs);
559e3c2d6aaSnw141292 	idmap_cleanup_batch(*state);
560*e3f2c991SKeyur Desai 	free((*state)->default_domain);
561c5c4113dSnw141292 	free(*state);
562c5c4113dSnw141292 	*state = NULL;
563c5c4113dSnw141292 }
564c5c4113dSnw141292 
565c5c4113dSnw141292 idmap_retcode
5660dcc7149Snw141292 idmap_lookup_batch_end(idmap_query_state_t **state)
567c5c4113dSnw141292 {
5682b4a7802SBaban Kenkre 	adutils_rc		ad_rc;
5692b4a7802SBaban Kenkre 	int			i;
5702b4a7802SBaban Kenkre 	idmap_query_state_t	*id_qs = *state;
571c5c4113dSnw141292 
5722b4a7802SBaban Kenkre 	ad_rc = adutils_lookup_batch_end(&id_qs->qs);
573c5c4113dSnw141292 
5742b4a7802SBaban Kenkre 	/*
5752b4a7802SBaban Kenkre 	 * Map adutils rc to idmap_retcode in each
5762b4a7802SBaban Kenkre 	 * query because consumers in dbutils.c
5772b4a7802SBaban Kenkre 	 * expects idmap_retcode.
5782b4a7802SBaban Kenkre 	 */
5792b4a7802SBaban Kenkre 	for (i = 0; i < id_qs->qcount; i++) {
5802b4a7802SBaban Kenkre 		*id_qs->queries[i].rc =
5812b4a7802SBaban Kenkre 		    map_adrc2idmaprc(id_qs->queries[i].ad_rc);
582c5c4113dSnw141292 	}
58384decf41Sjp151216 	idmap_lookup_release_batch(state);
5842b4a7802SBaban Kenkre 	return (map_adrc2idmaprc(ad_rc));
585c5c4113dSnw141292 }
586c5c4113dSnw141292 
587c5c4113dSnw141292 /*
588c5c4113dSnw141292  * Send one prepared search, queue up msgid, process what results are
589c5c4113dSnw141292  * available
590c5c4113dSnw141292  */
591c5c4113dSnw141292 static
592c5c4113dSnw141292 idmap_retcode
59348258c6bSjp151216 idmap_batch_add1(idmap_query_state_t *state, const char *filter,
59448258c6bSjp151216 	char *ecanonname, char *edomain, int eunixtype,
59548258c6bSjp151216 	char **dn, char **attr, char **value,
59648258c6bSjp151216 	char **canonname, char **dname,
59748258c6bSjp151216 	char **sid, rid_t *rid, int *sid_type, char **unixname,
598*e3f2c991SKeyur Desai 	posix_id_t *pid,
59948258c6bSjp151216 	idmap_retcode *rc)
600c5c4113dSnw141292 {
6012b4a7802SBaban Kenkre 	adutils_rc	ad_rc;
6022b4a7802SBaban Kenkre 	int		qid, i;
603c5c4113dSnw141292 	idmap_q_t	*q;
604*e3f2c991SKeyur Desai 	char	*attrs[20];	/* Plenty */
605c5c4113dSnw141292 
6064d61c878SJulian Pullen 	qid = atomic_inc_32_nv(&state->qcount) - 1;
607c5c4113dSnw141292 	q = &(state->queries[qid]);
608c5c4113dSnw141292 
6094d61c878SJulian Pullen 	assert(qid < state->qsize);
6104d61c878SJulian Pullen 
611cd37da74Snw141292 	/*
6122b4a7802SBaban Kenkre 	 * Remember the expected canonname, domainname and unix type
6132b4a7802SBaban Kenkre 	 * so we can check the results * against it
614cd37da74Snw141292 	 */
615cd37da74Snw141292 	q->ecanonname = ecanonname;
616cd37da74Snw141292 	q->edomain = edomain;
617e8c27ec8Sbaban 	q->eunixtype = eunixtype;
618e3c2d6aaSnw141292 
619c5c4113dSnw141292 	/* Remember where to put the results */
620cd37da74Snw141292 	q->canonname = canonname;
621e8c27ec8Sbaban 	q->sid = sid;
622c5c4113dSnw141292 	q->domain = dname;
623c5c4113dSnw141292 	q->rid = rid;
624c5c4113dSnw141292 	q->sid_type = sid_type;
625c5c4113dSnw141292 	q->rc = rc;
626e8c27ec8Sbaban 	q->unixname = unixname;
62748258c6bSjp151216 	q->dn = dn;
62848258c6bSjp151216 	q->attr = attr;
62948258c6bSjp151216 	q->value = value;
630*e3f2c991SKeyur Desai 	q->pid = pid;
631e8c27ec8Sbaban 
632*e3f2c991SKeyur Desai 	/* Add attributes that are not always needed */
633*e3f2c991SKeyur Desai 	i = 0;
634*e3f2c991SKeyur Desai 	attrs[i++] = SAN;
635*e3f2c991SKeyur Desai 	attrs[i++] = OBJSID;
636*e3f2c991SKeyur Desai 	attrs[i++] = OBJCLASS;
637*e3f2c991SKeyur Desai 
638e8c27ec8Sbaban 	if (unixname != NULL) {
639*e3f2c991SKeyur Desai 		/* Add unixuser/unixgroup attribute names to the attrs list */
640e8c27ec8Sbaban 		if (eunixtype != _IDMAP_T_GROUP &&
641e8c27ec8Sbaban 		    state->ad_unixuser_attr != NULL)
642e8c27ec8Sbaban 			attrs[i++] = (char *)state->ad_unixuser_attr;
643e8c27ec8Sbaban 		if (eunixtype != _IDMAP_T_USER &&
644e8c27ec8Sbaban 		    state->ad_unixgroup_attr != NULL)
645*e3f2c991SKeyur Desai 			attrs[i++] = (char *)state->ad_unixgroup_attr;
646e8c27ec8Sbaban 	}
647c5c4113dSnw141292 
648*e3f2c991SKeyur Desai 	if (pid != NULL) {
649*e3f2c991SKeyur Desai 		if (eunixtype != _IDMAP_T_GROUP)
650*e3f2c991SKeyur Desai 			attrs[i++] = UIDNUMBER;
651*e3f2c991SKeyur Desai 		if (eunixtype != _IDMAP_T_USER)
652*e3f2c991SKeyur Desai 			attrs[i++] = GIDNUMBER;
653*e3f2c991SKeyur Desai 	}
654*e3f2c991SKeyur Desai 
655*e3f2c991SKeyur Desai 	attrs[i] = NULL;
656*e3f2c991SKeyur Desai 
657c5c4113dSnw141292 	/*
658c5c4113dSnw141292 	 * Provide sane defaults for the results in case we never hear
659c5c4113dSnw141292 	 * back from the DS before closing the connection.
660e3c2d6aaSnw141292 	 *
661e3c2d6aaSnw141292 	 * In particular we default the result to indicate a retriable
662e3c2d6aaSnw141292 	 * error.  The first complete matching result entry will cause
663e3c2d6aaSnw141292 	 * this to be set to IDMAP_SUCCESS, and the end of the results
664e3c2d6aaSnw141292 	 * for this search will cause this to indicate "not found" if no
665e3c2d6aaSnw141292 	 * result entries arrived or no complete ones matched the lookup
666e3c2d6aaSnw141292 	 * we were doing.
667c5c4113dSnw141292 	 */
668c5c4113dSnw141292 	*rc = IDMAP_ERR_RETRIABLE_NET_ERR;
669e8c27ec8Sbaban 	if (sid_type != NULL)
670c5c4113dSnw141292 		*sid_type = _IDMAP_T_OTHER;
671e8c27ec8Sbaban 	if (sid != NULL)
672e8c27ec8Sbaban 		*sid = NULL;
673c5c4113dSnw141292 	if (dname != NULL)
674c5c4113dSnw141292 		*dname = NULL;
675c5c4113dSnw141292 	if (rid != NULL)
676c5c4113dSnw141292 		*rid = 0;
67748258c6bSjp151216 	if (dn != NULL)
67848258c6bSjp151216 		*dn = NULL;
67948258c6bSjp151216 	if (attr != NULL)
68048258c6bSjp151216 		*attr = NULL;
68148258c6bSjp151216 	if (value != NULL)
68248258c6bSjp151216 		*value = NULL;
683c5c4113dSnw141292 
684479ac375Sdm199847 	/*
685479ac375Sdm199847 	 * Don't set *canonname to NULL because it may be pointing to the
686479ac375Sdm199847 	 * given winname. Later on if we get a canonical name from AD the
687479ac375Sdm199847 	 * old name if any will be freed before assigning the new name.
688479ac375Sdm199847 	 */
689479ac375Sdm199847 
690c5c4113dSnw141292 	/*
6912b4a7802SBaban Kenkre 	 * Invoke the mother of all APIs i.e. the adutils API
692c5c4113dSnw141292 	 */
6932b4a7802SBaban Kenkre 	ad_rc = adutils_lookup_batch_add(state->qs, filter,
6942b4a7802SBaban Kenkre 	    (const char **)attrs,
6952b4a7802SBaban Kenkre 	    edomain, &q->result, &q->ad_rc);
6962b4a7802SBaban Kenkre 	return (map_adrc2idmaprc(ad_rc));
697c5c4113dSnw141292 }
698c5c4113dSnw141292 
699c5c4113dSnw141292 idmap_retcode
700c5c4113dSnw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state,
701e8c27ec8Sbaban 	const char *name, const char *dname, int eunixtype,
70248258c6bSjp151216 	char **dn, char **attr, char **value,
70348258c6bSjp151216 	char **canonname, char **sid, rid_t *rid,
704*e3f2c991SKeyur Desai 	int *sid_type, char **unixname,
705*e3f2c991SKeyur Desai 	posix_id_t *pid, idmap_retcode *rc)
706c5c4113dSnw141292 {
707c5c4113dSnw141292 	idmap_retcode	retcode;
708*e3f2c991SKeyur Desai 	char		*filter, *s_name;
709cd37da74Snw141292 	char		*ecanonname, *edomain; /* expected canonname */
710c5c4113dSnw141292 
711c5c4113dSnw141292 	/*
712e3c2d6aaSnw141292 	 * Strategy: search the global catalog for user/group by
713e3c2d6aaSnw141292 	 * sAMAccountName = user/groupname with "" as the base DN and by
714e3c2d6aaSnw141292 	 * userPrincipalName = user/groupname@domain.  The result
715e3c2d6aaSnw141292 	 * entries will be checked to conform to the name and domain
716e3c2d6aaSnw141292 	 * name given here.  The DN, sAMAccountName, userPrincipalName,
717e3c2d6aaSnw141292 	 * objectSid and objectClass of the result entries are all we
718e3c2d6aaSnw141292 	 * need to figure out which entries match the lookup, the SID of
719e3c2d6aaSnw141292 	 * the user/group and whether it is a user or a group.
720c5c4113dSnw141292 	 */
721c5c4113dSnw141292 
722cd37da74Snw141292 	if ((ecanonname = strdup(name)) == NULL)
723e3c2d6aaSnw141292 		return (IDMAP_ERR_MEMORY);
724cd37da74Snw141292 
725cd37da74Snw141292 	if (dname == NULL || *dname == '\0') {
7262b4a7802SBaban Kenkre 		/* 'name' not qualified and dname not given */
727*e3f2c991SKeyur Desai 		dname = state->default_domain;
7282b4a7802SBaban Kenkre 		edomain = strdup(dname);
729cd37da74Snw141292 		if (edomain == NULL) {
730cd37da74Snw141292 			free(ecanonname);
731e3c2d6aaSnw141292 			return (IDMAP_ERR_MEMORY);
732cd37da74Snw141292 		}
733cd37da74Snw141292 	} else {
734cd37da74Snw141292 		if ((edomain = strdup(dname)) == NULL) {
735cd37da74Snw141292 			free(ecanonname);
736cd37da74Snw141292 			return (IDMAP_ERR_MEMORY);
737cd37da74Snw141292 		}
738e3c2d6aaSnw141292 	}
739c5c4113dSnw141292 
7404d61c878SJulian Pullen 	if (!adutils_lookup_check_domain(state->qs, dname)) {
7414d61c878SJulian Pullen 		free(ecanonname);
7424d61c878SJulian Pullen 		free(edomain);
7434d61c878SJulian Pullen 		return (IDMAP_ERR_DOMAIN_NOTFOUND);
7444d61c878SJulian Pullen 	}
7454d61c878SJulian Pullen 
746479ac375Sdm199847 	s_name = sanitize_for_ldap_filter(name);
747479ac375Sdm199847 	if (s_name == NULL) {
748cd37da74Snw141292 		free(ecanonname);
749479ac375Sdm199847 		free(edomain);
750c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
751c5c4113dSnw141292 	}
752479ac375Sdm199847 
753479ac375Sdm199847 	/* Assemble filter */
754*e3f2c991SKeyur Desai 	(void) asprintf(&filter, SANFILTER, s_name);
755*e3f2c991SKeyur Desai 	if (s_name != name)
756*e3f2c991SKeyur Desai 		free(s_name);
757*e3f2c991SKeyur Desai 	if (filter == NULL) {
758479ac375Sdm199847 		free(ecanonname);
759479ac375Sdm199847 		free(edomain);
760479ac375Sdm199847 		return (IDMAP_ERR_MEMORY);
761479ac375Sdm199847 	}
762c5c4113dSnw141292 
763cd37da74Snw141292 	retcode = idmap_batch_add1(state, filter, ecanonname, edomain,
76448258c6bSjp151216 	    eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type,
765*e3f2c991SKeyur Desai 	    unixname, pid, rc);
766c5c4113dSnw141292 
767c5c4113dSnw141292 	free(filter);
768c5c4113dSnw141292 
769c5c4113dSnw141292 	return (retcode);
770c5c4113dSnw141292 }
771c5c4113dSnw141292 
772c5c4113dSnw141292 idmap_retcode
773c5c4113dSnw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state,
774e8c27ec8Sbaban 	const char *sid, const rid_t *rid, int eunixtype,
77548258c6bSjp151216 	char **dn, char **attr, char **value,
77648258c6bSjp151216 	char **name, char **dname, int *sid_type,
777*e3f2c991SKeyur Desai 	char **unixname, posix_id_t *pid, idmap_retcode *rc)
778c5c4113dSnw141292 {
779c5c4113dSnw141292 	idmap_retcode	retcode;
780*e3f2c991SKeyur Desai 	int		ret;
781*e3f2c991SKeyur Desai 	char		*filter;
7822b4a7802SBaban Kenkre 	char		cbinsid[ADUTILS_MAXHEXBINSID + 1];
783c5c4113dSnw141292 
784c5c4113dSnw141292 	/*
785c5c4113dSnw141292 	 * Strategy: search [the global catalog] for user/group by
786c5c4113dSnw141292 	 * objectSid = SID with empty base DN.  The DN, sAMAccountName
787c5c4113dSnw141292 	 * and objectClass of the result are all we need to figure out
788c5c4113dSnw141292 	 * the name of the SID and whether it is a user, a group or a
789c5c4113dSnw141292 	 * computer.
790c5c4113dSnw141292 	 */
791c5c4113dSnw141292 
7924d61c878SJulian Pullen 	if (!adutils_lookup_check_sid_prefix(state->qs, sid))
7934d61c878SJulian Pullen 		return (IDMAP_ERR_DOMAIN_NOTFOUND);
7944d61c878SJulian Pullen 
7952b4a7802SBaban Kenkre 	ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid));
796c5c4113dSnw141292 	if (ret != 0)
797c5c4113dSnw141292 		return (IDMAP_ERR_SID);
798c5c4113dSnw141292 
799c5c4113dSnw141292 	/* Assemble filter */
800*e3f2c991SKeyur Desai 	(void) asprintf(&filter, OBJSIDFILTER, cbinsid);
801*e3f2c991SKeyur Desai 	if (filter == NULL)
802c5c4113dSnw141292 		return (IDMAP_ERR_MEMORY);
803c5c4113dSnw141292 
804e8c27ec8Sbaban 	retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype,
805*e3f2c991SKeyur Desai 	    dn, attr, value, name, dname, NULL, NULL, sid_type, unixname,
806*e3f2c991SKeyur Desai 	    pid, rc);
807e8c27ec8Sbaban 
808e8c27ec8Sbaban 	free(filter);
809e8c27ec8Sbaban 
810e8c27ec8Sbaban 	return (retcode);
811e8c27ec8Sbaban }
812e8c27ec8Sbaban 
813e8c27ec8Sbaban idmap_retcode
814e8c27ec8Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
815e8c27ec8Sbaban 	const char *unixname, int is_user, int is_wuser,
81648258c6bSjp151216 	char **dn, char **attr, char **value,
81748258c6bSjp151216 	char **sid, rid_t *rid, char **name,
81848258c6bSjp151216 	char **dname, int *sid_type, idmap_retcode *rc)
819e8c27ec8Sbaban {
820e8c27ec8Sbaban 	idmap_retcode	retcode;
821*e3f2c991SKeyur Desai 	char		*filter, *s_unixname;
822*e3f2c991SKeyur Desai 	const char	*attrname;
823e8c27ec8Sbaban 
824e8c27ec8Sbaban 	/* Get unixuser or unixgroup AD attribute name */
825e8c27ec8Sbaban 	attrname = (is_user) ?
826e8c27ec8Sbaban 	    state->ad_unixuser_attr : state->ad_unixgroup_attr;
827e8c27ec8Sbaban 	if (attrname == NULL)
828e8c27ec8Sbaban 		return (IDMAP_ERR_NOTFOUND);
829e8c27ec8Sbaban 
830479ac375Sdm199847 	s_unixname = sanitize_for_ldap_filter(unixname);
831479ac375Sdm199847 	if (s_unixname == NULL)
832479ac375Sdm199847 		return (IDMAP_ERR_MEMORY);
833479ac375Sdm199847 
834e8c27ec8Sbaban 	/*  Assemble filter */
835*e3f2c991SKeyur Desai 	(void) asprintf(&filter, "(&(objectclass=%s)(%s=%s))",
836*e3f2c991SKeyur Desai 	    is_wuser ? "user" : "group", attrname, s_unixname);
837479ac375Sdm199847 	if (s_unixname != unixname)
838479ac375Sdm199847 		free(s_unixname);
839*e3f2c991SKeyur Desai 	if (filter == NULL) {
840e8c27ec8Sbaban 		return (IDMAP_ERR_MEMORY);
841479ac375Sdm199847 	}
842e8c27ec8Sbaban 
843e8c27ec8Sbaban 	retcode = idmap_batch_add1(state, filter, NULL, NULL,
84448258c6bSjp151216 	    _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type,
845*e3f2c991SKeyur Desai 	    NULL, NULL, rc);
84648258c6bSjp151216 
84748258c6bSjp151216 	if (retcode == IDMAP_SUCCESS && attr != NULL) {
84848258c6bSjp151216 		if ((*attr = strdup(attrname)) == NULL)
84948258c6bSjp151216 			retcode = IDMAP_ERR_MEMORY;
85048258c6bSjp151216 	}
85148258c6bSjp151216 
85248258c6bSjp151216 	if (retcode == IDMAP_SUCCESS && value != NULL) {
85348258c6bSjp151216 		if ((*value = strdup(unixname)) == NULL)
85448258c6bSjp151216 			retcode = IDMAP_ERR_MEMORY;
85548258c6bSjp151216 	}
856*e3f2c991SKeyur Desai 
857*e3f2c991SKeyur Desai 	free(filter);
858*e3f2c991SKeyur Desai 
859*e3f2c991SKeyur Desai 	return (retcode);
860*e3f2c991SKeyur Desai }
861*e3f2c991SKeyur Desai 
862*e3f2c991SKeyur Desai idmap_retcode
863*e3f2c991SKeyur Desai idmap_pid2sid_batch_add1(idmap_query_state_t *state,
864*e3f2c991SKeyur Desai 	posix_id_t pid, int is_user,
865*e3f2c991SKeyur Desai 	char **dn, char **attr, char **value,
866*e3f2c991SKeyur Desai 	char **sid, rid_t *rid, char **name,
867*e3f2c991SKeyur Desai 	char **dname, int *sid_type, idmap_retcode *rc)
868*e3f2c991SKeyur Desai {
869*e3f2c991SKeyur Desai 	idmap_retcode	retcode;
870*e3f2c991SKeyur Desai 	char		*filter;
871*e3f2c991SKeyur Desai 	const char	*attrname;
872*e3f2c991SKeyur Desai 
873*e3f2c991SKeyur Desai 	/*  Assemble filter */
874*e3f2c991SKeyur Desai 	if (is_user) {
875*e3f2c991SKeyur Desai 		(void) asprintf(&filter, UIDNUMBERFILTER, pid);
876*e3f2c991SKeyur Desai 		attrname = UIDNUMBER;
877*e3f2c991SKeyur Desai 	} else {
878*e3f2c991SKeyur Desai 		(void) asprintf(&filter, GIDNUMBERFILTER, pid);
879*e3f2c991SKeyur Desai 		attrname = GIDNUMBER;
880*e3f2c991SKeyur Desai 	}
881*e3f2c991SKeyur Desai 	if (filter == NULL)
882*e3f2c991SKeyur Desai 		return (IDMAP_ERR_MEMORY);
883*e3f2c991SKeyur Desai 
884*e3f2c991SKeyur Desai 	retcode = idmap_batch_add1(state, filter, NULL, NULL,
885*e3f2c991SKeyur Desai 	    _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type,
886*e3f2c991SKeyur Desai 	    NULL, NULL, rc);
887*e3f2c991SKeyur Desai 
888*e3f2c991SKeyur Desai 	if (retcode == IDMAP_SUCCESS && attr != NULL) {
889*e3f2c991SKeyur Desai 		if ((*attr = strdup(attrname)) == NULL)
890*e3f2c991SKeyur Desai 			retcode = IDMAP_ERR_MEMORY;
891*e3f2c991SKeyur Desai 	}
892*e3f2c991SKeyur Desai 
893*e3f2c991SKeyur Desai 	if (retcode == IDMAP_SUCCESS && value != NULL) {
894*e3f2c991SKeyur Desai 		(void) asprintf(value, "%u", pid);
895*e3f2c991SKeyur Desai 		if (*value == NULL)
896*e3f2c991SKeyur Desai 			retcode = IDMAP_ERR_MEMORY;
89748258c6bSjp151216 	}
898c5c4113dSnw141292 
899c5c4113dSnw141292 	free(filter);
900c5c4113dSnw141292 
901c5c4113dSnw141292 	return (retcode);
902c5c4113dSnw141292 }
903