xref: /illumos-gate/usr/src/cmd/idmap/idmapd/adutils.c (revision 49160520)
1c5c4113dSnw /*
2c5c4113dSnw  * CDDL HEADER START
3c5c4113dSnw  *
4c5c4113dSnw  * The contents of this file are subject to the terms of the
5c5c4113dSnw  * Common Development and Distribution License (the "License").
6c5c4113dSnw  * You may not use this file except in compliance with the License.
7c5c4113dSnw  *
8c5c4113dSnw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c5c4113dSnw  * or http://www.opensolaris.org/os/licensing.
10c5c4113dSnw  * See the License for the specific language governing permissions
11c5c4113dSnw  * and limitations under the License.
12c5c4113dSnw  *
13c5c4113dSnw  * When distributing Covered Code, include this CDDL HEADER in each
14c5c4113dSnw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c5c4113dSnw  * If applicable, add the following below this CDDL HEADER, with the
16c5c4113dSnw  * fields enclosed by brackets "[]" replaced with your own identifying
17c5c4113dSnw  * information: Portions Copyright [yyyy] [name of copyright owner]
18c5c4113dSnw  *
19c5c4113dSnw  * CDDL HEADER END
20c5c4113dSnw  */
21c5c4113dSnw 
22c5c4113dSnw /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24a01d29c9SMatt Barden  *
25a01d29c9SMatt Barden  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
26c5c4113dSnw  */
27c5c4113dSnw 
28c5c4113dSnw /*
29c5c4113dSnw  * Processes name2sid & sid2name batched lookups for a given user or
30c5c4113dSnw  * computer from an AD Directory server using GSSAPI authentication
31c5c4113dSnw  */
32c5c4113dSnw 
33c5c4113dSnw #include <stdio.h>
34c5c4113dSnw #include <stdlib.h>
35c5c4113dSnw #include <alloca.h>
36c5c4113dSnw #include <string.h>
37c5c4113dSnw #include <strings.h>
38c5c4113dSnw #include <lber.h>
39c5c4113dSnw #include <ldap.h>
40c5c4113dSnw #include <sasl/sasl.h>
41c5c4113dSnw #include <string.h>
42c5c4113dSnw #include <ctype.h>
43c5c4113dSnw #include <pthread.h>
44c5c4113dSnw #include <synch.h>
45c5c4113dSnw #include <atomic.h>
46c5c4113dSnw #include <errno.h>
47c5c4113dSnw #include <assert.h>
48c5c4113dSnw #include <limits.h>
492b4a7802SBaban Kenkre #include <time.h>
50cd37da74Snw #include <sys/u8_textprep.h>
512b4a7802SBaban Kenkre #include "libadutils.h"
52479ac375Sdm #include "nldaputils.h"
53c5c4113dSnw #include "idmapd.h"
54c5c4113dSnw 
55c5c4113dSnw /* Attribute names and filter format strings */
56e3c2d6aaSnw #define	SAN		"sAMAccountName"
57e3c2d6aaSnw #define	OBJSID		"objectSid"
58e3c2d6aaSnw #define	OBJCLASS	"objectClass"
59e3f2c991SKeyur Desai #define	UIDNUMBER	"uidNumber"
60e3f2c991SKeyur Desai #define	GIDNUMBER	"gidNumber"
61e3f2c991SKeyur Desai #define	UIDNUMBERFILTER	"(&(objectclass=user)(uidNumber=%u))"
62e3f2c991SKeyur Desai #define	GIDNUMBERFILTER	"(&(objectclass=group)(gidNumber=%u))"
63e3f2c991SKeyur Desai #define	SANFILTER	"(sAMAccountName=%s)"
64a01d29c9SMatt Barden #define	OBJSIDFILTER	"(|(objectSid=%s)(sIDHistory=%s))"
65c5c4113dSnw 
662b4a7802SBaban Kenkre void	idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc,
672b4a7802SBaban Kenkre 		int qid, void *argp);
68c5c4113dSnw 
69c5c4113dSnw /*
70c5c4113dSnw  * A place to put the results of a batched (async) query
71c5c4113dSnw  *
72c5c4113dSnw  * There is one of these for every query added to a batch object
73c5c4113dSnw  * (idmap_query_state, see below).
74c5c4113dSnw  */
75c5c4113dSnw typedef struct idmap_q {
76e3c2d6aaSnw 	/*
77e3c2d6aaSnw 	 * data used for validating search result entries for name->SID
78e8c27ec8Sbaban 	 * lookups
79e3c2d6aaSnw 	 */
80cd37da74Snw 	char			*ecanonname;	/* expected canon name */
81cd37da74Snw 	char			*edomain;	/* expected domain name */
82148c5f43SAlan Wright 	idmap_id_type		esidtype;	/* expected SID type */
83e3c2d6aaSnw 	/* results */
84cd37da74Snw 	char			**canonname;	/* actual canon name */
85c5c4113dSnw 	char			**domain;	/* name of domain of object */
86e8c27ec8Sbaban 	char			**sid;		/* stringified SID */
87e8c27ec8Sbaban 	rid_t			*rid;		/* RID */
88148c5f43SAlan Wright 	idmap_id_type		*sid_type;	/* user or group SID? */
89e8c27ec8Sbaban 	char			**unixname;	/* unixname for name mapping */
9048258c6bSjp 	char			**dn;		/* DN of entry */
9148258c6bSjp 	char			**attr;		/* Attr for name mapping */
9248258c6bSjp 	char			**value;	/* value for name mapping */
93e3f2c991SKeyur Desai 	posix_id_t		*pid;		/* Posix ID found via IDMU */
94c5c4113dSnw 	idmap_retcode		*rc;
952b4a7802SBaban Kenkre 	adutils_rc		ad_rc;
962b4a7802SBaban Kenkre 	adutils_result_t	*result;
97e3c2d6aaSnw 
98bcced03bSjp 	/*
99bcced03bSjp 	 * The LDAP search entry result is placed here to be processed
100bcced03bSjp 	 * when the search done result is received.
101bcced03bSjp 	 */
102bcced03bSjp 	LDAPMessage		*search_res;	/* The LDAP search result */
103c5c4113dSnw } idmap_q_t;
104c5c4113dSnw 
105c5c4113dSnw /* Batch context structure; typedef is in header file */
106c5c4113dSnw struct idmap_query_state {
1072b4a7802SBaban Kenkre 	adutils_query_state_t	*qs;
1084d61c878SJulian Pullen 	int			qsize;		/* Queue size */
1094d61c878SJulian Pullen 	uint32_t		qcount;		/* Number of queued requests */
110e8c27ec8Sbaban 	const char		*ad_unixuser_attr;
111e8c27ec8Sbaban 	const char		*ad_unixgroup_attr;
112e3f2c991SKeyur Desai 	int			directory_based_mapping;	/* enum */
113e3f2c991SKeyur Desai 	char			*default_domain;
114c5c4113dSnw 	idmap_q_t		queries[1];	/* array of query results */
115c5c4113dSnw };
116c5c4113dSnw 
117651c0131Sbaban static pthread_t	reaperid = 0;
118c5c4113dSnw 
119c5c4113dSnw /*
120c5c4113dSnw  * Keep connection management simple for now, extend or replace later
121c5c4113dSnw  * with updated libsldap code.
122c5c4113dSnw  */
123c5c4113dSnw #define	ADREAPERSLEEP	60
124c5c4113dSnw 
125c5c4113dSnw /*
126c5c4113dSnw  * Idle connection reaping side of connection management
127c5c4113dSnw  *
128c5c4113dSnw  * Every minute wake up and look for connections that have been idle for
129c5c4113dSnw  * five minutes or more and close them.
130c5c4113dSnw  */
131c5c4113dSnw /*ARGSUSED*/
132c5c4113dSnw static
133*49160520SToomas Soome void *
adreaper(void * arg __unused)134*49160520SToomas Soome adreaper(void *arg __unused)
135c5c4113dSnw {
136c5c4113dSnw 	timespec_t	ts;
137c5c4113dSnw 
138c5c4113dSnw 	ts.tv_sec = ADREAPERSLEEP;
139c5c4113dSnw 	ts.tv_nsec = 0;
140c5c4113dSnw 
141c5c4113dSnw 	for (;;) {
142c5c4113dSnw 		/*
143c5c4113dSnw 		 * nanosleep(3RT) is thead-safe (no SIGALRM) and more
144c5c4113dSnw 		 * portable than usleep(3C)
145c5c4113dSnw 		 */
146c5c4113dSnw 		(void) nanosleep(&ts, NULL);
1472b4a7802SBaban Kenkre 		adutils_reap_idle_connections();
148c5c4113dSnw 	}
149*49160520SToomas Soome 	return (NULL);
150c5c4113dSnw }
151c5c4113dSnw 
152c5c4113dSnw /*
153c5c4113dSnw  * Take ad_host_config_t information, create a ad_host_t,
154c5c4113dSnw  * populate it and add it to the list of hosts.
155c5c4113dSnw  */
156c5c4113dSnw 
157c5c4113dSnw int
idmap_add_ds(adutils_ad_t * ad,const char * host,int port)1582b4a7802SBaban Kenkre idmap_add_ds(adutils_ad_t *ad, const char *host, int port)
159c5c4113dSnw {
1602b4a7802SBaban Kenkre 	int	ret = -1;
161c5c4113dSnw 
1622b4a7802SBaban Kenkre 	if (adutils_add_ds(ad, host, port) == ADUTILS_SUCCESS)
1632b4a7802SBaban Kenkre 		ret = 0;
164c5c4113dSnw 
165c5c4113dSnw 	/* Start reaper if it doesn't exist */
1662b4a7802SBaban Kenkre 	if (ret == 0 && reaperid == 0)
167*49160520SToomas Soome 		(void) pthread_create(&reaperid, NULL, adreaper, NULL);
168c5c4113dSnw 	return (ret);
169c5c4113dSnw }
170c5c4113dSnw 
171c5c4113dSnw static
1722b4a7802SBaban Kenkre idmap_retcode
map_adrc2idmaprc(adutils_rc adrc)1732b4a7802SBaban Kenkre map_adrc2idmaprc(adutils_rc adrc)
1742b4a7802SBaban Kenkre {
1752b4a7802SBaban Kenkre 	switch (adrc) {
1762b4a7802SBaban Kenkre 	case ADUTILS_SUCCESS:
1772b4a7802SBaban Kenkre 		return (IDMAP_SUCCESS);
1782b4a7802SBaban Kenkre 	case ADUTILS_ERR_NOTFOUND:
1792b4a7802SBaban Kenkre 		return (IDMAP_ERR_NOTFOUND);
1802b4a7802SBaban Kenkre 	case ADUTILS_ERR_MEMORY:
1812b4a7802SBaban Kenkre 		return (IDMAP_ERR_MEMORY);
1822b4a7802SBaban Kenkre 	case ADUTILS_ERR_DOMAIN:
1832b4a7802SBaban Kenkre 		return (IDMAP_ERR_DOMAIN);
1842b4a7802SBaban Kenkre 	case ADUTILS_ERR_OTHER:
1852b4a7802SBaban Kenkre 		return (IDMAP_ERR_OTHER);
1862b4a7802SBaban Kenkre 	case ADUTILS_ERR_RETRIABLE_NET_ERR:
1872b4a7802SBaban Kenkre 		return (IDMAP_ERR_RETRIABLE_NET_ERR);
1882b4a7802SBaban Kenkre 	default:
1892b4a7802SBaban Kenkre 		return (IDMAP_ERR_INTERNAL);
190c5c4113dSnw 	}
1912b4a7802SBaban Kenkre 	/* NOTREACHED */
192c5c4113dSnw }
193c5c4113dSnw 
194c5c4113dSnw idmap_retcode
idmap_lookup_batch_start(adutils_ad_t * ad,int nqueries,int directory_based_mapping,const char * default_domain,idmap_query_state_t ** state)1952b4a7802SBaban Kenkre idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
196*49160520SToomas Soome     int directory_based_mapping, const char *default_domain,
197*49160520SToomas Soome     idmap_query_state_t **state)
198c5c4113dSnw {
1992b4a7802SBaban Kenkre 	idmap_query_state_t	*new_state;
2002b4a7802SBaban Kenkre 	adutils_rc		rc;
201c5c4113dSnw 
202c5c4113dSnw 	*state = NULL;
203c5c4113dSnw 
2044d61c878SJulian Pullen 	assert(ad != NULL);
205c5c4113dSnw 
206c5c4113dSnw 	new_state = calloc(1, sizeof (idmap_query_state_t) +
207c5c4113dSnw 	    (nqueries - 1) * sizeof (idmap_q_t));
208c5c4113dSnw 	if (new_state == NULL)
209c5c4113dSnw 		return (IDMAP_ERR_MEMORY);
210c5c4113dSnw 
2112b4a7802SBaban Kenkre 	if ((rc = adutils_lookup_batch_start(ad, nqueries,
2122b4a7802SBaban Kenkre 	    idmap_ldap_res_search_cb, new_state, &new_state->qs))
2132b4a7802SBaban Kenkre 	    != ADUTILS_SUCCESS) {
214e3f2c991SKeyur Desai 		idmap_lookup_release_batch(&new_state);
2152b4a7802SBaban Kenkre 		return (map_adrc2idmaprc(rc));
2162b4a7802SBaban Kenkre 	}
217c5c4113dSnw 
218e3f2c991SKeyur Desai 	new_state->default_domain = strdup(default_domain);
219e3f2c991SKeyur Desai 	if (new_state->default_domain == NULL) {
220e3f2c991SKeyur Desai 		idmap_lookup_release_batch(&new_state);
221e3f2c991SKeyur Desai 		return (IDMAP_ERR_MEMORY);
222e3f2c991SKeyur Desai 	}
223e3f2c991SKeyur Desai 
224e3f2c991SKeyur Desai 	new_state->directory_based_mapping = directory_based_mapping;
2254d61c878SJulian Pullen 	new_state->qsize = nqueries;
226c5c4113dSnw 	*state = new_state;
227c5c4113dSnw 	return (IDMAP_SUCCESS);
228c5c4113dSnw }
229c5c4113dSnw 
230e8c27ec8Sbaban /*
231e8c27ec8Sbaban  * Set unixuser_attr and unixgroup_attr for AD-based name mapping
232e8c27ec8Sbaban  */
233e8c27ec8Sbaban void
idmap_lookup_batch_set_unixattr(idmap_query_state_t * state,const char * unixuser_attr,const char * unixgroup_attr)234e8c27ec8Sbaban idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
235*49160520SToomas Soome     const char *unixuser_attr, const char *unixgroup_attr)
2364edd44c5Sjp {
237e8c27ec8Sbaban 	state->ad_unixuser_attr = unixuser_attr;
238e8c27ec8Sbaban 	state->ad_unixgroup_attr = unixgroup_attr;
239e8c27ec8Sbaban }
240e8c27ec8Sbaban 
241c5c4113dSnw /*
242cd37da74Snw  * Take parsed attribute values from a search result entry and check if
243cd37da74Snw  * it is the result that was desired and, if so, set the result fields
244cd37da74Snw  * of the given idmap_q_t.
245cd37da74Snw  *
246e3f2c991SKeyur Desai  * Except for dn and attr, all strings are consumed, either by transferring
247e3f2c991SKeyur Desai  * them over into the request results (where the caller will eventually free
248e3f2c991SKeyur Desai  * them) or by freeing them here.  Note that this aligns with the "const"
249e3f2c991SKeyur Desai  * declarations below.
250c5c4113dSnw  */
251c5c4113dSnw static
252cd37da74Snw void
idmap_setqresults(idmap_q_t * q,char * san,const char * dn,const char * attr,char * value,char * sid,rid_t rid,int sid_type,char * unixname,posix_id_t pid)253e3f2c991SKeyur Desai idmap_setqresults(
254e3f2c991SKeyur Desai     idmap_q_t *q,
255e3f2c991SKeyur Desai     char *san,
256e3f2c991SKeyur Desai     const char *dn,
257e3f2c991SKeyur Desai     const char *attr,
258e3f2c991SKeyur Desai     char *value,
259e3f2c991SKeyur Desai     char *sid,
260e3f2c991SKeyur Desai     rid_t rid,
261e3f2c991SKeyur Desai     int sid_type,
262e3f2c991SKeyur Desai     char *unixname,
263e3f2c991SKeyur Desai     posix_id_t pid)
264c5c4113dSnw {
265cd37da74Snw 	char *domain;
2661fcced4cSJordan Brown 	int err1;
267c5c4113dSnw 
268cd37da74Snw 	assert(dn != NULL);
269e3c2d6aaSnw 
2702b4a7802SBaban Kenkre 	if ((domain = adutils_dn2dns(dn)) == NULL)
271cd37da74Snw 		goto out;
272cd37da74Snw 
273e8c27ec8Sbaban 	if (q->ecanonname != NULL && san != NULL) {
274e8c27ec8Sbaban 		/* Check that this is the canonname that we were looking for */
275cd37da74Snw 		if (u8_strcmp(q->ecanonname, san, 0,
276cd37da74Snw 		    U8_STRCMP_CI_LOWER, /* no normalization, for now */
277e8c27ec8Sbaban 		    U8_UNICODE_LATEST, &err1) != 0 || err1 != 0)
278e8c27ec8Sbaban 			goto out;
279e8c27ec8Sbaban 	}
280e8c27ec8Sbaban 
281e8c27ec8Sbaban 	if (q->edomain != NULL) {
282e8c27ec8Sbaban 		/* Check that this is the domain that we were looking for */
2831fcced4cSJordan Brown 		if (!domain_eq(q->edomain, domain))
284cd37da74Snw 			goto out;
285e8c27ec8Sbaban 	}
286cd37da74Snw 
28748258c6bSjp 	/* Copy the DN and attr and value */
28848258c6bSjp 	if (q->dn != NULL)
28948258c6bSjp 		*q->dn = strdup(dn);
29048258c6bSjp 
29148258c6bSjp 	if (q->attr != NULL && attr != NULL)
29248258c6bSjp 		*q->attr = strdup(attr);
29348258c6bSjp 
294e3f2c991SKeyur Desai 	if (q->value != NULL && value != NULL) {
295e3f2c991SKeyur Desai 		*q->value = value;
296e3f2c991SKeyur Desai 		value = NULL;
297e3f2c991SKeyur Desai 	}
29848258c6bSjp 
299e8c27ec8Sbaban 	/* Set results */
300e8c27ec8Sbaban 	if (q->sid) {
301e8c27ec8Sbaban 		*q->sid = sid;
302e8c27ec8Sbaban 		sid = NULL;
303e8c27ec8Sbaban 	}
304e8c27ec8Sbaban 	if (q->rid)
305cd37da74Snw 		*q->rid = rid;
306e8c27ec8Sbaban 	if (q->sid_type)
307cd37da74Snw 		*q->sid_type = sid_type;
308e8c27ec8Sbaban 	if (q->unixname) {
309e8c27ec8Sbaban 		*q->unixname = unixname;
310e8c27ec8Sbaban 		unixname = NULL;
311e8c27ec8Sbaban 	}
312e8c27ec8Sbaban 	if (q->domain != NULL) {
313e8c27ec8Sbaban 		*q->domain = domain;
314e8c27ec8Sbaban 		domain = NULL;
315e8c27ec8Sbaban 	}
316e8c27ec8Sbaban 	if (q->canonname != NULL) {
317479ac375Sdm 		/*
318479ac375Sdm 		 * The caller may be replacing the given winname by its
319479ac375Sdm 		 * canonical name and therefore free any old name before
320479ac375Sdm 		 * overwriting the field by the canonical name.
321479ac375Sdm 		 */
322479ac375Sdm 		free(*q->canonname);
323cd37da74Snw 		*q->canonname = san;
324cd37da74Snw 		san = NULL;
325e3c2d6aaSnw 	}
326e3c2d6aaSnw 
3279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (q->pid != NULL && pid != IDMAP_SENTINEL_PID) {
328e3f2c991SKeyur Desai 		*q->pid = pid;
329e3f2c991SKeyur Desai 	}
330e3f2c991SKeyur Desai 
3312b4a7802SBaban Kenkre 	q->ad_rc = ADUTILS_SUCCESS;
332e3c2d6aaSnw 
333cd37da74Snw out:
334cd37da74Snw 	/* Free unused attribute values */
335cd37da74Snw 	free(san);
336cd37da74Snw 	free(sid);
337cd37da74Snw 	free(domain);
338e8c27ec8Sbaban 	free(unixname);
339e3f2c991SKeyur Desai 	free(value);
340cd37da74Snw }
341c5c4113dSnw 
342c5c4113dSnw #define	BVAL_CASEEQ(bv, str) \
343c5c4113dSnw 		(((*(bv))->bv_len == (sizeof (str) - 1)) && \
344c5c4113dSnw 		    strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0)
345c5c4113dSnw 
346c5c4113dSnw /*
347cd37da74Snw  * Extract the class of the result entry.  Returns 1 on success, 0 on
348cd37da74Snw  * failure.
349c5c4113dSnw  */
350c5c4113dSnw static
351e3c2d6aaSnw int
idmap_bv_objclass2sidtype(BerValue ** bvalues,int * sid_type)352cd37da74Snw idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type)
353c5c4113dSnw {
354c5c4113dSnw 	BerValue	**cbval;
355c5c4113dSnw 
356148c5f43SAlan Wright 	*sid_type = IDMAP_SID;
357c5c4113dSnw 	if (bvalues == NULL)
358e3c2d6aaSnw 		return (0);
359c5c4113dSnw 
360cd37da74Snw 	/*
361e3f2c991SKeyur Desai 	 * We consider Computer to be a subclass of User, so we can just
362e3f2c991SKeyur Desai 	 * ignore Computer entries and pay attention to the accompanying
363e3f2c991SKeyur Desai 	 * User entries.
364cd37da74Snw 	 */
365c5c4113dSnw 	for (cbval = bvalues; *cbval != NULL; cbval++) {
366e3f2c991SKeyur Desai 		if (BVAL_CASEEQ(cbval, "group")) {
367148c5f43SAlan Wright 			*sid_type = IDMAP_GSID;
368cd37da74Snw 			break;
369e3f2c991SKeyur Desai 		} else if (BVAL_CASEEQ(cbval, "user")) {
370148c5f43SAlan Wright 			*sid_type = IDMAP_USID;
371e3f2c991SKeyur Desai 			break;
372cd37da74Snw 		}
373cd37da74Snw 		/*
374148c5f43SAlan Wright 		 * "else if (*sid_type = IDMAP_USID)" then this is a
375cd37da74Snw 		 * new sub-class of user -- what to do with it??
376cd37da74Snw 		 */
377c5c4113dSnw 	}
378e3c2d6aaSnw 
379e3c2d6aaSnw 	return (1);
380c5c4113dSnw }
381c5c4113dSnw 
382c5c4113dSnw /*
383c5c4113dSnw  * Handle a given search result entry
384c5c4113dSnw  */
385c5c4113dSnw static
386c5c4113dSnw void
idmap_extract_object(idmap_query_state_t * state,idmap_q_t * q,LDAPMessage * res,LDAP * ld)3872b4a7802SBaban Kenkre idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q,
388*49160520SToomas Soome     LDAPMessage *res, LDAP *ld)
389c5c4113dSnw {
390c5c4113dSnw 	BerValue		**bvalues;
391e3f2c991SKeyur Desai 	const char		*attr = NULL;
392e3f2c991SKeyur Desai 	char			*value = NULL;
393e3f2c991SKeyur Desai 	char			*unix_name = NULL;
394e3f2c991SKeyur Desai 	char			*dn;
395cd37da74Snw 	char			*san = NULL;
396cd37da74Snw 	char			*sid = NULL;
397cd37da74Snw 	rid_t			rid = 0;
398e3f2c991SKeyur Desai 	int			sid_type;
399e3f2c991SKeyur Desai 	int			ok;
4009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	posix_id_t		pid = IDMAP_SENTINEL_PID;
401e3c2d6aaSnw 
402e8c27ec8Sbaban 	assert(q->rc != NULL);
403e3f2c991SKeyur Desai 	assert(q->domain == NULL || *q->domain == NULL);
404e8c27ec8Sbaban 
4052b4a7802SBaban Kenkre 	if ((dn = ldap_get_dn(ld, res)) == NULL)
406c5c4113dSnw 		return;
407c5c4113dSnw 
408e3f2c991SKeyur Desai 	bvalues = ldap_get_values_len(ld, res, OBJCLASS);
409e3f2c991SKeyur Desai 	if (bvalues == NULL) {
410e3f2c991SKeyur Desai 		/*
411e3f2c991SKeyur Desai 		 * Didn't find objectclass. Something's wrong with our
412e3f2c991SKeyur Desai 		 * AD data.
413e3f2c991SKeyur Desai 		 */
414e3f2c991SKeyur Desai 		idmapdlog(LOG_ERR, "%s has no %s", dn, OBJCLASS);
415e3f2c991SKeyur Desai 		goto out;
416e8c27ec8Sbaban 	}
417e3f2c991SKeyur Desai 	ok = idmap_bv_objclass2sidtype(bvalues, &sid_type);
418e3f2c991SKeyur Desai 	ldap_value_free_len(bvalues);
419e3f2c991SKeyur Desai 	if (!ok) {
420c5c4113dSnw 		/*
421e3f2c991SKeyur Desai 		 * Didn't understand objectclass. Something's wrong with our
422e3f2c991SKeyur Desai 		 * AD data.
423c5c4113dSnw 		 */
424e3f2c991SKeyur Desai 		idmapdlog(LOG_ERR, "%s has unexpected %s", dn, OBJCLASS);
425e3f2c991SKeyur Desai 		goto out;
426e3f2c991SKeyur Desai 	}
427e3f2c991SKeyur Desai 
428e3f2c991SKeyur Desai 	if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU &&
429e3f2c991SKeyur Desai 	    q->pid != NULL) {
430148c5f43SAlan Wright 		if (sid_type == IDMAP_USID)
431e3f2c991SKeyur Desai 			attr = UIDNUMBER;
432148c5f43SAlan Wright 		else if (sid_type == IDMAP_GSID)
433e3f2c991SKeyur Desai 			attr = GIDNUMBER;
434e3f2c991SKeyur Desai 		if (attr != NULL) {
4352b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
4362b4a7802SBaban Kenkre 			if (bvalues != NULL) {
437e3f2c991SKeyur Desai 				value = adutils_bv_str(bvalues[0]);
438e3f2c991SKeyur Desai 				if (!adutils_bv_uint(bvalues[0], &pid)) {
439e3f2c991SKeyur Desai 					idmapdlog(LOG_ERR,
440e3f2c991SKeyur Desai 					    "%s has Invalid %s value \"%s\"",
441e3f2c991SKeyur Desai 					    dn, attr, value);
442e8c27ec8Sbaban 				}
443e3f2c991SKeyur Desai 				ldap_value_free_len(bvalues);
444e8c27ec8Sbaban 			}
445e3f2c991SKeyur Desai 		}
446e3f2c991SKeyur Desai 	}
447e3f2c991SKeyur Desai 
448e3f2c991SKeyur Desai 	if (state->directory_based_mapping == DIRECTORY_MAPPING_NAME &&
449e3f2c991SKeyur Desai 	    q->unixname != NULL) {
450e3f2c991SKeyur Desai 		/*
451e3f2c991SKeyur Desai 		 * If the caller has requested unixname then determine the
452e3f2c991SKeyur Desai 		 * AD attribute name that will have the unixname, and retrieve
453e3f2c991SKeyur Desai 		 * its value.
454e3f2c991SKeyur Desai 		 */
455148c5f43SAlan Wright 		idmap_id_type esidtype;
456e3f2c991SKeyur Desai 		/*
457148c5f43SAlan Wright 		 * Determine the target type.
458e3f2c991SKeyur Desai 		 *
459e3f2c991SKeyur Desai 		 * If the caller specified one, use that.  Otherwise, give the
460e3f2c991SKeyur Desai 		 * same type that as we found for the Windows user.
461e3f2c991SKeyur Desai 		 */
462148c5f43SAlan Wright 		esidtype = q->esidtype;
463148c5f43SAlan Wright 		if (esidtype == IDMAP_SID)
464148c5f43SAlan Wright 			esidtype = sid_type;
46548258c6bSjp 
466148c5f43SAlan Wright 		if (esidtype == IDMAP_USID)
467e3f2c991SKeyur Desai 			attr = state->ad_unixuser_attr;
468148c5f43SAlan Wright 		else if (esidtype == IDMAP_GSID)
469e3f2c991SKeyur Desai 			attr = state->ad_unixgroup_attr;
470e3f2c991SKeyur Desai 
471e3f2c991SKeyur Desai 		if (attr != NULL) {
4722b4a7802SBaban Kenkre 			bvalues = ldap_get_values_len(ld, res, attr);
4732b4a7802SBaban Kenkre 			if (bvalues != NULL) {
474e3f2c991SKeyur Desai 				unix_name = adutils_bv_str(bvalues[0]);
475e3f2c991SKeyur Desai 				ldap_value_free_len(bvalues);
476e3f2c991SKeyur Desai 				value = strdup(unix_name);
4772b4a7802SBaban Kenkre 			}
478c5c4113dSnw 		}
479e3f2c991SKeyur Desai 	}
480c5c4113dSnw 
481e3f2c991SKeyur Desai 	bvalues = ldap_get_values_len(ld, res, SAN);
482e3f2c991SKeyur Desai 	if (bvalues != NULL) {
483e3f2c991SKeyur Desai 		san = adutils_bv_str(bvalues[0]);
484e3f2c991SKeyur Desai 		ldap_value_free_len(bvalues);
485c5c4113dSnw 	}
486c5c4113dSnw 
487e3f2c991SKeyur Desai 	if (q->sid != NULL) {
488e3f2c991SKeyur Desai 		bvalues = ldap_get_values_len(ld, res, OBJSID);
489e3f2c991SKeyur Desai 		if (bvalues != NULL) {
490e3f2c991SKeyur Desai 			sid = adutils_bv_objsid2sidstr(bvalues[0], &rid);
491e3f2c991SKeyur Desai 			ldap_value_free_len(bvalues);
492e3f2c991SKeyur Desai 		}
493e8c27ec8Sbaban 	}
494e8c27ec8Sbaban 
495e3f2c991SKeyur Desai 	idmap_setqresults(q, san, dn,
496e3f2c991SKeyur Desai 	    attr, value,
497e3f2c991SKeyur Desai 	    sid, rid, sid_type,
498e3f2c991SKeyur Desai 	    unix_name, pid);
499c5c4113dSnw 
500e3f2c991SKeyur Desai out:
501c5c4113dSnw 	ldap_memfree(dn);
502c5c4113dSnw }
503c5c4113dSnw 
5042b4a7802SBaban Kenkre void
idmap_ldap_res_search_cb(LDAP * ld,LDAPMessage ** res,int rc,int qid,void * argp)5052b4a7802SBaban Kenkre idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid,
506*49160520SToomas Soome     void *argp)
507c5c4113dSnw {
5082b4a7802SBaban Kenkre 	idmap_query_state_t	*state = (idmap_query_state_t *)argp;
5092b4a7802SBaban Kenkre 	idmap_q_t		*q = &(state->queries[qid]);
510c5c4113dSnw 
511c5c4113dSnw 	switch (rc) {
512c5c4113dSnw 	case LDAP_RES_SEARCH_RESULT:
5132b4a7802SBaban Kenkre 		if (q->search_res != NULL) {
5142b4a7802SBaban Kenkre 			idmap_extract_object(state, q, q->search_res, ld);
5152b4a7802SBaban Kenkre 			(void) ldap_msgfree(q->search_res);
5162b4a7802SBaban Kenkre 			q->search_res = NULL;
5172b4a7802SBaban Kenkre 		} else
5182b4a7802SBaban Kenkre 			q->ad_rc = ADUTILS_ERR_NOTFOUND;
519c5c4113dSnw 		break;
520c5c4113dSnw 	case LDAP_RES_SEARCH_ENTRY:
5212b4a7802SBaban Kenkre 		if (q->search_res == NULL) {
5222b4a7802SBaban Kenkre 			q->search_res = *res;
5232b4a7802SBaban Kenkre 			*res = NULL;
524c5c4113dSnw 		}
525c5c4113dSnw 		break;
526c5c4113dSnw 	default:
527c5c4113dSnw 		break;
528c5c4113dSnw 	}
52984decf41Sjp }
53084decf41Sjp 
531e3c2d6aaSnw static
532e3c2d6aaSnw void
idmap_cleanup_batch(idmap_query_state_t * batch)533e3c2d6aaSnw idmap_cleanup_batch(idmap_query_state_t *batch)
534e3c2d6aaSnw {
535e3c2d6aaSnw 	int i;
536e3c2d6aaSnw 
537e3c2d6aaSnw 	for (i = 0; i < batch->qcount; i++) {
538cd37da74Snw 		if (batch->queries[i].ecanonname != NULL)
539cd37da74Snw 			free(batch->queries[i].ecanonname);
540cd37da74Snw 		batch->queries[i].ecanonname = NULL;
541cd37da74Snw 		if (batch->queries[i].edomain != NULL)
542cd37da74Snw 			free(batch->queries[i].edomain);
543cd37da74Snw 		batch->queries[i].edomain = NULL;
544e3c2d6aaSnw 	}
545e3c2d6aaSnw }
546e3c2d6aaSnw 
54784decf41Sjp /*
54884decf41Sjp  * This routine frees the idmap_query_state_t structure
54984decf41Sjp  */
550c5c4113dSnw void
idmap_lookup_release_batch(idmap_query_state_t ** state)55184decf41Sjp idmap_lookup_release_batch(idmap_query_state_t **state)
552c5c4113dSnw {
5532b4a7802SBaban Kenkre 	if (state == NULL || *state == NULL)
5542b4a7802SBaban Kenkre 		return;
5552b4a7802SBaban Kenkre 	adutils_lookup_batch_release(&(*state)->qs);
556e3c2d6aaSnw 	idmap_cleanup_batch(*state);
557e3f2c991SKeyur Desai 	free((*state)->default_domain);
558c5c4113dSnw 	free(*state);
559c5c4113dSnw 	*state = NULL;
560c5c4113dSnw }
561c5c4113dSnw 
562c5c4113dSnw idmap_retcode
idmap_lookup_batch_end(idmap_query_state_t ** state)5630dcc7149Snw idmap_lookup_batch_end(idmap_query_state_t **state)
564c5c4113dSnw {
5652b4a7802SBaban Kenkre 	adutils_rc		ad_rc;
5662b4a7802SBaban Kenkre 	int			i;
5672b4a7802SBaban Kenkre 	idmap_query_state_t	*id_qs = *state;
568c5c4113dSnw 
5692b4a7802SBaban Kenkre 	ad_rc = adutils_lookup_batch_end(&id_qs->qs);
570c5c4113dSnw 
5712b4a7802SBaban Kenkre 	/*
5722b4a7802SBaban Kenkre 	 * Map adutils rc to idmap_retcode in each
5732b4a7802SBaban Kenkre 	 * query because consumers in dbutils.c
5742b4a7802SBaban Kenkre 	 * expects idmap_retcode.
5752b4a7802SBaban Kenkre 	 */
5762b4a7802SBaban Kenkre 	for (i = 0; i < id_qs->qcount; i++) {
5772b4a7802SBaban Kenkre 		*id_qs->queries[i].rc =
5782b4a7802SBaban Kenkre 		    map_adrc2idmaprc(id_qs->queries[i].ad_rc);
579c5c4113dSnw 	}
58084decf41Sjp 	idmap_lookup_release_batch(state);
5812b4a7802SBaban Kenkre 	return (map_adrc2idmaprc(ad_rc));
582c5c4113dSnw }
583c5c4113dSnw 
584c5c4113dSnw /*
585c5c4113dSnw  * Send one prepared search, queue up msgid, process what results are
586c5c4113dSnw  * available
587c5c4113dSnw  */
588c5c4113dSnw static
589c5c4113dSnw idmap_retcode
idmap_batch_add1(idmap_query_state_t * state,const char * filter,char * ecanonname,char * edomain,idmap_id_type esidtype,char ** dn,char ** attr,char ** value,char ** canonname,char ** dname,char ** sid,rid_t * rid,idmap_id_type * sid_type,char ** unixname,posix_id_t * pid,idmap_retcode * rc)59048258c6bSjp idmap_batch_add1(idmap_query_state_t *state, const char *filter,
591*49160520SToomas Soome     char *ecanonname, char *edomain, idmap_id_type esidtype,
592*49160520SToomas Soome     char **dn, char **attr, char **value,
593*49160520SToomas Soome     char **canonname, char **dname,
594*49160520SToomas Soome     char **sid, rid_t *rid, idmap_id_type *sid_type, char **unixname,
595*49160520SToomas Soome     posix_id_t *pid,
596*49160520SToomas Soome     idmap_retcode *rc)
597c5c4113dSnw {
5982b4a7802SBaban Kenkre 	adutils_rc	ad_rc;
5992b4a7802SBaban Kenkre 	int		qid, i;
600c5c4113dSnw 	idmap_q_t	*q;
601e3f2c991SKeyur Desai 	char	*attrs[20];	/* Plenty */
602c5c4113dSnw 
6034d61c878SJulian Pullen 	qid = atomic_inc_32_nv(&state->qcount) - 1;
604c5c4113dSnw 	q = &(state->queries[qid]);
605c5c4113dSnw 
6064d61c878SJulian Pullen 	assert(qid < state->qsize);
6074d61c878SJulian Pullen 
608cd37da74Snw 	/*
6092b4a7802SBaban Kenkre 	 * Remember the expected canonname, domainname and unix type
6102b4a7802SBaban Kenkre 	 * so we can check the results * against it
611cd37da74Snw 	 */
612cd37da74Snw 	q->ecanonname = ecanonname;
613cd37da74Snw 	q->edomain = edomain;
614148c5f43SAlan Wright 	q->esidtype = esidtype;
615e3c2d6aaSnw 
616c5c4113dSnw 	/* Remember where to put the results */
617cd37da74Snw 	q->canonname = canonname;
618e8c27ec8Sbaban 	q->sid = sid;
619c5c4113dSnw 	q->domain = dname;
620c5c4113dSnw 	q->rid = rid;
621c5c4113dSnw 	q->sid_type = sid_type;
622c5c4113dSnw 	q->rc = rc;
623e8c27ec8Sbaban 	q->unixname = unixname;
62448258c6bSjp 	q->dn = dn;
62548258c6bSjp 	q->attr = attr;
62648258c6bSjp 	q->value = value;
627e3f2c991SKeyur Desai 	q->pid = pid;
628e3f2c991SKeyur Desai 
629e3f2c991SKeyur Desai 	/* Add attributes that are not always needed */
630e3f2c991SKeyur Desai 	i = 0;
631e3f2c991SKeyur Desai 	attrs[i++] = SAN;
632e3f2c991SKeyur Desai 	attrs[i++] = OBJSID;
633e3f2c991SKeyur Desai 	attrs[i++] = OBJCLASS;
634e8c27ec8Sbaban 
635e8c27ec8Sbaban 	if (unixname != NULL) {
636e3f2c991SKeyur Desai 		/* Add unixuser/unixgroup attribute names to the attrs list */
637148c5f43SAlan Wright 		if (esidtype != IDMAP_GSID &&
638e8c27ec8Sbaban 		    state->ad_unixuser_attr != NULL)
639e8c27ec8Sbaban 			attrs[i++] = (char *)state->ad_unixuser_attr;
640148c5f43SAlan Wright 		if (esidtype != IDMAP_USID &&
641e8c27ec8Sbaban 		    state->ad_unixgroup_attr != NULL)
642e3f2c991SKeyur Desai 			attrs[i++] = (char *)state->ad_unixgroup_attr;
643e8c27ec8Sbaban 	}
644c5c4113dSnw 
645e3f2c991SKeyur Desai 	if (pid != NULL) {
646148c5f43SAlan Wright 		if (esidtype != IDMAP_GSID)
647e3f2c991SKeyur Desai 			attrs[i++] = UIDNUMBER;
648148c5f43SAlan Wright 		if (esidtype != IDMAP_USID)
649e3f2c991SKeyur Desai 			attrs[i++] = GIDNUMBER;
650e3f2c991SKeyur Desai 	}
651e3f2c991SKeyur Desai 
652e3f2c991SKeyur Desai 	attrs[i] = NULL;
653e3f2c991SKeyur Desai 
654c5c4113dSnw 	/*
655c5c4113dSnw 	 * Provide sane defaults for the results in case we never hear
656c5c4113dSnw 	 * back from the DS before closing the connection.
657e3c2d6aaSnw 	 *
658e3c2d6aaSnw 	 * In particular we default the result to indicate a retriable
659e3c2d6aaSnw 	 * error.  The first complete matching result entry will cause
660e3c2d6aaSnw 	 * this to be set to IDMAP_SUCCESS, and the end of the results
661e3c2d6aaSnw 	 * for this search will cause this to indicate "not found" if no
662e3c2d6aaSnw 	 * result entries arrived or no complete ones matched the lookup
663e3c2d6aaSnw 	 * we were doing.
664c5c4113dSnw 	 */
665c5c4113dSnw 	*rc = IDMAP_ERR_RETRIABLE_NET_ERR;
666e8c27ec8Sbaban 	if (sid_type != NULL)
667148c5f43SAlan Wright 		*sid_type = IDMAP_SID;
668e8c27ec8Sbaban 	if (sid != NULL)
669e8c27ec8Sbaban 		*sid = NULL;
670c5c4113dSnw 	if (dname != NULL)
671c5c4113dSnw 		*dname = NULL;
672c5c4113dSnw 	if (rid != NULL)
673c5c4113dSnw 		*rid = 0;
67448258c6bSjp 	if (dn != NULL)
67548258c6bSjp 		*dn = NULL;
67648258c6bSjp 	if (attr != NULL)
67748258c6bSjp 		*attr = NULL;
67848258c6bSjp 	if (value != NULL)
67948258c6bSjp 		*value = NULL;
680c5c4113dSnw 
681479ac375Sdm 	/*
682479ac375Sdm 	 * Don't set *canonname to NULL because it may be pointing to the
683479ac375Sdm 	 * given winname. Later on if we get a canonical name from AD the
684479ac375Sdm 	 * old name if any will be freed before assigning the new name.
685479ac375Sdm 	 */
686479ac375Sdm 
687c5c4113dSnw 	/*
6882b4a7802SBaban Kenkre 	 * Invoke the mother of all APIs i.e. the adutils API
689c5c4113dSnw 	 */
6902b4a7802SBaban Kenkre 	ad_rc = adutils_lookup_batch_add(state->qs, filter,
6912b4a7802SBaban Kenkre 	    (const char **)attrs,
6922b4a7802SBaban Kenkre 	    edomain, &q->result, &q->ad_rc);
6932b4a7802SBaban Kenkre 	return (map_adrc2idmaprc(ad_rc));
694c5c4113dSnw }
695c5c4113dSnw 
696c5c4113dSnw idmap_retcode
idmap_name2sid_batch_add1(idmap_query_state_t * state,const char * name,const char * dname,idmap_id_type esidtype,char ** dn,char ** attr,char ** value,char ** canonname,char ** sid,rid_t * rid,idmap_id_type * sid_type,char ** unixname,posix_id_t * pid,idmap_retcode * rc)697c5c4113dSnw idmap_name2sid_batch_add1(idmap_query_state_t *state,
698*49160520SToomas Soome     const char *name, const char *dname, idmap_id_type esidtype,
699*49160520SToomas Soome     char **dn, char **attr, char **value,
700*49160520SToomas Soome     char **canonname, char **sid, rid_t *rid,
701*49160520SToomas Soome     idmap_id_type *sid_type, char **unixname,
702*49160520SToomas Soome     posix_id_t *pid, idmap_retcode *rc)
703c5c4113dSnw {
704c5c4113dSnw 	idmap_retcode	retcode;
705e3f2c991SKeyur Desai 	char		*filter, *s_name;
706cd37da74Snw 	char		*ecanonname, *edomain; /* expected canonname */
707c5c4113dSnw 
708c5c4113dSnw 	/*
709e3c2d6aaSnw 	 * Strategy: search the global catalog for user/group by
710e3c2d6aaSnw 	 * sAMAccountName = user/groupname with "" as the base DN and by
711e3c2d6aaSnw 	 * userPrincipalName = user/groupname@domain.  The result
712e3c2d6aaSnw 	 * entries will be checked to conform to the name and domain
713e3c2d6aaSnw 	 * name given here.  The DN, sAMAccountName, userPrincipalName,
714e3c2d6aaSnw 	 * objectSid and objectClass of the result entries are all we
715e3c2d6aaSnw 	 * need to figure out which entries match the lookup, the SID of
716e3c2d6aaSnw 	 * the user/group and whether it is a user or a group.
717c5c4113dSnw 	 */
718c5c4113dSnw 
719cd37da74Snw 	if ((ecanonname = strdup(name)) == NULL)
720cd37da74Snw 		return (IDMAP_ERR_MEMORY);
721cd37da74Snw 
722d3a612caSnw 	if (dname == NULL || *dname == '\0') {
723e3f2c991SKeyur Desai 		/* 'name' not qualified and dname not given */
724e3f2c991SKeyur Desai 		dname = state->default_domain;
725e3f2c991SKeyur Desai 		edomain = strdup(dname);
726e3f2c991SKeyur Desai 		if (edomain == NULL) {
727e3f2c991SKeyur Desai 			free(ecanonname);
728e3f2c991SKeyur Desai 			return (IDMAP_ERR_MEMORY);
729c5c4113dSnw 		}
730cd37da74Snw 	} else {
731cd37da74Snw 		if ((edomain = strdup(dname)) == NULL) {
732cd37da74Snw 			free(ecanonname);
733e3c2d6aaSnw 			return (IDMAP_ERR_MEMORY);
734cd37da74Snw 		}
735e3c2d6aaSnw 	}
736c5c4113dSnw 
7374d61c878SJulian Pullen 	if (!adutils_lookup_check_domain(state->qs, dname)) {
7384d61c878SJulian Pullen 		free(ecanonname);
7394d61c878SJulian Pullen 		free(edomain);
7404d61c878SJulian Pullen 		return (IDMAP_ERR_DOMAIN_NOTFOUND);
7414d61c878SJulian Pullen 	}
7424d61c878SJulian Pullen 
743479ac375Sdm 	s_name = sanitize_for_ldap_filter(name);
744479ac375Sdm 	if (s_name == NULL) {
745479ac375Sdm 		free(ecanonname);
746479ac375Sdm 		free(edomain);
747479ac375Sdm 		return (IDMAP_ERR_MEMORY);
748479ac375Sdm 	}
749479ac375Sdm 
750c5c4113dSnw 	/* Assemble filter */
751e3f2c991SKeyur Desai 	(void) asprintf(&filter, SANFILTER, s_name);
752e3f2c991SKeyur Desai 	if (s_name != name)
753e3f2c991SKeyur Desai 		free(s_name);
754e3f2c991SKeyur Desai 	if (filter == NULL) {
755cd37da74Snw 		free(ecanonname);
756479ac375Sdm 		free(edomain);
757c5c4113dSnw 		return (IDMAP_ERR_MEMORY);
758c5c4113dSnw 	}
759c5c4113dSnw 
760cd37da74Snw 	retcode = idmap_batch_add1(state, filter, ecanonname, edomain,
761148c5f43SAlan Wright 	    esidtype, dn, attr, value, canonname, NULL, sid, rid, sid_type,
762e3f2c991SKeyur Desai 	    unixname, pid, rc);
763c5c4113dSnw 
764c5c4113dSnw 	free(filter);
765c5c4113dSnw 
766c5c4113dSnw 	return (retcode);
767c5c4113dSnw }
768c5c4113dSnw 
769c5c4113dSnw idmap_retcode
idmap_sid2name_batch_add1(idmap_query_state_t * state,const char * sid,const rid_t * rid,idmap_id_type esidtype,char ** dn,char ** attr,char ** value,char ** name,char ** dname,idmap_id_type * sid_type,char ** unixname,posix_id_t * pid,idmap_retcode * rc)770c5c4113dSnw idmap_sid2name_batch_add1(idmap_query_state_t *state,
771*49160520SToomas Soome     const char *sid, const rid_t *rid, idmap_id_type esidtype,
772*49160520SToomas Soome     char **dn, char **attr, char **value,
773*49160520SToomas Soome     char **name, char **dname, idmap_id_type *sid_type,
774*49160520SToomas Soome     char **unixname, posix_id_t *pid, idmap_retcode *rc)
775c5c4113dSnw {
776c5c4113dSnw 	idmap_retcode	retcode;
777e3f2c991SKeyur Desai 	int		ret;
778e3f2c991SKeyur Desai 	char		*filter;
7792b4a7802SBaban Kenkre 	char		cbinsid[ADUTILS_MAXHEXBINSID + 1];
780c5c4113dSnw 
781c5c4113dSnw 	/*
782c5c4113dSnw 	 * Strategy: search [the global catalog] for user/group by
783c5c4113dSnw 	 * objectSid = SID with empty base DN.  The DN, sAMAccountName
784c5c4113dSnw 	 * and objectClass of the result are all we need to figure out
785c5c4113dSnw 	 * the name of the SID and whether it is a user, a group or a
786c5c4113dSnw 	 * computer.
787c5c4113dSnw 	 */
788c5c4113dSnw 
7894d61c878SJulian Pullen 	if (!adutils_lookup_check_sid_prefix(state->qs, sid))
7904d61c878SJulian Pullen 		return (IDMAP_ERR_DOMAIN_NOTFOUND);
7914d61c878SJulian Pullen 
7922b4a7802SBaban Kenkre 	ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid));
793c5c4113dSnw 	if (ret != 0)
794c5c4113dSnw 		return (IDMAP_ERR_SID);
795c5c4113dSnw 
796c5c4113dSnw 	/* Assemble filter */
797a01d29c9SMatt Barden 	(void) asprintf(&filter, OBJSIDFILTER, cbinsid, cbinsid);
798e3f2c991SKeyur Desai 	if (filter == NULL)
799c5c4113dSnw 		return (IDMAP_ERR_MEMORY);
800c5c4113dSnw 
801148c5f43SAlan Wright 	retcode = idmap_batch_add1(state, filter, NULL, NULL, esidtype,
802e3f2c991SKeyur Desai 	    dn, attr, value, name, dname, NULL, NULL, sid_type, unixname,
803e3f2c991SKeyur Desai 	    pid, rc);
804e8c27ec8Sbaban 
805e8c27ec8Sbaban 	free(filter);
806e8c27ec8Sbaban 
807e8c27ec8Sbaban 	return (retcode);
808e8c27ec8Sbaban }
809e8c27ec8Sbaban 
810e8c27ec8Sbaban idmap_retcode
idmap_unixname2sid_batch_add1(idmap_query_state_t * state,const char * unixname,int is_user,int is_wuser,char ** dn,char ** attr,char ** value,char ** sid,rid_t * rid,char ** name,char ** dname,idmap_id_type * sid_type,idmap_retcode * rc)811e8c27ec8Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
812*49160520SToomas Soome     const char *unixname, int is_user, int is_wuser,
813*49160520SToomas Soome     char **dn, char **attr, char **value,
814*49160520SToomas Soome     char **sid, rid_t *rid, char **name,
815*49160520SToomas Soome     char **dname, idmap_id_type *sid_type, idmap_retcode *rc)
816e8c27ec8Sbaban {
817e8c27ec8Sbaban 	idmap_retcode	retcode;
818e3f2c991SKeyur Desai 	char		*filter, *s_unixname;
819e3f2c991SKeyur Desai 	const char	*attrname;
820e8c27ec8Sbaban 
821e8c27ec8Sbaban 	/* Get unixuser or unixgroup AD attribute name */
822e8c27ec8Sbaban 	attrname = (is_user) ?
823e8c27ec8Sbaban 	    state->ad_unixuser_attr : state->ad_unixgroup_attr;
824e8c27ec8Sbaban 	if (attrname == NULL)
825e8c27ec8Sbaban 		return (IDMAP_ERR_NOTFOUND);
826e8c27ec8Sbaban 
827479ac375Sdm 	s_unixname = sanitize_for_ldap_filter(unixname);
828479ac375Sdm 	if (s_unixname == NULL)
829479ac375Sdm 		return (IDMAP_ERR_MEMORY);
830479ac375Sdm 
831e8c27ec8Sbaban 	/*  Assemble filter */
832e3f2c991SKeyur Desai 	(void) asprintf(&filter, "(&(objectclass=%s)(%s=%s))",
833e3f2c991SKeyur Desai 	    is_wuser ? "user" : "group", attrname, s_unixname);
834479ac375Sdm 	if (s_unixname != unixname)
835479ac375Sdm 		free(s_unixname);
836e3f2c991SKeyur Desai 	if (filter == NULL) {
837e3f2c991SKeyur Desai 		return (IDMAP_ERR_MEMORY);
838e3f2c991SKeyur Desai 	}
839e8c27ec8Sbaban 
840e8c27ec8Sbaban 	retcode = idmap_batch_add1(state, filter, NULL, NULL,
841148c5f43SAlan Wright 	    IDMAP_POSIXID, dn, NULL, NULL, name, dname, sid, rid, sid_type,
842e3f2c991SKeyur Desai 	    NULL, NULL, rc);
84348258c6bSjp 
84448258c6bSjp 	if (retcode == IDMAP_SUCCESS && attr != NULL) {
84548258c6bSjp 		if ((*attr = strdup(attrname)) == NULL)
84648258c6bSjp 			retcode = IDMAP_ERR_MEMORY;
84748258c6bSjp 	}
84848258c6bSjp 
84948258c6bSjp 	if (retcode == IDMAP_SUCCESS && value != NULL) {
850e3f2c991SKeyur Desai 		if ((*value = strdup(unixname)) == NULL)
851e3f2c991SKeyur Desai 			retcode = IDMAP_ERR_MEMORY;
852e3f2c991SKeyur Desai 	}
853e3f2c991SKeyur Desai 
854e3f2c991SKeyur Desai 	free(filter);
855e3f2c991SKeyur Desai 
856e3f2c991SKeyur Desai 	return (retcode);
857e3f2c991SKeyur Desai }
858e3f2c991SKeyur Desai 
859e3f2c991SKeyur Desai idmap_retcode
idmap_pid2sid_batch_add1(idmap_query_state_t * state,posix_id_t pid,int is_user,char ** dn,char ** attr,char ** value,char ** sid,rid_t * rid,char ** name,char ** dname,idmap_id_type * sid_type,idmap_retcode * rc)860e3f2c991SKeyur Desai idmap_pid2sid_batch_add1(idmap_query_state_t *state,
861*49160520SToomas Soome     posix_id_t pid, int is_user,
862*49160520SToomas Soome     char **dn, char **attr, char **value,
863*49160520SToomas Soome     char **sid, rid_t *rid, char **name,
864*49160520SToomas Soome     char **dname, idmap_id_type *sid_type, idmap_retcode *rc)
865e3f2c991SKeyur Desai {
866e3f2c991SKeyur Desai 	idmap_retcode	retcode;
867e3f2c991SKeyur Desai 	char		*filter;
868e3f2c991SKeyur Desai 	const char	*attrname;
869e3f2c991SKeyur Desai 
870e3f2c991SKeyur Desai 	/*  Assemble filter */
871e3f2c991SKeyur Desai 	if (is_user) {
872e3f2c991SKeyur Desai 		(void) asprintf(&filter, UIDNUMBERFILTER, pid);
873e3f2c991SKeyur Desai 		attrname = UIDNUMBER;
874e3f2c991SKeyur Desai 	} else {
875e3f2c991SKeyur Desai 		(void) asprintf(&filter, GIDNUMBERFILTER, pid);
876e3f2c991SKeyur Desai 		attrname = GIDNUMBER;
877e3f2c991SKeyur Desai 	}
878e3f2c991SKeyur Desai 	if (filter == NULL)
879e3f2c991SKeyur Desai 		return (IDMAP_ERR_MEMORY);
880e3f2c991SKeyur Desai 
881e3f2c991SKeyur Desai 	retcode = idmap_batch_add1(state, filter, NULL, NULL,
882148c5f43SAlan Wright 	    IDMAP_POSIXID, dn, NULL, NULL, name, dname, sid, rid, sid_type,
883e3f2c991SKeyur Desai 	    NULL, NULL, rc);
884e3f2c991SKeyur Desai 
885e3f2c991SKeyur Desai 	if (retcode == IDMAP_SUCCESS && attr != NULL) {
886e3f2c991SKeyur Desai 		if ((*attr = strdup(attrname)) == NULL)
887e3f2c991SKeyur Desai 			retcode = IDMAP_ERR_MEMORY;
888e3f2c991SKeyur Desai 	}
889e3f2c991SKeyur Desai 
890e3f2c991SKeyur Desai 	if (retcode == IDMAP_SUCCESS && value != NULL) {
891e3f2c991SKeyur Desai 		(void) asprintf(value, "%u", pid);
892e3f2c991SKeyur Desai 		if (*value == NULL)
893e3f2c991SKeyur Desai 			retcode = IDMAP_ERR_MEMORY;
89448258c6bSjp 	}
895c5c4113dSnw 
896c5c4113dSnw 	free(filter);
897c5c4113dSnw 
898c5c4113dSnw 	return (retcode);
899c5c4113dSnw }
900