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