2e8c27ecbaban * CDDL HEADER START
3e8c27ecbaban *
4e8c27ecbaban * The contents of this file are subject to the terms of the
5e8c27ecbaban * Common Development and Distribution License (the "License").
6e8c27ecbaban * You may not use this file except in compliance with the License.
7e8c27ecbaban *
8e8c27ecbaban * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e8c27ecbaban * or http://www.opensolaris.org/os/licensing.
10e8c27ecbaban * See the License for the specific language governing permissions
11e8c27ecbaban * and limitations under the License.
12e8c27ecbaban *
13e8c27ecbaban * When distributing Covered Code, include this CDDL HEADER in each
14e8c27ecbaban * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e8c27ecbaban * If applicable, add the following below this CDDL HEADER, with the
16e8c27ecbaban * fields enclosed by brackets "[]" replaced with your own identifying
17e8c27ecbaban * information: Portions Copyright [yyyy] [name of copyright owner]
18e8c27ecbaban *
19e8c27ecbaban * CDDL HEADER END
20e8c27ecbaban */
23148c5f4Alan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24528b7d8Richard Lowe * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
25e8c27ecbaban */
28e8c27ecbaban * native LDAP related utility routines
29e8c27ecbaban */
31e8c27ecbaban#include "idmapd.h"
32479ac37dm#include "idmap_priv.h"
33479ac37dm#include "ns_sldap.h"
34479ac37dm#include "nldaputils.h"
35479ac37dm#include <assert.h>
38479ac37dm * The following are format strings used to construct LDAP search filters
39479ac37dm * when looking up Native LDAP directory service. The _F_XXX_SSD format
40479ac37dm * is used by the libsldap API if a corresponding SSD is defined in
41479ac37dm * Native LDAP configuration. The SSD contains a string that replaces
42479ac37dm * the first %s in _F_XXX_SSD. If no SSD is defined then the regular
43479ac37dm * _F_XXX format is used.
44479ac37dm *
45479ac37dm * Note that '\\' needs to be represented as "\\5c" in LDAP filters.
46479ac37dm */
48479ac37dm/* Native LDAP lookup using UNIX username */
49479ac37dm#define	_F_GETPWNAM		"(&(objectClass=posixAccount)(uid=%s))"
50479ac37dm#define	_F_GETPWNAM_SSD		"(&(%%s)(uid=%s))"
53479ac37dm * Native LDAP user lookup using names of well-known SIDs
54479ac37dm * Note the use of 1$, 2$ in the format string which basically
55479ac37dm * allows snprintf to re-use its first two arguments.
56479ac37dm */
57479ac37dm#define	_F_GETPWWNAMWK \
58479ac37dm		"(&(objectClass=posixAccount)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
59479ac37dm#define	_F_GETPWWNAMWK_SSD	"(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
61479ac37dm/* Native LDAP user lookup using winname@windomain OR windomain\winname */
62479ac37dm#define	_F_GETPWWNAMDOM \
63479ac37dm	"(&(objectClass=posixAccount)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
64479ac37dm#define	_F_GETPWWNAMDOM_SSD	"(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
66479ac37dm/* Native LDAP lookup using UID */
67479ac37dm#define	_F_GETPWUID		"(&(objectClass=posixAccount)(uidNumber=%u))"
68479ac37dm#define	_F_GETPWUID_SSD		"(&(%%s)(uidNumber=%u))"
70479ac37dm/* Native LDAP lookup using UNIX groupname */
71479ac37dm#define	_F_GETGRNAM		"(&(objectClass=posixGroup)(cn=%s))"
72479ac37dm#define	_F_GETGRNAM_SSD		"(&(%%s)(cn=%s))"
74479ac37dm/* Native LDAP group lookup using names of well-known SIDs */
75479ac37dm#define	_F_GETGRWNAMWK \
76479ac37dm		"(&(objectClass=posixGroup)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
77479ac37dm#define	_F_GETGRWNAMWK_SSD	"(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
79479ac37dm/* Native LDAP group lookup using winname@windomain OR windomain\winname */
80479ac37dm#define	_F_GETGRWNAMDOM \
81479ac37dm		"(&(objectClass=posixGroup)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
82479ac37dm#define	_F_GETGRWNAMDOM_SSD	"(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
84479ac37dm/* Native LDAP lookup using GID */
85479ac37dm#define	_F_GETGRGID		"(&(objectClass=posixGroup)(gidNumber=%u))"
86479ac37dm#define	_F_GETGRGID_SSD		"(&(%%s)(gidNumber=%u))"
88479ac37dm/* Native LDAP attribute names */
89479ac37dm#define	UID			"uid"
90479ac37dm#define	CN			"cn"
91479ac37dm#define	UIDNUMBER		"uidnumber"
92479ac37dm#define	GIDNUMBER		"gidnumber"
93479ac37dm#define	DN			"dn"
95479ac37dm#define	IS_NLDAP_RC_FATAL(x)	((x == NS_LDAP_MEMORY) ? 1 : 0)
97479ac37dmtypedef struct idmap_nldap_q {
98479ac37dm	char			**winname;
99479ac37dm	char			**windomain;
100479ac37dm	char			**unixname;
101479ac37dm	uid_t			*pid;
102479ac37dm	char			**dn;
103479ac37dm	char			**attr;
104479ac37dm	char			**value;
105479ac37dm	int			is_user;
106479ac37dm	idmap_retcode		*rc;
107479ac37dm	int			lrc;
108479ac37dm	ns_ldap_result_t	*result;
109479ac37dm	ns_ldap_error_t		*errorp;
110479ac37dm	char			*filter;
111479ac37dm	char			*udata;
112479ac37dm} idmap_nldap_q_t;
114479ac37dmtypedef struct idmap_nldap_query_state {
115479ac37dm	const char		*nldap_winname_attr;
116479ac37dm	const char		*defdom;
117479ac37dm	int			nqueries;
118479ac37dm	int			qid;
119479ac37dm	int			flag;
120479ac37dm	ns_ldap_list_batch_t	*batch;
121479ac37dm	idmap_nldap_q_t		queries[1];
122479ac37dm} idmap_nldap_query_state_t;
125479ac37dm * This routine has been copied from lib/nsswitch/ldap/common/ldap_utils.c
126479ac37dm * after removing the debug statements.
127479ac37dm *
128479ac37dm * This is a generic filter callback function for merging the filter
129479ac37dm * from service search descriptor with an existing search filter. This
130479ac37dm * routine expects userdata to contain a format string with a single %s
131479ac37dm * in it, and will use the format string with sprintf() to insert the
132479ac37dm * SSD filter.
133479ac37dm *
134479ac37dm * This routine and userdata are passed to the __ns_ldap_list_batch_add()
135479ac37dm * API.
136479ac37dm *
137479ac37dm * Consider an example that uses __ns_ldap_list_batch_add() to lookup
138479ac37dm * native LDAP directory using a given userid 'xy12345'. In this
139479ac37dm * example the userdata will contain the filter "(&(%s)(cn=xy1234))".
140479ac37dm * If a SSD is defined to replace the rfc2307bis specified filter
141479ac37dm * i.e. (objectClass=posixAccount) by a site-specific filter
142479ac37dm * say (department=sds) then this routine when called will produce
143479ac37dm * "(&(department=sds)(uid=xy1234))" as the real search filter.
144479ac37dm */
147479ac37dmmerge_SSD_filter(const ns_ldap_search_desc_t *desc,
148479ac37dm	char **realfilter, const void *userdata)
150479ac37dm	int	len;
151528b7d8Richard Lowe	char *checker;
152528b7d8Richard Lowe
153479ac37dm	if (realfilter == NULL)
154479ac37dm		return (NS_LDAP_INVALID_PARAM);
155479ac37dm	*realfilter = NULL;
156479ac37dm	if (desc == NULL || desc->filter == NULL || userdata == NULL)
157479ac37dm		return (NS_LDAP_INVALID_PARAM);
158528b7d8Richard Lowe
159528b7d8Richard Lowe	/* Parameter check.  We only want one %s here, otherwise bail. */
160528b7d8Richard Lowe	len = 0;	/* Reuse 'len' as "Number of %s hits"... */
161528b7d8Richard Lowe	checker = (char *)userdata;
162528b7d8Richard Lowe	do {
163528b7d8Richard Lowe		checker = strchr(checker, '%');
164528b7d8Richard Lowe		if (checker != NULL) {
165528b7d8Richard Lowe			if (len > 0 || *(checker + 1) != 's')
166528b7d8Richard Lowe				return (NS_LDAP_INVALID_PARAM);
167528b7d8Richard Lowe			len++;	/* Got our %s. */
168528b7d8Richard Lowe			checker += 2;
169528b7d8Richard Lowe		} else if (len != 1)
170528b7d8Richard Lowe			return (NS_LDAP_INVALID_PARAM);
171528b7d8Richard Lowe	} while (checker != NULL);
172528b7d8Richard Lowe
173479ac37dm	len = strlen(userdata) + strlen(desc->filter) + 1;
174479ac37dm	*realfilter = (char *)malloc(len);
175479ac37dm	if (*realfilter == NULL)
176479ac37dm		return (NS_LDAP_MEMORY);
177479ac37dm	(void) sprintf(*realfilter, (char *)userdata, desc->filter);
178479ac37dm	return (NS_LDAP_SUCCESS);
183479ac37dmhex_char(int n)
185479ac37dm	return ("0123456789abcdef"[n & 0xf]);
189479ac37dm * If the input string contains special characters that needs to be
190479ac37dm * escaped before the string can be used in a LDAP filter then this
191479ac37dm * function will return a new sanitized string. Otherwise this function
192479ac37dm * returns the input string (This saves us un-necessary memory allocations
193479ac37dm * especially when processing a batch of requests). The caller must free
194479ac37dm * the returned string if it isn't the input string.
195479ac37dm *
196479ac37dm * The escape mechanism for LDAP filter is described in RFC2254 basically
197479ac37dm * it's \hh where hh are the two hexadecimal digits representing the ASCII
198479ac37dm * value of the encoded character (case of hh is not significant).
199479ac37dm * Example: * -> \2a, ( -> \28, ) -> \29, \ -> \5c,
200479ac37dm *
201479ac37dm * outstring = sanitize_for_ldap_filter(instring);
202479ac37dm * if (outstring == NULL)
203479ac37dm *	Out of memory
204479ac37dm * else
205479ac37dm *	Use outstring
206479ac37dm *	if (outstring != instring)
207479ac37dm *		free(outstring);
208479ac37dm * done
209479ac37dm */
210479ac37dmchar *
211479ac37dmsanitize_for_ldap_filter(const char *str)
213479ac37dm	const char	*p;
214479ac37dm	char		*q, *s_str = NULL;
215479ac37dm	int		n;
217479ac37dm	/* Get a count of special characters */
218479ac37dm	for (p = str, n = 0; *p; p++)
219479ac37dm		if (*p == '*' || *p == '(' || *p == ')' ||
220479ac37dm		    *p == '\\' || *p == '%')
221479ac37dm			n++;
222479ac37dm	/* If count is zero then no need to sanitize */
223479ac37dm	if (n == 0)
224479ac37dm		return ((char *)str);
225479ac37dm	/* Create output buffer that will contain the sanitized value */
226479ac37dm	s_str = calloc(1, n * 2 + strlen(str) + 1);
227479ac37dm	if (s_str == NULL)
228479ac37dm		return (NULL);
229479ac37dm	for (p = str, q = s_str; *p; p++) {
230479ac37dm		if (*p == '*' || *p == '(' || *p == ')' ||
231479ac37dm		    *p == '\\' || *p == '%') {
232479ac37dm			*q++ = '\\';
233479ac37dm			*q++ = hex_char(*p >> 4);
234479ac37dm			*q++ = hex_char(*p & 0xf);
235479ac37dm		} else
236479ac37dm			*q++ = *p;
237479ac37dm	}
238479ac37dm	return (s_str);
242479ac37dm * Map libsldap status to idmap  status
243479ac37dm */
246479ac37dmnldaprc2retcode(int rc)
248479ac37dm	switch (rc) {
249479ac37dm	case NS_LDAP_SUCCESS:
250479ac37dm	case NS_LDAP_SUCCESS_WITH_INFO:
251479ac37dm		return (IDMAP_SUCCESS);
252479ac37dm	case NS_LDAP_NOTFOUND:
253479ac37dm		return (IDMAP_ERR_NOTFOUND);
254479ac37dm	case NS_LDAP_MEMORY:
255479ac37dm		return (IDMAP_ERR_MEMORY);
256479ac37dm	case NS_LDAP_CONFIG:
257479ac37dm		return (IDMAP_ERR_NS_LDAP_CFG);
258479ac37dm	case NS_LDAP_OP_FAILED:
259479ac37dm		return (IDMAP_ERR_NS_LDAP_OP_FAILED);
260479ac37dm	case NS_LDAP_PARTIAL:
261479ac37dm		return (IDMAP_ERR_NS_LDAP_PARTIAL);
262479ac37dm	case NS_LDAP_INTERNAL:
263479ac37dm		return (IDMAP_ERR_INTERNAL);
264479ac37dm	case NS_LDAP_INVALID_PARAM:
265479ac37dm		return (IDMAP_ERR_ARG);
266479ac37dm	default:
267479ac37dm		return (IDMAP_ERR_OTHER);
268479ac37dm	}
269479ac37dm	/*NOTREACHED*/
273479ac37dm * Create a batch for native LDAP lookup.
274479ac37dm */
277479ac37dmidmap_nldap_lookup_batch_start(int nqueries, idmap_nldap_query_state_t **qs)
279479ac37dm	idmap_nldap_query_state_t	*s;
281479ac37dm	s = calloc(1, sizeof (*s) +
282479ac37dm	    (nqueries - 1) * sizeof (idmap_nldap_q_t));
283479ac37dm	if (s == NULL)
284479ac37dm		return (IDMAP_ERR_MEMORY);
285479ac37dm	if (__ns_ldap_list_batch_start(&s->batch) != NS_LDAP_SUCCESS) {
286479ac37dm		free(s);
287479ac37dm		return (IDMAP_ERR_MEMORY);
288479ac37dm	}
289479ac37dm	s->nqueries = nqueries;
290479ac37dm	s->flag = NS_LDAP_KEEP_CONN;
291479ac37dm	*qs = s;
292479ac37dm	return (IDMAP_SUCCESS);
296479ac37dm * Add a lookup by winname request to the batch.
297479ac37dm */
300479ac37dmidmap_nldap_bywinname_batch_add(idmap_nldap_query_state_t *qs,
301479ac37dm	const char *winname, const char *windomain, int is_user,
302479ac37dm	char **dn, char **attr, char **value,
303479ac37dm	char **unixname, uid_t *pid, idmap_retcode *rc)
305479ac37dm	idmap_nldap_q_t		*q;
306479ac37dm	const char		*db, *filter, *udata;
307479ac37dm	int			flen, ulen, wksid = 0;
308479ac37dm	char			*s_winname, *s_windomain;
309479ac37dm	const char		**attrs;
310479ac37dm	const char		*pwd_attrs[] = {UID, UIDNUMBER, NULL, NULL};
311479ac37dm	const char		*grp_attrs[] = {CN, GIDNUMBER, NULL, NULL};
313479ac37dm	s_winname = s_windomain = NULL;
314479ac37dm	q = &(qs->queries[qs->qid++]);
315479ac37dm	q->unixname = unixname;
316479ac37dm	q->pid = pid;
317479ac37dm	q->rc = rc;
318479ac37dm	q->is_user = is_user;
319479ac37dm	q->dn = dn;
320479ac37dm	q->attr = attr;
321479ac37dm	q->value = value;
323479ac37dm	if (is_user) {
324479ac37dm		db = "passwd";
32508f0d8dafshin salek ardakani - Sun Microsystems - Irvine United States		if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL,
32608f0d8dafshin salek ardakani - Sun Microsystems - Irvine United States		    NULL, NULL) == IDMAP_SUCCESS) {
327479ac37dm			filter = _F_GETPWWNAMWK;
328479ac37dm			udata = _F_GETPWWNAMWK_SSD;
329479ac37dm			wksid = 1;
330479ac37dm		} else if (windomain != NULL) {
331479ac37dm			filter = _F_GETPWWNAMDOM;
332479ac37dm			udata = _F_GETPWWNAMDOM_SSD;
333479ac37dm		} else {
334479ac37dm			*q->rc = IDMAP_ERR_DOMAIN_NOTFOUND;
335479ac37dm			goto errout;
336479ac37dm		}
337479ac37dm		pwd_attrs[2] = qs->nldap_winname_attr;
338479ac37dm		attrs = pwd_attrs;
339479ac37dm	} else {
340479ac37dm		db = "group";
34108f0d8dafshin salek ardakani - Sun Microsystems - Irvine United States		if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL,
34208f0d8dafshin salek ardakani - Sun Microsystems - Irvine United States		    NULL, NULL) == IDMAP_SUCCESS) {
343479ac37dm			filter = _F_GETGRWNAMWK;
344479ac37dm			udata = _F_GETGRWNAMWK_SSD;
345479ac37dm			wksid = 1;
346479ac37dm		} else if (windomain != NULL) {
347479ac37dm			filter = _F_GETGRWNAMDOM;
348479ac37dm			udata = _F_GETGRWNAMDOM_SSD;
349479ac37dm		} else {
350479ac37dm			*q->rc = IDMAP_ERR_DOMAIN_NOTFOUND;
351479ac37dm			goto errout;
352479ac37dm		}
353479ac37dm		grp_attrs[2] = qs->nldap_winname_attr;
354479ac37dm		attrs = grp_attrs;
355479ac37dm	}
357e8c27ecbaban	/*
358479ac37dm	 * Sanitize names. No need to sanitize qs->nldap_winname_attr
359479ac37dm	 * because if it contained any of the special characters then
360479ac37dm	 * it would have been rejected by the function that reads it
361479ac37dm	 * from the SMF config. LDAP attribute names can only contain
362479ac37dm	 * letters, digits or hyphens.
363e8c27ecbaban	 */
364479ac37dm	s_winname = sanitize_for_ldap_filter(winname);
365479ac37dm	if (s_winname == NULL) {
366479ac37dm		*q->rc = IDMAP_ERR_MEMORY;
367479ac37dm		goto errout;
368479ac37dm	}
369479ac37dm	/* windomain could be NULL for names of well-known SIDs */
370479ac37dm	if (windomain != NULL) {
371479ac37dm		s_windomain = sanitize_for_ldap_filter(windomain);
372479ac37dm		if (s_windomain == NULL) {
373479ac37dm			*q->rc = IDMAP_ERR_MEMORY;
374479ac37dm			goto errout;
375479ac37dm		}
376479ac37dm	}
378479ac37dm	/* Construct the filter and udata using snprintf. */
379479ac37dm	if (wksid) {
380479ac37dm		flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr,
381479ac37dm		    s_winname) + 1;
382479ac37dm		ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr,
383479ac37dm		    s_winname) + 1;
384479ac37dm	} else {
385479ac37dm		flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr,
386479ac37dm		    s_winname, s_windomain) + 1;
387479ac37dm		ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr,
388479ac37dm		    s_winname, s_windomain) + 1;
389479ac37dm	}
391479ac37dm	q->filter = malloc(flen);
392479ac37dm	if (q->filter == NULL) {
393479ac37dm		*q->rc = IDMAP_ERR_MEMORY;
394479ac37dm		goto errout;
395479ac37dm	}
396479ac37dm	q->udata = malloc(ulen);
397479ac37dm	if (q->udata == NULL) {
398479ac37dm		*q->rc = IDMAP_ERR_MEMORY;
399479ac37dm		goto errout;
400479ac37dm	}
402479ac37dm	if (wksid) {
403479ac37dm		(void) snprintf(q->filter, flen, filter,
404479ac37dm		    qs->nldap_winname_attr, s_winname);
405479ac37dm		(void) snprintf(q->udata, ulen, udata,
406479ac37dm		    qs->nldap_winname_attr, s_winname);
407479ac37dm	} else {
408479ac37dm		(void) snprintf(q->filter, flen, filter,
409479ac37dm		    qs->nldap_winname_attr, s_winname, s_windomain);
410479ac37dm		(void) snprintf(q->udata, ulen, udata,
411479ac37dm		    qs->nldap_winname_attr, s_winname, s_windomain);
412479ac37dm	}
414479ac37dm	if (s_winname != winname)
415479ac37dm		free(s_winname);
416479ac37dm	if (s_windomain != windomain)
417479ac37dm		free(s_windomain);
419479ac37dm	q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
420479ac37dm	    merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
421479ac37dm	    &q->errorp, &q->lrc, NULL, q->udata);
423479ac37dm	if (IS_NLDAP_RC_FATAL(q->lrc))
424479ac37dm		return (nldaprc2retcode(q->lrc));
425479ac37dm	return (IDMAP_SUCCESS);
428479ac37dm	/* query q and its content will be freed by batch_release */
429479ac37dm	if (s_winname != winname)
430479ac37dm		free(s_winname);
431479ac37dm	if (s_windomain != windomain)
432479ac37dm		free(s_windomain);
433479ac37dm	return (*q->rc);
437479ac37dm * Add a lookup by uid/gid request to the batch.
438479ac37dm */
441479ac37dmidmap_nldap_bypid_batch_add(idmap_nldap_query_state_t *qs,
442479ac37dm	uid_t pid, int is_user, char **dn, char **attr, char **value,
443479ac37dm	char **winname, char **windomain,
444479ac37dm	char **unixname, idmap_retcode *rc)
446479ac37dm	idmap_nldap_q_t		*q;
447479ac37dm	const char		*db, *filter, *udata;
448479ac37dm	int			len;
449479ac37dm	const char		**attrs;
450479ac37dm	const char		*pwd_attrs[] = {UID, NULL, NULL};
451479ac37dm	const char		*grp_attrs[] = {CN, NULL, NULL};
453479ac37dm	q = &(qs->queries[qs->qid++]);
454479ac37dm	q->winname = winname;
455479ac37dm	q->windomain = windomain;
456479ac37dm	q->unixname = unixname;
457479ac37dm	q->rc = rc;
458479ac37dm	q->is_user = is_user;
459479ac37dm	q->dn = dn;
460479ac37dm	q->attr = attr;
461479ac37dm	q->value = value;
463479ac37dm	if (is_user) {
464479ac37dm		db = "passwd";
465479ac37dm		filter = _F_GETPWUID;
466479ac37dm		udata = _F_GETPWUID_SSD;
467479ac37dm		pwd_attrs[1] = qs->nldap_winname_attr;
468479ac37dm		attrs = pwd_attrs;
469479ac37dm	} else {
470479ac37dm		db = "group";
471479ac37dm		filter = _F_GETGRGID;
472479ac37dm		udata = _F_GETGRGID_SSD;
473479ac37dm		grp_attrs[1] = qs->nldap_winname_attr;
474479ac37dm		attrs = grp_attrs;
475479ac37dm	}
477479ac37dm	len = snprintf(NULL, 0, filter, pid) + 1;
478479ac37dm	q->filter = malloc(len);
479479ac37dm	if (q->filter == NULL) {
480479ac37dm		*q->rc = IDMAP_ERR_MEMORY;
481479ac37dm		return (IDMAP_ERR_MEMORY);
482479ac37dm	}
483479ac37dm	(void) snprintf(q->filter, len, filter, pid);
485479ac37dm	len = snprintf(NULL, 0, udata, pid) + 1;
486479ac37dm	q->udata = malloc(len);
487479ac37dm	if (q->udata == NULL) {
488479ac37dm		*q->rc = IDMAP_ERR_MEMORY;
489479ac37dm		return (IDMAP_ERR_MEMORY);
490479ac37dm	}
491479ac37dm	(void) snprintf(q->udata, len, udata, pid);
493479ac37dm	q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
494479ac37dm	    merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
495479ac37dm	    &q->errorp, &q->lrc, NULL, q->udata);
497479ac37dm	if (IS_NLDAP_RC_FATAL(q->lrc))
498479ac37dm		return (nldaprc2retcode(q->lrc));
499479ac37dm	return (IDMAP_SUCCESS);
503479ac37dm * Add a lookup by user/group name request to the batch.
504479ac37dm */
507479ac37dmidmap_nldap_byunixname_batch_add(idmap_nldap_query_state_t *qs,
508479ac37dm	const char *unixname, int is_user,
509479ac37dm	char **dn, char **attr, char **value,
510479ac37dm	char **winname, char **windomain, uid_t *pid, idmap_retcode *rc)
512479ac37dm	idmap_nldap_q_t		*q;
513479ac37dm	const char		*db, *filter, *udata;
514479ac37dm	int			len;
515479ac37dm	char			*s_unixname = NULL;
516479ac37dm	const char		**attrs;
517479ac37dm	const char		*pwd_attrs[] = {UIDNUMBER, NULL, NULL};
518479ac37dm	const char		*grp_attrs[] = {GIDNUMBER, NULL, NULL};
520479ac37dm	q = &(qs->queries[qs->qid++]);
521479ac37dm	q->winname = winname;
522479ac37dm	q->windomain = windomain;
523479ac37dm	q->pid = pid;
524479ac37dm	q->rc = rc;
525479ac37dm	q->is_user = is_user;
526479ac37dm	q->dn = dn;
527479ac37dm	q->attr = attr;
528479ac37dm	q->value = value;
530479ac37dm	if (is_user) {
531479ac37dm		db = "passwd";
532479ac37dm		filter = _F_GETPWNAM;
533479ac37dm		udata = _F_GETPWNAM_SSD;
534479ac37dm		pwd_attrs[1] = qs->nldap_winname_attr;
535479ac37dm		attrs = pwd_attrs;
536479ac37dm	} else {
537479ac37dm		db = "group";
538479ac37dm		filter = _F_GETGRNAM;
539479ac37dm		udata = _F_GETGRNAM_SSD;
540479ac37dm		grp_attrs[1] = qs->nldap_winname_attr;
541479ac37dm		attrs = grp_attrs;
542479ac37dm	}
544479ac37dm	s_unixname = sanitize_for_ldap_filter(unixname);