xref: /illumos-gate/usr/src/cmd/idmap/idmapd/nldaputils.c (revision 479ac37569625bae44ffb80071d4bc865fc710ed)
1e8c27ec8Sbaban /*
2e8c27ec8Sbaban  * CDDL HEADER START
3e8c27ec8Sbaban  *
4e8c27ec8Sbaban  * The contents of this file are subject to the terms of the
5e8c27ec8Sbaban  * Common Development and Distribution License (the "License").
6e8c27ec8Sbaban  * You may not use this file except in compliance with the License.
7e8c27ec8Sbaban  *
8e8c27ec8Sbaban  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e8c27ec8Sbaban  * or http://www.opensolaris.org/os/licensing.
10e8c27ec8Sbaban  * See the License for the specific language governing permissions
11e8c27ec8Sbaban  * and limitations under the License.
12e8c27ec8Sbaban  *
13e8c27ec8Sbaban  * When distributing Covered Code, include this CDDL HEADER in each
14e8c27ec8Sbaban  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e8c27ec8Sbaban  * If applicable, add the following below this CDDL HEADER, with the
16e8c27ec8Sbaban  * fields enclosed by brackets "[]" replaced with your own identifying
17e8c27ec8Sbaban  * information: Portions Copyright [yyyy] [name of copyright owner]
18e8c27ec8Sbaban  *
19e8c27ec8Sbaban  * CDDL HEADER END
20e8c27ec8Sbaban  */
21e8c27ec8Sbaban 
22e8c27ec8Sbaban /*
23*479ac375Sdm  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24e8c27ec8Sbaban  * Use is subject to license terms.
25e8c27ec8Sbaban  */
26e8c27ec8Sbaban 
27e8c27ec8Sbaban #pragma ident	"%Z%%M%	%I%	%E% SMI"
28e8c27ec8Sbaban 
29e8c27ec8Sbaban /*
30e8c27ec8Sbaban  * native LDAP related utility routines
31e8c27ec8Sbaban  */
32e8c27ec8Sbaban 
33e8c27ec8Sbaban #include "idmapd.h"
34*479ac375Sdm #include "idmap_priv.h"
35*479ac375Sdm #include "ns_sldap.h"
36*479ac375Sdm #include "nldaputils.h"
37*479ac375Sdm #include <assert.h>
38e8c27ec8Sbaban 
39*479ac375Sdm /*
40*479ac375Sdm  * The following are format strings used to construct LDAP search filters
41*479ac375Sdm  * when looking up Native LDAP directory service. The _F_XXX_SSD format
42*479ac375Sdm  * is used by the libsldap API if a corresponding SSD is defined in
43*479ac375Sdm  * Native LDAP configuration. The SSD contains a string that replaces
44*479ac375Sdm  * the first %s in _F_XXX_SSD. If no SSD is defined then the regular
45*479ac375Sdm  * _F_XXX format is used.
46*479ac375Sdm  *
47*479ac375Sdm  * Note that '\\' needs to be represented as "\\5c" in LDAP filters.
48*479ac375Sdm  */
49*479ac375Sdm 
50*479ac375Sdm /* Native LDAP lookup using UNIX username */
51*479ac375Sdm #define	_F_GETPWNAM		"(&(objectClass=posixAccount)(uid=%s))"
52*479ac375Sdm #define	_F_GETPWNAM_SSD		"(&(%%s)(uid=%s))"
53*479ac375Sdm 
54*479ac375Sdm /*
55*479ac375Sdm  * Native LDAP user lookup using names of well-known SIDs
56*479ac375Sdm  * Note the use of 1$, 2$ in the format string which basically
57*479ac375Sdm  * allows snprintf to re-use its first two arguments.
58*479ac375Sdm  */
59*479ac375Sdm #define	_F_GETPWWNAMWK \
60*479ac375Sdm 		"(&(objectClass=posixAccount)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
61*479ac375Sdm #define	_F_GETPWWNAMWK_SSD	"(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
62*479ac375Sdm 
63*479ac375Sdm /* Native LDAP user lookup using winname@windomain OR windomain\winname */
64*479ac375Sdm #define	_F_GETPWWNAMDOM \
65*479ac375Sdm 	"(&(objectClass=posixAccount)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
66*479ac375Sdm #define	_F_GETPWWNAMDOM_SSD	"(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
67*479ac375Sdm 
68*479ac375Sdm /* Native LDAP lookup using UID */
69*479ac375Sdm #define	_F_GETPWUID		"(&(objectClass=posixAccount)(uidNumber=%u))"
70*479ac375Sdm #define	_F_GETPWUID_SSD		"(&(%%s)(uidNumber=%u))"
71*479ac375Sdm 
72*479ac375Sdm /* Native LDAP lookup using UNIX groupname */
73*479ac375Sdm #define	_F_GETGRNAM		"(&(objectClass=posixGroup)(cn=%s))"
74*479ac375Sdm #define	_F_GETGRNAM_SSD		"(&(%%s)(cn=%s))"
75*479ac375Sdm 
76*479ac375Sdm /* Native LDAP group lookup using names of well-known SIDs */
77*479ac375Sdm #define	_F_GETGRWNAMWK \
78*479ac375Sdm 		"(&(objectClass=posixGroup)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
79*479ac375Sdm #define	_F_GETGRWNAMWK_SSD	"(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
80*479ac375Sdm 
81*479ac375Sdm /* Native LDAP group lookup using winname@windomain OR windomain\winname */
82*479ac375Sdm #define	_F_GETGRWNAMDOM \
83*479ac375Sdm 		"(&(objectClass=posixGroup)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
84*479ac375Sdm #define	_F_GETGRWNAMDOM_SSD	"(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
85*479ac375Sdm 
86*479ac375Sdm /* Native LDAP lookup using GID */
87*479ac375Sdm #define	_F_GETGRGID		"(&(objectClass=posixGroup)(gidNumber=%u))"
88*479ac375Sdm #define	_F_GETGRGID_SSD		"(&(%%s)(gidNumber=%u))"
89*479ac375Sdm 
90*479ac375Sdm /* Native LDAP attribute names */
91*479ac375Sdm #define	UID			"uid"
92*479ac375Sdm #define	CN			"cn"
93*479ac375Sdm #define	UIDNUMBER		"uidnumber"
94*479ac375Sdm #define	GIDNUMBER		"gidnumber"
95*479ac375Sdm #define	DN			"dn"
96*479ac375Sdm 
97*479ac375Sdm #define	IS_NLDAP_RC_FATAL(x)	((x == NS_LDAP_MEMORY) ? 1 : 0)
98*479ac375Sdm 
99*479ac375Sdm typedef struct idmap_nldap_q {
100*479ac375Sdm 	char			**winname;
101*479ac375Sdm 	char			**windomain;
102*479ac375Sdm 	char			**unixname;
103*479ac375Sdm 	uid_t			*pid;
104*479ac375Sdm 	char			**dn;
105*479ac375Sdm 	char			**attr;
106*479ac375Sdm 	char			**value;
107*479ac375Sdm 	int			is_user;
108*479ac375Sdm 	idmap_retcode		*rc;
109*479ac375Sdm 	int			lrc;
110*479ac375Sdm 	ns_ldap_result_t	*result;
111*479ac375Sdm 	ns_ldap_error_t		*errorp;
112*479ac375Sdm 	char			*filter;
113*479ac375Sdm 	char			*udata;
114*479ac375Sdm } idmap_nldap_q_t;
115*479ac375Sdm 
116*479ac375Sdm typedef struct idmap_nldap_query_state {
117*479ac375Sdm 	const char		*nldap_winname_attr;
118*479ac375Sdm 	const char		*defdom;
119*479ac375Sdm 	int			nqueries;
120*479ac375Sdm 	int			qid;
121*479ac375Sdm 	int			flag;
122*479ac375Sdm 	ns_ldap_list_batch_t	*batch;
123*479ac375Sdm 	idmap_nldap_q_t		queries[1];
124*479ac375Sdm } idmap_nldap_query_state_t;
125*479ac375Sdm 
126*479ac375Sdm /*
127*479ac375Sdm  * This routine has been copied from lib/nsswitch/ldap/common/ldap_utils.c
128*479ac375Sdm  * after removing the debug statements.
129*479ac375Sdm  *
130*479ac375Sdm  * This is a generic filter callback function for merging the filter
131*479ac375Sdm  * from service search descriptor with an existing search filter. This
132*479ac375Sdm  * routine expects userdata to contain a format string with a single %s
133*479ac375Sdm  * in it, and will use the format string with sprintf() to insert the
134*479ac375Sdm  * SSD filter.
135*479ac375Sdm  *
136*479ac375Sdm  * This routine and userdata are passed to the __ns_ldap_list_batch_add()
137*479ac375Sdm  * API.
138*479ac375Sdm  *
139*479ac375Sdm  * Consider an example that uses __ns_ldap_list_batch_add() to lookup
140*479ac375Sdm  * native LDAP directory using a given userid 'xy12345'. In this
141*479ac375Sdm  * example the userdata will contain the filter "(&(%s)(cn=xy1234))".
142*479ac375Sdm  * If a SSD is defined to replace the rfc2307bis specified filter
143*479ac375Sdm  * i.e. (objectClass=posixAccount) by a site-specific filter
144*479ac375Sdm  * say (department=sds) then this routine when called will produce
145*479ac375Sdm  * "(&(department=sds)(uid=xy1234))" as the real search filter.
146*479ac375Sdm  */
147*479ac375Sdm static
148*479ac375Sdm int
149*479ac375Sdm merge_SSD_filter(const ns_ldap_search_desc_t *desc,
150*479ac375Sdm 	char **realfilter, const void *userdata)
151*479ac375Sdm {
152*479ac375Sdm 	int	len;
153*479ac375Sdm 	if (realfilter == NULL)
154*479ac375Sdm 		return (NS_LDAP_INVALID_PARAM);
155*479ac375Sdm 	*realfilter = NULL;
156*479ac375Sdm 	if (desc == NULL || desc->filter == NULL || userdata == NULL)
157*479ac375Sdm 		return (NS_LDAP_INVALID_PARAM);
158*479ac375Sdm 	len = strlen(userdata) + strlen(desc->filter) + 1;
159*479ac375Sdm 	*realfilter = (char *)malloc(len);
160*479ac375Sdm 	if (*realfilter == NULL)
161*479ac375Sdm 		return (NS_LDAP_MEMORY);
162*479ac375Sdm 	(void) sprintf(*realfilter, (char *)userdata, desc->filter);
163*479ac375Sdm 	return (NS_LDAP_SUCCESS);
164*479ac375Sdm }
165*479ac375Sdm 
166*479ac375Sdm static
167*479ac375Sdm char
168*479ac375Sdm hex_char(int n)
169*479ac375Sdm {
170*479ac375Sdm 	return ("0123456789abcdef"[n & 0xf]);
171*479ac375Sdm }
172*479ac375Sdm 
173*479ac375Sdm /*
174*479ac375Sdm  * If the input string contains special characters that needs to be
175*479ac375Sdm  * escaped before the string can be used in a LDAP filter then this
176*479ac375Sdm  * function will return a new sanitized string. Otherwise this function
177*479ac375Sdm  * returns the input string (This saves us un-necessary memory allocations
178*479ac375Sdm  * especially when processing a batch of requests). The caller must free
179*479ac375Sdm  * the returned string if it isn't the input string.
180*479ac375Sdm  *
181*479ac375Sdm  * The escape mechanism for LDAP filter is described in RFC2254 basically
182*479ac375Sdm  * it's \hh where hh are the two hexadecimal digits representing the ASCII
183*479ac375Sdm  * value of the encoded character (case of hh is not significant).
184*479ac375Sdm  * Example: * -> \2a, ( -> \28, ) -> \29, \ -> \5c,
185*479ac375Sdm  *
186*479ac375Sdm  * outstring = sanitize_for_ldap_filter(instring);
187*479ac375Sdm  * if (outstring == NULL)
188*479ac375Sdm  *	Out of memory
189*479ac375Sdm  * else
190*479ac375Sdm  *	Use outstring
191*479ac375Sdm  *	if (outstring != instring)
192*479ac375Sdm  *		free(outstring);
193*479ac375Sdm  * done
194*479ac375Sdm  */
195*479ac375Sdm char *
196*479ac375Sdm sanitize_for_ldap_filter(const char *str)
197*479ac375Sdm {
198*479ac375Sdm 	const char	*p;
199*479ac375Sdm 	char		*q, *s_str = NULL;
200*479ac375Sdm 	int		n;
201*479ac375Sdm 
202*479ac375Sdm 	/* Get a count of special characters */
203*479ac375Sdm 	for (p = str, n = 0; *p; p++)
204*479ac375Sdm 		if (*p == '*' || *p == '(' || *p == ')' ||
205*479ac375Sdm 		    *p == '\\' || *p == '%')
206*479ac375Sdm 			n++;
207*479ac375Sdm 	/* If count is zero then no need to sanitize */
208*479ac375Sdm 	if (n == 0)
209*479ac375Sdm 		return ((char *)str);
210*479ac375Sdm 	/* Create output buffer that will contain the sanitized value */
211*479ac375Sdm 	s_str = calloc(1, n * 2 + strlen(str) + 1);
212*479ac375Sdm 	if (s_str == NULL)
213*479ac375Sdm 		return (NULL);
214*479ac375Sdm 	for (p = str, q = s_str; *p; p++) {
215*479ac375Sdm 		if (*p == '*' || *p == '(' || *p == ')' ||
216*479ac375Sdm 		    *p == '\\' || *p == '%') {
217*479ac375Sdm 			*q++ = '\\';
218*479ac375Sdm 			*q++ = hex_char(*p >> 4);
219*479ac375Sdm 			*q++ = hex_char(*p & 0xf);
220*479ac375Sdm 		} else
221*479ac375Sdm 			*q++ = *p;
222*479ac375Sdm 	}
223*479ac375Sdm 	return (s_str);
224*479ac375Sdm }
225*479ac375Sdm 
226*479ac375Sdm /*
227*479ac375Sdm  * Map libsldap status to idmap  status
228*479ac375Sdm  */
229*479ac375Sdm static
230*479ac375Sdm idmap_retcode
231*479ac375Sdm nldaprc2retcode(int rc)
232*479ac375Sdm {
233*479ac375Sdm 	switch (rc) {
234*479ac375Sdm 	case NS_LDAP_SUCCESS:
235*479ac375Sdm 	case NS_LDAP_SUCCESS_WITH_INFO:
236*479ac375Sdm 		return (IDMAP_SUCCESS);
237*479ac375Sdm 	case NS_LDAP_NOTFOUND:
238*479ac375Sdm 		return (IDMAP_ERR_NOTFOUND);
239*479ac375Sdm 	case NS_LDAP_MEMORY:
240*479ac375Sdm 		return (IDMAP_ERR_MEMORY);
241*479ac375Sdm 	case NS_LDAP_CONFIG:
242*479ac375Sdm 		return (IDMAP_ERR_NS_LDAP_CFG);
243*479ac375Sdm 	case NS_LDAP_OP_FAILED:
244*479ac375Sdm 		return (IDMAP_ERR_NS_LDAP_OP_FAILED);
245*479ac375Sdm 	case NS_LDAP_PARTIAL:
246*479ac375Sdm 		return (IDMAP_ERR_NS_LDAP_PARTIAL);
247*479ac375Sdm 	case NS_LDAP_INTERNAL:
248*479ac375Sdm 		return (IDMAP_ERR_INTERNAL);
249*479ac375Sdm 	case NS_LDAP_INVALID_PARAM:
250*479ac375Sdm 		return (IDMAP_ERR_ARG);
251*479ac375Sdm 	default:
252*479ac375Sdm 		return (IDMAP_ERR_OTHER);
253*479ac375Sdm 	}
254*479ac375Sdm 	/*NOTREACHED*/
255*479ac375Sdm }
256*479ac375Sdm 
257*479ac375Sdm /*
258*479ac375Sdm  * Create a batch for native LDAP lookup.
259*479ac375Sdm  */
260*479ac375Sdm static
261*479ac375Sdm idmap_retcode
262*479ac375Sdm idmap_nldap_lookup_batch_start(int nqueries, idmap_nldap_query_state_t **qs)
263*479ac375Sdm {
264*479ac375Sdm 	idmap_nldap_query_state_t	*s;
265*479ac375Sdm 
266*479ac375Sdm 	s = calloc(1, sizeof (*s) +
267*479ac375Sdm 	    (nqueries - 1) * sizeof (idmap_nldap_q_t));
268*479ac375Sdm 	if (s == NULL)
269*479ac375Sdm 		return (IDMAP_ERR_MEMORY);
270*479ac375Sdm 	if (__ns_ldap_list_batch_start(&s->batch) != NS_LDAP_SUCCESS) {
271*479ac375Sdm 		free(s);
272*479ac375Sdm 		return (IDMAP_ERR_MEMORY);
273*479ac375Sdm 	}
274*479ac375Sdm 	s->nqueries = nqueries;
275*479ac375Sdm 	s->flag = NS_LDAP_KEEP_CONN;
276*479ac375Sdm 	*qs = s;
277*479ac375Sdm 	return (IDMAP_SUCCESS);
278*479ac375Sdm }
279*479ac375Sdm 
280*479ac375Sdm /*
281*479ac375Sdm  * Add a lookup by winname request to the batch.
282*479ac375Sdm  */
283*479ac375Sdm static
284e8c27ec8Sbaban idmap_retcode
285*479ac375Sdm idmap_nldap_bywinname_batch_add(idmap_nldap_query_state_t *qs,
286*479ac375Sdm 	const char *winname, const char *windomain, int is_user,
287*479ac375Sdm 	char **dn, char **attr, char **value,
288*479ac375Sdm 	char **unixname, uid_t *pid, idmap_retcode *rc)
289e8c27ec8Sbaban {
290*479ac375Sdm 	idmap_nldap_q_t		*q;
291*479ac375Sdm 	const char		*db, *filter, *udata;
292*479ac375Sdm 	int			flen, ulen, wksid = 0;
293*479ac375Sdm 	char			*s_winname, *s_windomain;
294*479ac375Sdm 	const char		**attrs;
295*479ac375Sdm 	const char		*pwd_attrs[] = {UID, UIDNUMBER, NULL, NULL};
296*479ac375Sdm 	const char		*grp_attrs[] = {CN, GIDNUMBER, NULL, NULL};
297*479ac375Sdm 
298*479ac375Sdm 	s_winname = s_windomain = NULL;
299*479ac375Sdm 	q = &(qs->queries[qs->qid++]);
300*479ac375Sdm 	q->unixname = unixname;
301*479ac375Sdm 	q->pid = pid;
302*479ac375Sdm 	q->rc = rc;
303*479ac375Sdm 	q->is_user = is_user;
304*479ac375Sdm 	q->dn = dn;
305*479ac375Sdm 	q->attr = attr;
306*479ac375Sdm 	q->value = value;
307*479ac375Sdm 
308*479ac375Sdm 	if (is_user) {
309*479ac375Sdm 		db = "passwd";
310*479ac375Sdm 		if (lookup_wksids_name2sid(winname, NULL, NULL, NULL,
311*479ac375Sdm 		    NULL) == IDMAP_SUCCESS) {
312*479ac375Sdm 			filter = _F_GETPWWNAMWK;
313*479ac375Sdm 			udata = _F_GETPWWNAMWK_SSD;
314*479ac375Sdm 			wksid = 1;
315*479ac375Sdm 		} else if (windomain != NULL) {
316*479ac375Sdm 			filter = _F_GETPWWNAMDOM;
317*479ac375Sdm 			udata = _F_GETPWWNAMDOM_SSD;
318*479ac375Sdm 		} else {
319*479ac375Sdm 			*q->rc = IDMAP_ERR_DOMAIN_NOTFOUND;
320*479ac375Sdm 			goto errout;
321*479ac375Sdm 		}
322*479ac375Sdm 		pwd_attrs[2] = qs->nldap_winname_attr;
323*479ac375Sdm 		attrs = pwd_attrs;
324*479ac375Sdm 	} else {
325*479ac375Sdm 		db = "group";
326*479ac375Sdm 		if (lookup_wksids_name2sid(winname, NULL, NULL, NULL,
327*479ac375Sdm 		    NULL) == IDMAP_SUCCESS) {
328*479ac375Sdm 			filter = _F_GETGRWNAMWK;
329*479ac375Sdm 			udata = _F_GETGRWNAMWK_SSD;
330*479ac375Sdm 			wksid = 1;
331*479ac375Sdm 		} else if (windomain != NULL) {
332*479ac375Sdm 			filter = _F_GETGRWNAMDOM;
333*479ac375Sdm 			udata = _F_GETGRWNAMDOM_SSD;
334*479ac375Sdm 		} else {
335*479ac375Sdm 			*q->rc = IDMAP_ERR_DOMAIN_NOTFOUND;
336*479ac375Sdm 			goto errout;
337*479ac375Sdm 		}
338*479ac375Sdm 		grp_attrs[2] = qs->nldap_winname_attr;
339*479ac375Sdm 		attrs = grp_attrs;
340*479ac375Sdm 	}
341*479ac375Sdm 
342e8c27ec8Sbaban 	/*
343*479ac375Sdm 	 * Sanitize names. No need to sanitize qs->nldap_winname_attr
344*479ac375Sdm 	 * because if it contained any of the special characters then
345*479ac375Sdm 	 * it would have been rejected by the function that reads it
346*479ac375Sdm 	 * from the SMF config. LDAP attribute names can only contain
347*479ac375Sdm 	 * letters, digits or hyphens.
348e8c27ec8Sbaban 	 */
349*479ac375Sdm 	s_winname = sanitize_for_ldap_filter(winname);
350*479ac375Sdm 	if (s_winname == NULL) {
351*479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
352*479ac375Sdm 		goto errout;
353*479ac375Sdm 	}
354*479ac375Sdm 	/* windomain could be NULL for names of well-known SIDs */
355*479ac375Sdm 	if (windomain != NULL) {
356*479ac375Sdm 		s_windomain = sanitize_for_ldap_filter(windomain);
357*479ac375Sdm 		if (s_windomain == NULL) {
358*479ac375Sdm 			*q->rc = IDMAP_ERR_MEMORY;
359*479ac375Sdm 			goto errout;
360*479ac375Sdm 		}
361*479ac375Sdm 	}
362*479ac375Sdm 
363*479ac375Sdm 	/* Construct the filter and udata using snprintf. */
364*479ac375Sdm 	if (wksid) {
365*479ac375Sdm 		flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr,
366*479ac375Sdm 		    s_winname) + 1;
367*479ac375Sdm 		ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr,
368*479ac375Sdm 		    s_winname) + 1;
369*479ac375Sdm 	} else {
370*479ac375Sdm 		flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr,
371*479ac375Sdm 		    s_winname, s_windomain) + 1;
372*479ac375Sdm 		ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr,
373*479ac375Sdm 		    s_winname, s_windomain) + 1;
374*479ac375Sdm 	}
375*479ac375Sdm 
376*479ac375Sdm 	q->filter = malloc(flen);
377*479ac375Sdm 	if (q->filter == NULL) {
378*479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
379*479ac375Sdm 		goto errout;
380*479ac375Sdm 	}
381*479ac375Sdm 	q->udata = malloc(ulen);
382*479ac375Sdm 	if (q->udata == NULL) {
383*479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
384*479ac375Sdm 		goto errout;
385*479ac375Sdm 	}
386*479ac375Sdm 
387*479ac375Sdm 	if (wksid) {
388*479ac375Sdm 		(void) snprintf(q->filter, flen, filter,
389*479ac375Sdm 		    qs->nldap_winname_attr, s_winname);
390*479ac375Sdm 		(void) snprintf(q->udata, ulen, udata,
391*479ac375Sdm 		    qs->nldap_winname_attr, s_winname);
392*479ac375Sdm 	} else {
393*479ac375Sdm 		(void) snprintf(q->filter, flen, filter,
394*479ac375Sdm 		    qs->nldap_winname_attr, s_winname, s_windomain);
395*479ac375Sdm 		(void) snprintf(q->udata, ulen, udata,
396*479ac375Sdm 		    qs->nldap_winname_attr, s_winname, s_windomain);
397*479ac375Sdm 	}
398*479ac375Sdm 
399*479ac375Sdm 	if (s_winname != winname)
400*479ac375Sdm 		free(s_winname);
401*479ac375Sdm 	if (s_windomain != windomain)
402*479ac375Sdm 		free(s_windomain);
403*479ac375Sdm 
404*479ac375Sdm 	q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
405*479ac375Sdm 	    merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
406*479ac375Sdm 	    &q->errorp, &q->lrc, NULL, q->udata);
407*479ac375Sdm 
408*479ac375Sdm 	if (IS_NLDAP_RC_FATAL(q->lrc))
409*479ac375Sdm 		return (nldaprc2retcode(q->lrc));
410*479ac375Sdm 	return (IDMAP_SUCCESS);
411*479ac375Sdm 
412*479ac375Sdm errout:
413*479ac375Sdm 	/* query q and its content will be freed by batch_release */
414*479ac375Sdm 	if (s_winname != winname)
415*479ac375Sdm 		free(s_winname);
416*479ac375Sdm 	if (s_windomain != windomain)
417*479ac375Sdm 		free(s_windomain);
418*479ac375Sdm 	return (*q->rc);
419*479ac375Sdm }
420*479ac375Sdm 
421*479ac375Sdm /*
422*479ac375Sdm  * Add a lookup by uid/gid request to the batch.
423*479ac375Sdm  */
424*479ac375Sdm static
425*479ac375Sdm idmap_retcode
426*479ac375Sdm idmap_nldap_bypid_batch_add(idmap_nldap_query_state_t *qs,
427*479ac375Sdm 	uid_t pid, int is_user, char **dn, char **attr, char **value,
428*479ac375Sdm 	char **winname, char **windomain,
429*479ac375Sdm 	char **unixname, idmap_retcode *rc)
430*479ac375Sdm {
431*479ac375Sdm 	idmap_nldap_q_t		*q;
432*479ac375Sdm 	const char		*db, *filter, *udata;
433*479ac375Sdm 	int			len;
434*479ac375Sdm 	const char		**attrs;
435*479ac375Sdm 	const char		*pwd_attrs[] = {UID, NULL, NULL};
436*479ac375Sdm 	const char		*grp_attrs[] = {CN, NULL, NULL};
437*479ac375Sdm 
438*479ac375Sdm 	q = &(qs->queries[qs->qid++]);
439*479ac375Sdm 	q->winname = winname;
440*479ac375Sdm 	q->windomain = windomain;
441*479ac375Sdm 	q->unixname = unixname;
442*479ac375Sdm 	q->rc = rc;
443*479ac375Sdm 	q->is_user = is_user;
444*479ac375Sdm 	q->dn = dn;
445*479ac375Sdm 	q->attr = attr;
446*479ac375Sdm 	q->value = value;
447*479ac375Sdm 
448*479ac375Sdm 	if (is_user) {
449*479ac375Sdm 		db = "passwd";
450*479ac375Sdm 		filter = _F_GETPWUID;
451*479ac375Sdm 		udata = _F_GETPWUID_SSD;
452*479ac375Sdm 		pwd_attrs[1] = qs->nldap_winname_attr;
453*479ac375Sdm 		attrs = pwd_attrs;
454*479ac375Sdm 	} else {
455*479ac375Sdm 		db = "group";
456*479ac375Sdm 		filter = _F_GETGRGID;
457*479ac375Sdm 		udata = _F_GETGRGID_SSD;
458*479ac375Sdm 		grp_attrs[1] = qs->nldap_winname_attr;
459*479ac375Sdm 		attrs = grp_attrs;
460*479ac375Sdm 	}
461*479ac375Sdm 
462*479ac375Sdm 	len = snprintf(NULL, 0, filter, pid) + 1;
463*479ac375Sdm 	q->filter = malloc(len);
464*479ac375Sdm 	if (q->filter == NULL) {
465*479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
466*479ac375Sdm 		return (IDMAP_ERR_MEMORY);
467*479ac375Sdm 	}
468*479ac375Sdm 	(void) snprintf(q->filter, len, filter, pid);
469*479ac375Sdm 
470*479ac375Sdm 	len = snprintf(NULL, 0, udata, pid) + 1;
471*479ac375Sdm 	q->udata = malloc(len);
472*479ac375Sdm 	if (q->udata == NULL) {
473*479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
474*479ac375Sdm 		return (IDMAP_ERR_MEMORY);
475*479ac375Sdm 	}
476*479ac375Sdm 	(void) snprintf(q->udata, len, udata, pid);
477*479ac375Sdm 
478*479ac375Sdm 	q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
479*479ac375Sdm 	    merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
480*479ac375Sdm 	    &q->errorp, &q->lrc, NULL, q->udata);
481*479ac375Sdm 
482*479ac375Sdm 	if (IS_NLDAP_RC_FATAL(q->lrc))
483*479ac375Sdm 		return (nldaprc2retcode(q->lrc));
484*479ac375Sdm 	return (IDMAP_SUCCESS);
485*479ac375Sdm }
486*479ac375Sdm 
487*479ac375Sdm /*
488*479ac375Sdm  * Add a lookup by user/group name request to the batch.
489*479ac375Sdm  */
490*479ac375Sdm static
491*479ac375Sdm idmap_retcode
492*479ac375Sdm idmap_nldap_byunixname_batch_add(idmap_nldap_query_state_t *qs,
493*479ac375Sdm 	const char *unixname, int is_user,
494*479ac375Sdm 	char **dn, char **attr, char **value,
495*479ac375Sdm 	char **winname, char **windomain, uid_t *pid, idmap_retcode *rc)
496*479ac375Sdm {
497*479ac375Sdm 	idmap_nldap_q_t		*q;
498*479ac375Sdm 	const char		*db, *filter, *udata;
499*479ac375Sdm 	int			len;
500*479ac375Sdm 	char			*s_unixname = NULL;
501*479ac375Sdm 	const char		**attrs;
502*479ac375Sdm 	const char		*pwd_attrs[] = {UIDNUMBER, NULL, NULL};
503*479ac375Sdm 	const char		*grp_attrs[] = {GIDNUMBER, NULL, NULL};
504*479ac375Sdm 
505*479ac375Sdm 	q = &(qs->queries[qs->qid++]);
506*479ac375Sdm 	q->winname = winname;
507*479ac375Sdm 	q->windomain = windomain;
508*479ac375Sdm 	q->pid = pid;
509*479ac375Sdm 	q->rc = rc;
510*479ac375Sdm 	q->is_user = is_user;
511*479ac375Sdm 	q->dn = dn;
512*479ac375Sdm 	q->attr = attr;
513*479ac375Sdm 	q->value = value;
514*479ac375Sdm 
515*479ac375Sdm 	if (is_user) {
516*479ac375Sdm 		db = "passwd";
517*479ac375Sdm 		filter = _F_GETPWNAM;
518*479ac375Sdm 		udata = _F_GETPWNAM_SSD;
519*479ac375Sdm 		pwd_attrs[1] = qs->nldap_winname_attr;
520*479ac375Sdm 		attrs = pwd_attrs;
521*479ac375Sdm 	} else {
522*479ac375Sdm 		db = "group";
523*479ac375Sdm 		filter = _F_GETGRNAM;
524*479ac375Sdm 		udata = _F_GETGRNAM_SSD;
525*479ac375Sdm 		grp_attrs[1] = qs->nldap_winname_attr;
526*479ac375Sdm 		attrs = grp_attrs;
527*479ac375Sdm 	}
528*479ac375Sdm 
529*479ac375Sdm 	s_unixname = sanitize_for_ldap_filter(unixname);
530*479ac375Sdm 	if (s_unixname == NULL) {
531*479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
532*479ac375Sdm 		return (IDMAP_ERR_MEMORY);
533*479ac375Sdm 	}
534*479ac375Sdm 
535*479ac375Sdm 	len = snprintf(NULL, 0, filter, s_unixname) + 1;
536*479ac375Sdm 	q->filter = malloc(len);
537*479ac375Sdm 	if (q->filter == NULL) {
538*479ac375Sdm 		if (s_unixname != unixname)
539*479ac375Sdm 			free(s_unixname);
540*479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
541*479ac375Sdm 		return (IDMAP_ERR_MEMORY);
542*479ac375Sdm 	}
543*479ac375Sdm 	(void) snprintf(q->filter, len, filter, s_unixname);
544*479ac375Sdm 
545*479ac375Sdm 	len = snprintf(NULL, 0, udata, s_unixname) + 1;
546*479ac375Sdm 	q->udata = malloc(len);
547*479ac375Sdm 	if (q->udata == NULL) {
548*479ac375Sdm 		if (s_unixname != unixname)
549*479ac375Sdm 			free(s_unixname);
550*479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
551*479ac375Sdm 		return (IDMAP_ERR_MEMORY);
552*479ac375Sdm 	}
553*479ac375Sdm 	(void) snprintf(q->udata, len, udata, s_unixname);
554*479ac375Sdm 
555*479ac375Sdm 	if (s_unixname != unixname)
556*479ac375Sdm 		free(s_unixname);
557*479ac375Sdm 
558*479ac375Sdm 	q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
559*479ac375Sdm 	    merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
560*479ac375Sdm 	    &q->errorp, &q->lrc, NULL, q->udata);
561*479ac375Sdm 
562*479ac375Sdm 	if (IS_NLDAP_RC_FATAL(q->lrc))
563*479ac375Sdm 		return (nldaprc2retcode(q->lrc));
564*479ac375Sdm 	return (IDMAP_SUCCESS);
565*479ac375Sdm }
566*479ac375Sdm 
567*479ac375Sdm /*
568*479ac375Sdm  * Free the batch
569*479ac375Sdm  */
570*479ac375Sdm static
571*479ac375Sdm void
572*479ac375Sdm idmap_nldap_lookup_batch_release(idmap_nldap_query_state_t *qs)
573*479ac375Sdm {
574*479ac375Sdm 	idmap_nldap_q_t		*q;
575*479ac375Sdm 	int			i;
576*479ac375Sdm 
577*479ac375Sdm 	if (qs->batch != NULL)
578*479ac375Sdm 		(void) __ns_ldap_list_batch_release(qs->batch);
579*479ac375Sdm 	for (i = 0; i < qs->qid; i++) {
580*479ac375Sdm 		q = &(qs->queries[i]);
581*479ac375Sdm 		free(q->filter);
582*479ac375Sdm 		free(q->udata);
583*479ac375Sdm 		if (q->errorp != NULL)
584*479ac375Sdm 			(void) __ns_ldap_freeError(&q->errorp);
585*479ac375Sdm 		if (q->result != NULL)
586*479ac375Sdm 			(void) __ns_ldap_freeResult(&q->result);
587*479ac375Sdm 	}
588*479ac375Sdm 	free(qs);
589*479ac375Sdm }
590*479ac375Sdm 
591*479ac375Sdm /*
592*479ac375Sdm  * Process all requests added to the batch and then free the batch.
593*479ac375Sdm  * The results for individual requests will be accessible using the
594*479ac375Sdm  * pointers passed during idmap_nldap_lookup_batch_end.
595*479ac375Sdm  */
596*479ac375Sdm static
597*479ac375Sdm idmap_retcode
598*479ac375Sdm idmap_nldap_lookup_batch_end(idmap_nldap_query_state_t *qs)
599*479ac375Sdm {
600*479ac375Sdm 	idmap_nldap_q_t		*q;
601*479ac375Sdm 	int			i;
602*479ac375Sdm 	ns_ldap_entry_t		*entry;
603*479ac375Sdm 	char			**val, *end, *str, *name, *dom;
604*479ac375Sdm 	idmap_retcode		rc = IDMAP_SUCCESS;
605*479ac375Sdm 
606*479ac375Sdm 	(void) __ns_ldap_list_batch_end(qs->batch);
607*479ac375Sdm 	qs->batch = NULL;
608*479ac375Sdm 	for (i = 0; i < qs->qid; i++) {
609*479ac375Sdm 		q = &(qs->queries[i]);
610*479ac375Sdm 		*q->rc = nldaprc2retcode(q->lrc);
611*479ac375Sdm 		if (*q->rc != IDMAP_SUCCESS)
612*479ac375Sdm 			continue;
613*479ac375Sdm 		if (q->result == NULL ||
614*479ac375Sdm 		    !q->result->entries_count ||
615*479ac375Sdm 		    (entry = q->result->entry) == NULL ||
616*479ac375Sdm 		    !entry->attr_count) {
617*479ac375Sdm 			*q->rc = IDMAP_ERR_NOTFOUND;
618*479ac375Sdm 			continue;
619*479ac375Sdm 		}
620*479ac375Sdm 		/* Get uid/gid */
621*479ac375Sdm 		if (q->pid != NULL) {
622*479ac375Sdm 			val = __ns_ldap_getAttr(entry,
623*479ac375Sdm 			    (q->is_user) ? UIDNUMBER : GIDNUMBER);
624*479ac375Sdm 			if (val != NULL && *val != NULL)
625*479ac375Sdm 				*q->pid = strtoul(*val, &end, 10);
626*479ac375Sdm 		}
627*479ac375Sdm 		/* Get unixname */
628*479ac375Sdm 		if (q->unixname != NULL) {
629*479ac375Sdm 			val = __ns_ldap_getAttr(entry,
630*479ac375Sdm 			    (q->is_user) ? UID : CN);
631*479ac375Sdm 			if (val != NULL && *val != NULL) {
632*479ac375Sdm 				*q->unixname = strdup(*val);
633*479ac375Sdm 				if (*q->unixname == NULL) {
634*479ac375Sdm 					rc = *q->rc = IDMAP_ERR_MEMORY;
635*479ac375Sdm 					goto out;
636*479ac375Sdm 				}
637*479ac375Sdm 			}
638*479ac375Sdm 		}
639*479ac375Sdm 		/* Get DN for how info */
640*479ac375Sdm 		if (q->dn != NULL) {
641*479ac375Sdm 			val = __ns_ldap_getAttr(entry, DN);
642*479ac375Sdm 			if (val != NULL && *val != NULL) {
643*479ac375Sdm 				*q->dn = strdup(*val);
644*479ac375Sdm 				if (*q->dn == NULL) {
645*479ac375Sdm 					rc = *q->rc = IDMAP_ERR_MEMORY;
646*479ac375Sdm 					goto out;
647*479ac375Sdm 				}
648*479ac375Sdm 			}
649*479ac375Sdm 		}
650*479ac375Sdm 		/* Get nldap name mapping attr name for how info */
651*479ac375Sdm 		if (q->attr != NULL) {
652*479ac375Sdm 			*q->attr = strdup(qs->nldap_winname_attr);
653*479ac375Sdm 			if (*q->attr == NULL) {
654*479ac375Sdm 				rc = *q->rc = IDMAP_ERR_MEMORY;
655*479ac375Sdm 				goto out;
656*479ac375Sdm 			}
657*479ac375Sdm 		}
658*479ac375Sdm 		/* Get nldap name mapping attr value for how info */
659*479ac375Sdm 		val =  __ns_ldap_getAttr(entry, qs->nldap_winname_attr);
660*479ac375Sdm 		if (val == NULL || *val == NULL)
661*479ac375Sdm 			continue;
662*479ac375Sdm 		if (q->value != NULL) {
663*479ac375Sdm 			*q->value = strdup(*val);
664*479ac375Sdm 			if (*q->value == NULL) {
665*479ac375Sdm 				rc = *q->rc = IDMAP_ERR_MEMORY;
666*479ac375Sdm 				goto out;
667*479ac375Sdm 			}
668*479ac375Sdm 		}
669*479ac375Sdm 
670*479ac375Sdm 		/* Get winname and windomain */
671*479ac375Sdm 		if (q->winname == NULL && q->windomain == NULL)
672*479ac375Sdm 			continue;
673*479ac375Sdm 		/*
674*479ac375Sdm 		 * We need to split the value into winname and
675*479ac375Sdm 		 * windomain. The value could be either in NT4
676*479ac375Sdm 		 * style (i.e. dom\name) or AD-style (i.e. name@dom).
677*479ac375Sdm 		 * We choose the first '\\' if it's in NT4 style and
678*479ac375Sdm 		 * the last '@' if it's in AD-style for the split.
679*479ac375Sdm 		 */
680*479ac375Sdm 		name = dom = NULL;
681*479ac375Sdm 		if (lookup_wksids_name2sid(*val, NULL, NULL, NULL, NULL) ==
682*479ac375Sdm 		    IDMAP_SUCCESS) {
683*479ac375Sdm 			name = *val;
684*479ac375Sdm 			dom = NULL;
685*479ac375Sdm 		} else if ((str = strchr(*val, '\\')) != NULL) {
686*479ac375Sdm 			*str = '\0';
687*479ac375Sdm 			name = str + 1;
688*479ac375Sdm 			dom = *val;
689*479ac375Sdm 		} else if ((str = strrchr(*val, '@')) != NULL) {
690*479ac375Sdm 			*str = '\0';
691*479ac375Sdm 			name = *val;
692*479ac375Sdm 			dom = str + 1;
693*479ac375Sdm 		} else {
694*479ac375Sdm 			idmapdlog(LOG_INFO, "Domain-less "
695*479ac375Sdm 			    "winname (%s) found in Native LDAP", *val);
696*479ac375Sdm 			*q->rc = IDMAP_ERR_NS_LDAP_BAD_WINNAME;
697*479ac375Sdm 			continue;
698*479ac375Sdm 		}
699*479ac375Sdm 		if (q->winname != NULL) {
700*479ac375Sdm 			*q->winname = strdup(name);
701*479ac375Sdm 			if (*q->winname == NULL) {
702*479ac375Sdm 				rc = *q->rc = IDMAP_ERR_MEMORY;
703*479ac375Sdm 				goto out;
704*479ac375Sdm 			}
705*479ac375Sdm 		}
706*479ac375Sdm 		if (q->windomain != NULL && dom != NULL) {
707*479ac375Sdm 			*q->windomain = strdup(dom);
708*479ac375Sdm 			if (*q->windomain == NULL) {
709*479ac375Sdm 				rc = *q->rc = IDMAP_ERR_MEMORY;
710*479ac375Sdm 				goto out;
711*479ac375Sdm 			}
712*479ac375Sdm 		}
713*479ac375Sdm 	}
714*479ac375Sdm 
715*479ac375Sdm out:
716*479ac375Sdm 	(void) idmap_nldap_lookup_batch_release(qs);
717*479ac375Sdm 	return (rc);
718*479ac375Sdm }
719*479ac375Sdm 
720*479ac375Sdm /* ARGSUSED */
721*479ac375Sdm idmap_retcode
722*479ac375Sdm nldap_lookup_one(lookup_state_t *state, idmap_mapping *req, idmap_id_res *res)
723*479ac375Sdm {
724*479ac375Sdm 	idmap_mapping_batch	batch;
725*479ac375Sdm 	idmap_ids_res		result;
726*479ac375Sdm 
727*479ac375Sdm 	/* Using nldap_lookup_batch() */
728*479ac375Sdm 
729*479ac375Sdm 	batch.idmap_mapping_batch_len = 1;
730*479ac375Sdm 	batch.idmap_mapping_batch_val = req;
731*479ac375Sdm 	result.ids.ids_len = 1;
732*479ac375Sdm 	result.ids.ids_val = res;
733*479ac375Sdm 	return (nldap_lookup_batch(state, &batch, &result));
734e8c27ec8Sbaban }
735e8c27ec8Sbaban 
736e8c27ec8Sbaban /* ARGSUSED */
737e8c27ec8Sbaban idmap_retcode
738e8c27ec8Sbaban nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
739e8c27ec8Sbaban 		idmap_ids_res *result)
740e8c27ec8Sbaban {
741*479ac375Sdm 	idmap_retcode			retcode, rc1;
742*479ac375Sdm 	int				i, add, is_wuser;
743*479ac375Sdm 	idmap_mapping			*req;
744*479ac375Sdm 	idmap_id_res			*res;
745*479ac375Sdm 	idmap_nldap_query_state_t	*qs = NULL;
746*479ac375Sdm 	idmap_how			*how;
747*479ac375Sdm 
748*479ac375Sdm 	if (state->nldap_nqueries == 0)
749*479ac375Sdm 		return (IDMAP_SUCCESS);
750*479ac375Sdm 
751*479ac375Sdm 	/* Create nldap lookup batch */
752*479ac375Sdm 	retcode = idmap_nldap_lookup_batch_start(state->nldap_nqueries, &qs);
753*479ac375Sdm 	if (retcode != IDMAP_SUCCESS) {
754*479ac375Sdm 		idmapdlog(LOG_ERR,
755*479ac375Sdm 		    "Failed to create batch for native LDAP lookup");
756*479ac375Sdm 		goto out;
757*479ac375Sdm 	}
758*479ac375Sdm 
759*479ac375Sdm 	qs->nldap_winname_attr = state->nldap_winname_attr;
760*479ac375Sdm 	qs->defdom = state->defdom;
761*479ac375Sdm 
762*479ac375Sdm 	/* Add requests to the batch */
763*479ac375Sdm 	for (i = 0, add = 0; i < batch->idmap_mapping_batch_len; i++) {
764*479ac375Sdm 		req = &batch->idmap_mapping_batch_val[i];
765*479ac375Sdm 		res = &result->ids.ids_val[i];
766*479ac375Sdm 		retcode = IDMAP_SUCCESS;
767*479ac375Sdm 
768*479ac375Sdm 		/* Skip if not marked for nldap lookup */
769*479ac375Sdm 		if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP))
770*479ac375Sdm 			continue;
771*479ac375Sdm 
772*479ac375Sdm 		if (IS_REQUEST_SID(*req, 1)) {
773*479ac375Sdm 
774*479ac375Sdm 			/* win2unix request: */
775*479ac375Sdm 
776*479ac375Sdm 			/*
777*479ac375Sdm 			 * When processing a win2unix request, nldap lookup
778*479ac375Sdm 			 * is performed after AD lookup or a successful
779*479ac375Sdm 			 * name-cache lookup. Therefore we should already
780*479ac375Sdm 			 * have sid, winname and sidtype. Note that
781*479ac375Sdm 			 * windomain could be NULL e.g. well-known SIDs.
782*479ac375Sdm 			 */
783*479ac375Sdm 			assert(req->id1name != NULL &&
784*479ac375Sdm 			    (res->id.idtype == IDMAP_UID ||
785*479ac375Sdm 			    res->id.idtype == IDMAP_GID));
786*479ac375Sdm 
787*479ac375Sdm 			/* Skip if we already have pid and unixname */
788*479ac375Sdm 			if (req->id2name != NULL &&
789*479ac375Sdm 			    res->id.idmap_id_u.uid != SENTINEL_PID) {
790*479ac375Sdm 				res->retcode = IDMAP_SUCCESS;
791*479ac375Sdm 				continue;
792*479ac375Sdm 			}
793*479ac375Sdm 
794*479ac375Sdm 			/* Clear leftover value */
795*479ac375Sdm 			free(req->id2name);
796*479ac375Sdm 			req->id2name = NULL;
797*479ac375Sdm 
798*479ac375Sdm 			/* Lookup nldap by winname to get pid and unixname */
799*479ac375Sdm 			add = 1;
800*479ac375Sdm 			idmap_info_free(&res->info);
801*479ac375Sdm 			res->info.src = IDMAP_MAP_SRC_NEW;
802*479ac375Sdm 			how = &res->info.how;
803*479ac375Sdm 			how->map_type = IDMAP_MAP_TYPE_DS_NLDAP;
804*479ac375Sdm 			retcode = idmap_nldap_bywinname_batch_add(
805*479ac375Sdm 			    qs, req->id1name, req->id1domain,
806*479ac375Sdm 			    (res->id.idtype == IDMAP_UID) ? 1 : 0,
807*479ac375Sdm 			    &how->idmap_how_u.nldap.dn,
808*479ac375Sdm 			    &how->idmap_how_u.nldap.attr,
809*479ac375Sdm 			    &how->idmap_how_u.nldap.value,
810*479ac375Sdm 			    &req->id2name, &res->id.idmap_id_u.uid,
811*479ac375Sdm 			    &res->retcode);
812*479ac375Sdm 
813*479ac375Sdm 		} else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) {
814*479ac375Sdm 
815*479ac375Sdm 			/* unix2win request: */
816*479ac375Sdm 
817*479ac375Sdm 			/* Skip if we already have winname */
818*479ac375Sdm 			if (req->id2name != NULL) {
819*479ac375Sdm 				res->retcode = IDMAP_SUCCESS;
820*479ac375Sdm 				continue;
821*479ac375Sdm 			}
822*479ac375Sdm 
823*479ac375Sdm 			/* Clear old value */
824*479ac375Sdm 			free(req->id2domain);
825*479ac375Sdm 			req->id2domain = NULL;
826*479ac375Sdm 
827*479ac375Sdm 			/* Set how info */
828*479ac375Sdm 			idmap_info_free(&res->info);
829*479ac375Sdm 			res->info.src = IDMAP_MAP_SRC_NEW;
830*479ac375Sdm 			how = &res->info.how;
831*479ac375Sdm 			how->map_type = IDMAP_MAP_TYPE_DS_NLDAP;
832*479ac375Sdm 
833*479ac375Sdm 			/* Lookup nldap by pid or unixname to get winname */
834*479ac375Sdm 			if (req->id1.idmap_id_u.uid != SENTINEL_PID) {
835*479ac375Sdm 				add = 1;
836*479ac375Sdm 				retcode = idmap_nldap_bypid_batch_add(
837*479ac375Sdm 				    qs, req->id1.idmap_id_u.uid,
838*479ac375Sdm 				    (req->id1.idtype == IDMAP_UID) ? 1 : 0,
839*479ac375Sdm 				    &how->idmap_how_u.nldap.dn,
840*479ac375Sdm 				    &how->idmap_how_u.nldap.attr,
841*479ac375Sdm 				    &how->idmap_how_u.nldap.value,
842*479ac375Sdm 				    &req->id2name, &req->id2domain,
843*479ac375Sdm 				    (req->id1name == NULL) ?
844*479ac375Sdm 				    &req->id1name : NULL,
845*479ac375Sdm 				    &res->retcode);
846*479ac375Sdm 			} else if (req->id1name != NULL) {
847*479ac375Sdm 				add = 1;
848*479ac375Sdm 				retcode = idmap_nldap_byunixname_batch_add(
849*479ac375Sdm 				    qs, req->id1name,
850*479ac375Sdm 				    (req->id1.idtype == IDMAP_UID) ? 1 : 0,
851*479ac375Sdm 				    &how->idmap_how_u.nldap.dn,
852*479ac375Sdm 				    &how->idmap_how_u.nldap.attr,
853*479ac375Sdm 				    &how->idmap_how_u.nldap.value,
854*479ac375Sdm 				    &req->id2name, &req->id2domain,
855*479ac375Sdm 				    &req->id1.idmap_id_u.uid, &res->retcode);
856*479ac375Sdm 			}
857*479ac375Sdm 
858*479ac375Sdm 		}
859*479ac375Sdm 
860*479ac375Sdm 		/*
861*479ac375Sdm 		 * nldap_batch_add API returns error only on fatal failures
862*479ac375Sdm 		 * otherwise it returns success and the actual status
863*479ac375Sdm 		 * is stored in the individual request (res->retcode).
864*479ac375Sdm 		 * Stop adding requests to this batch on fatal failures
865*479ac375Sdm 		 * (i.e. if retcode != success)
866*479ac375Sdm 		 */
867*479ac375Sdm 		if (retcode != IDMAP_SUCCESS)
868*479ac375Sdm 			break;
869*479ac375Sdm 	}
870*479ac375Sdm 
871*479ac375Sdm 	if (!add)
872*479ac375Sdm 		idmap_nldap_lookup_batch_release(qs);
873*479ac375Sdm 	else if (retcode != IDMAP_SUCCESS)
874*479ac375Sdm 		idmap_nldap_lookup_batch_release(qs);
875*479ac375Sdm 	else
876*479ac375Sdm 		retcode = idmap_nldap_lookup_batch_end(qs);
877*479ac375Sdm 
878*479ac375Sdm out:
879*479ac375Sdm 	for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
880*479ac375Sdm 		req = &batch->idmap_mapping_batch_val[i];
881*479ac375Sdm 		res = &result->ids.ids_val[i];
882*479ac375Sdm 		if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP))
883*479ac375Sdm 			continue;
884*479ac375Sdm 
885*479ac375Sdm 		/* Reset nldap flag */
886*479ac375Sdm 		req->direction &= ~(_IDMAP_F_LOOKUP_NLDAP);
887*479ac375Sdm 
888*479ac375Sdm 		/*
889*479ac375Sdm 		 * As noted earlier retcode != success if there were fatal
890*479ac375Sdm 		 * errors during batch_start and batch_adds. If so then set
891*479ac375Sdm 		 * the status of each nldap request to that error.
892*479ac375Sdm 		 */
893*479ac375Sdm 		if (retcode != IDMAP_SUCCESS) {
894*479ac375Sdm 			res->retcode = retcode;
895*479ac375Sdm 			continue;
896*479ac375Sdm 		}
897*479ac375Sdm 		if (!add)
898*479ac375Sdm 			continue;
899*479ac375Sdm 
900*479ac375Sdm 		/*
901*479ac375Sdm 		 * If we successfully retrieved winname from nldap entry
902*479ac375Sdm 		 * then lookup winname2sid locally. If not found locally
903*479ac375Sdm 		 * then mark this request for AD lookup.
904*479ac375Sdm 		 */
905*479ac375Sdm 		if (res->retcode == IDMAP_SUCCESS &&
906*479ac375Sdm 		    req->id2name != NULL &&
907*479ac375Sdm 		    res->id.idmap_id_u.sid.prefix == NULL &&
908*479ac375Sdm 		    (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req))) {
909*479ac375Sdm 
910*479ac375Sdm 			is_wuser = -1;
911*479ac375Sdm 			rc1 = lookup_name2sid(state->cache,
912*479ac375Sdm 			    req->id2name, req->id2domain, &is_wuser, NULL,
913*479ac375Sdm 			    &res->id.idmap_id_u.sid.prefix,
914*479ac375Sdm 			    &res->id.idmap_id_u.sid.rid, req, 1);
915*479ac375Sdm 			if (rc1 == IDMAP_SUCCESS)
916*479ac375Sdm 				res->id.idtype =
917*479ac375Sdm 				    is_wuser ? IDMAP_USID : IDMAP_GSID;
918*479ac375Sdm 			else if (rc1 == IDMAP_ERR_NOTFOUND) {
919*479ac375Sdm 				req->direction |= _IDMAP_F_LOOKUP_AD;
920*479ac375Sdm 				state->ad_nqueries++;
921*479ac375Sdm 			} else
922*479ac375Sdm 				res->retcode = rc1;
923*479ac375Sdm 		}
924*479ac375Sdm 
925*479ac375Sdm 		/*
926*479ac375Sdm 		 * Unset non-fatal errors in individual request. This allows
927*479ac375Sdm 		 * the next pass to process other mapping mechanisms for
928*479ac375Sdm 		 * this request.
929*479ac375Sdm 		 */
930*479ac375Sdm 		if (res->retcode != IDMAP_SUCCESS &&
931*479ac375Sdm 		    res->retcode != IDMAP_ERR_NS_LDAP_BAD_WINNAME &&
932*479ac375Sdm 		    !(IDMAP_FATAL_ERROR(res->retcode))) {
933*479ac375Sdm 			idmap_info_free(&res->info);
934*479ac375Sdm 			res->retcode = IDMAP_SUCCESS;
935*479ac375Sdm 		}
936*479ac375Sdm 	}
937*479ac375Sdm 
938*479ac375Sdm 	state->nldap_nqueries = 0;
939*479ac375Sdm 	return (retcode);
940e8c27ec8Sbaban }
941