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 /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24*528b7d8bSRichard Lowe  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
25e8c27ec8Sbaban  */
26e8c27ec8Sbaban 
27e8c27ec8Sbaban /*
28e8c27ec8Sbaban  * native LDAP related utility routines
29e8c27ec8Sbaban  */
30e8c27ec8Sbaban 
31e8c27ec8Sbaban #include "idmapd.h"
32479ac375Sdm #include "idmap_priv.h"
33479ac375Sdm #include "ns_sldap.h"
34479ac375Sdm #include "nldaputils.h"
35479ac375Sdm #include <assert.h>
36e8c27ec8Sbaban 
37479ac375Sdm /*
38479ac375Sdm  * The following are format strings used to construct LDAP search filters
39479ac375Sdm  * when looking up Native LDAP directory service. The _F_XXX_SSD format
40479ac375Sdm  * is used by the libsldap API if a corresponding SSD is defined in
41479ac375Sdm  * Native LDAP configuration. The SSD contains a string that replaces
42479ac375Sdm  * the first %s in _F_XXX_SSD. If no SSD is defined then the regular
43479ac375Sdm  * _F_XXX format is used.
44479ac375Sdm  *
45479ac375Sdm  * Note that '\\' needs to be represented as "\\5c" in LDAP filters.
46479ac375Sdm  */
47479ac375Sdm 
48479ac375Sdm /* Native LDAP lookup using UNIX username */
49479ac375Sdm #define	_F_GETPWNAM		"(&(objectClass=posixAccount)(uid=%s))"
50479ac375Sdm #define	_F_GETPWNAM_SSD		"(&(%%s)(uid=%s))"
51479ac375Sdm 
52479ac375Sdm /*
53479ac375Sdm  * Native LDAP user lookup using names of well-known SIDs
54479ac375Sdm  * Note the use of 1$, 2$ in the format string which basically
55479ac375Sdm  * allows snprintf to re-use its first two arguments.
56479ac375Sdm  */
57479ac375Sdm #define	_F_GETPWWNAMWK \
58479ac375Sdm 		"(&(objectClass=posixAccount)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
59479ac375Sdm #define	_F_GETPWWNAMWK_SSD	"(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
60479ac375Sdm 
61479ac375Sdm /* Native LDAP user lookup using winname@windomain OR windomain\winname */
62479ac375Sdm #define	_F_GETPWWNAMDOM \
63479ac375Sdm 	"(&(objectClass=posixAccount)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
64479ac375Sdm #define	_F_GETPWWNAMDOM_SSD	"(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
65479ac375Sdm 
66479ac375Sdm /* Native LDAP lookup using UID */
67479ac375Sdm #define	_F_GETPWUID		"(&(objectClass=posixAccount)(uidNumber=%u))"
68479ac375Sdm #define	_F_GETPWUID_SSD		"(&(%%s)(uidNumber=%u))"
69479ac375Sdm 
70479ac375Sdm /* Native LDAP lookup using UNIX groupname */
71479ac375Sdm #define	_F_GETGRNAM		"(&(objectClass=posixGroup)(cn=%s))"
72479ac375Sdm #define	_F_GETGRNAM_SSD		"(&(%%s)(cn=%s))"
73479ac375Sdm 
74479ac375Sdm /* Native LDAP group lookup using names of well-known SIDs */
75479ac375Sdm #define	_F_GETGRWNAMWK \
76479ac375Sdm 		"(&(objectClass=posixGroup)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
77479ac375Sdm #define	_F_GETGRWNAMWK_SSD	"(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
78479ac375Sdm 
79479ac375Sdm /* Native LDAP group lookup using winname@windomain OR windomain\winname */
80479ac375Sdm #define	_F_GETGRWNAMDOM \
81479ac375Sdm 		"(&(objectClass=posixGroup)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
82479ac375Sdm #define	_F_GETGRWNAMDOM_SSD	"(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
83479ac375Sdm 
84479ac375Sdm /* Native LDAP lookup using GID */
85479ac375Sdm #define	_F_GETGRGID		"(&(objectClass=posixGroup)(gidNumber=%u))"
86479ac375Sdm #define	_F_GETGRGID_SSD		"(&(%%s)(gidNumber=%u))"
87479ac375Sdm 
88479ac375Sdm /* Native LDAP attribute names */
89479ac375Sdm #define	UID			"uid"
90479ac375Sdm #define	CN			"cn"
91479ac375Sdm #define	UIDNUMBER		"uidnumber"
92479ac375Sdm #define	GIDNUMBER		"gidnumber"
93479ac375Sdm #define	DN			"dn"
94479ac375Sdm 
95479ac375Sdm #define	IS_NLDAP_RC_FATAL(x)	((x == NS_LDAP_MEMORY) ? 1 : 0)
96479ac375Sdm 
97479ac375Sdm typedef struct idmap_nldap_q {
98479ac375Sdm 	char			**winname;
99479ac375Sdm 	char			**windomain;
100479ac375Sdm 	char			**unixname;
101479ac375Sdm 	uid_t			*pid;
102479ac375Sdm 	char			**dn;
103479ac375Sdm 	char			**attr;
104479ac375Sdm 	char			**value;
105479ac375Sdm 	int			is_user;
106479ac375Sdm 	idmap_retcode		*rc;
107479ac375Sdm 	int			lrc;
108479ac375Sdm 	ns_ldap_result_t	*result;
109479ac375Sdm 	ns_ldap_error_t		*errorp;
110479ac375Sdm 	char			*filter;
111479ac375Sdm 	char			*udata;
112479ac375Sdm } idmap_nldap_q_t;
113479ac375Sdm 
114479ac375Sdm typedef struct idmap_nldap_query_state {
115479ac375Sdm 	const char		*nldap_winname_attr;
116479ac375Sdm 	const char		*defdom;
117479ac375Sdm 	int			nqueries;
118479ac375Sdm 	int			qid;
119479ac375Sdm 	int			flag;
120479ac375Sdm 	ns_ldap_list_batch_t	*batch;
121479ac375Sdm 	idmap_nldap_q_t		queries[1];
122479ac375Sdm } idmap_nldap_query_state_t;
123479ac375Sdm 
124479ac375Sdm /*
125479ac375Sdm  * This routine has been copied from lib/nsswitch/ldap/common/ldap_utils.c
126479ac375Sdm  * after removing the debug statements.
127479ac375Sdm  *
128479ac375Sdm  * This is a generic filter callback function for merging the filter
129479ac375Sdm  * from service search descriptor with an existing search filter. This
130479ac375Sdm  * routine expects userdata to contain a format string with a single %s
131479ac375Sdm  * in it, and will use the format string with sprintf() to insert the
132479ac375Sdm  * SSD filter.
133479ac375Sdm  *
134479ac375Sdm  * This routine and userdata are passed to the __ns_ldap_list_batch_add()
135479ac375Sdm  * API.
136479ac375Sdm  *
137479ac375Sdm  * Consider an example that uses __ns_ldap_list_batch_add() to lookup
138479ac375Sdm  * native LDAP directory using a given userid 'xy12345'. In this
139479ac375Sdm  * example the userdata will contain the filter "(&(%s)(cn=xy1234))".
140479ac375Sdm  * If a SSD is defined to replace the rfc2307bis specified filter
141479ac375Sdm  * i.e. (objectClass=posixAccount) by a site-specific filter
142479ac375Sdm  * say (department=sds) then this routine when called will produce
143479ac375Sdm  * "(&(department=sds)(uid=xy1234))" as the real search filter.
144479ac375Sdm  */
145479ac375Sdm static
146479ac375Sdm int
merge_SSD_filter(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata)147479ac375Sdm merge_SSD_filter(const ns_ldap_search_desc_t *desc,
148479ac375Sdm 	char **realfilter, const void *userdata)
149479ac375Sdm {
150479ac375Sdm 	int	len;
151*528b7d8bSRichard Lowe 	char *checker;
152*528b7d8bSRichard Lowe 
153479ac375Sdm 	if (realfilter == NULL)
154479ac375Sdm 		return (NS_LDAP_INVALID_PARAM);
155479ac375Sdm 	*realfilter = NULL;
156479ac375Sdm 	if (desc == NULL || desc->filter == NULL || userdata == NULL)
157479ac375Sdm 		return (NS_LDAP_INVALID_PARAM);
158*528b7d8bSRichard Lowe 
159*528b7d8bSRichard Lowe 	/* Parameter check.  We only want one %s here, otherwise bail. */
160*528b7d8bSRichard Lowe 	len = 0;	/* Reuse 'len' as "Number of %s hits"... */
161*528b7d8bSRichard Lowe 	checker = (char *)userdata;
162*528b7d8bSRichard Lowe 	do {
163*528b7d8bSRichard Lowe 		checker = strchr(checker, '%');
164*528b7d8bSRichard Lowe 		if (checker != NULL) {
165*528b7d8bSRichard Lowe 			if (len > 0 || *(checker + 1) != 's')
166*528b7d8bSRichard Lowe 				return (NS_LDAP_INVALID_PARAM);
167*528b7d8bSRichard Lowe 			len++;	/* Got our %s. */
168*528b7d8bSRichard Lowe 			checker += 2;
169*528b7d8bSRichard Lowe 		} else if (len != 1)
170*528b7d8bSRichard Lowe 			return (NS_LDAP_INVALID_PARAM);
171*528b7d8bSRichard Lowe 	} while (checker != NULL);
172*528b7d8bSRichard Lowe 
173479ac375Sdm 	len = strlen(userdata) + strlen(desc->filter) + 1;
174479ac375Sdm 	*realfilter = (char *)malloc(len);
175479ac375Sdm 	if (*realfilter == NULL)
176479ac375Sdm 		return (NS_LDAP_MEMORY);
177479ac375Sdm 	(void) sprintf(*realfilter, (char *)userdata, desc->filter);
178479ac375Sdm 	return (NS_LDAP_SUCCESS);
179479ac375Sdm }
180479ac375Sdm 
181479ac375Sdm static
182479ac375Sdm char
hex_char(int n)183479ac375Sdm hex_char(int n)
184479ac375Sdm {
185479ac375Sdm 	return ("0123456789abcdef"[n & 0xf]);
186479ac375Sdm }
187479ac375Sdm 
188479ac375Sdm /*
189479ac375Sdm  * If the input string contains special characters that needs to be
190479ac375Sdm  * escaped before the string can be used in a LDAP filter then this
191479ac375Sdm  * function will return a new sanitized string. Otherwise this function
192479ac375Sdm  * returns the input string (This saves us un-necessary memory allocations
193479ac375Sdm  * especially when processing a batch of requests). The caller must free
194479ac375Sdm  * the returned string if it isn't the input string.
195479ac375Sdm  *
196479ac375Sdm  * The escape mechanism for LDAP filter is described in RFC2254 basically
197479ac375Sdm  * it's \hh where hh are the two hexadecimal digits representing the ASCII
198479ac375Sdm  * value of the encoded character (case of hh is not significant).
199479ac375Sdm  * Example: * -> \2a, ( -> \28, ) -> \29, \ -> \5c,
200479ac375Sdm  *
201479ac375Sdm  * outstring = sanitize_for_ldap_filter(instring);
202479ac375Sdm  * if (outstring == NULL)
203479ac375Sdm  *	Out of memory
204479ac375Sdm  * else
205479ac375Sdm  *	Use outstring
206479ac375Sdm  *	if (outstring != instring)
207479ac375Sdm  *		free(outstring);
208479ac375Sdm  * done
209479ac375Sdm  */
210479ac375Sdm char *
sanitize_for_ldap_filter(const char * str)211479ac375Sdm sanitize_for_ldap_filter(const char *str)
212479ac375Sdm {
213479ac375Sdm 	const char	*p;
214479ac375Sdm 	char		*q, *s_str = NULL;
215479ac375Sdm 	int		n;
216479ac375Sdm 
217479ac375Sdm 	/* Get a count of special characters */
218479ac375Sdm 	for (p = str, n = 0; *p; p++)
219479ac375Sdm 		if (*p == '*' || *p == '(' || *p == ')' ||
220479ac375Sdm 		    *p == '\\' || *p == '%')
221479ac375Sdm 			n++;
222479ac375Sdm 	/* If count is zero then no need to sanitize */
223479ac375Sdm 	if (n == 0)
224479ac375Sdm 		return ((char *)str);
225479ac375Sdm 	/* Create output buffer that will contain the sanitized value */
226479ac375Sdm 	s_str = calloc(1, n * 2 + strlen(str) + 1);
227479ac375Sdm 	if (s_str == NULL)
228479ac375Sdm 		return (NULL);
229479ac375Sdm 	for (p = str, q = s_str; *p; p++) {
230479ac375Sdm 		if (*p == '*' || *p == '(' || *p == ')' ||
231479ac375Sdm 		    *p == '\\' || *p == '%') {
232479ac375Sdm 			*q++ = '\\';
233479ac375Sdm 			*q++ = hex_char(*p >> 4);
234479ac375Sdm 			*q++ = hex_char(*p & 0xf);
235479ac375Sdm 		} else
236479ac375Sdm 			*q++ = *p;
237479ac375Sdm 	}
238479ac375Sdm 	return (s_str);
239479ac375Sdm }
240479ac375Sdm 
241479ac375Sdm /*
242479ac375Sdm  * Map libsldap status to idmap  status
243479ac375Sdm  */
244479ac375Sdm static
245479ac375Sdm idmap_retcode
nldaprc2retcode(int rc)246479ac375Sdm nldaprc2retcode(int rc)
247479ac375Sdm {
248479ac375Sdm 	switch (rc) {
249479ac375Sdm 	case NS_LDAP_SUCCESS:
250479ac375Sdm 	case NS_LDAP_SUCCESS_WITH_INFO:
251479ac375Sdm 		return (IDMAP_SUCCESS);
252479ac375Sdm 	case NS_LDAP_NOTFOUND:
253479ac375Sdm 		return (IDMAP_ERR_NOTFOUND);
254479ac375Sdm 	case NS_LDAP_MEMORY:
255479ac375Sdm 		return (IDMAP_ERR_MEMORY);
256479ac375Sdm 	case NS_LDAP_CONFIG:
257479ac375Sdm 		return (IDMAP_ERR_NS_LDAP_CFG);
258479ac375Sdm 	case NS_LDAP_OP_FAILED:
259479ac375Sdm 		return (IDMAP_ERR_NS_LDAP_OP_FAILED);
260479ac375Sdm 	case NS_LDAP_PARTIAL:
261479ac375Sdm 		return (IDMAP_ERR_NS_LDAP_PARTIAL);
262479ac375Sdm 	case NS_LDAP_INTERNAL:
263479ac375Sdm 		return (IDMAP_ERR_INTERNAL);
264479ac375Sdm 	case NS_LDAP_INVALID_PARAM:
265479ac375Sdm 		return (IDMAP_ERR_ARG);
266479ac375Sdm 	default:
267479ac375Sdm 		return (IDMAP_ERR_OTHER);
268479ac375Sdm 	}
269479ac375Sdm 	/*NOTREACHED*/
270479ac375Sdm }
271479ac375Sdm 
272479ac375Sdm /*
273479ac375Sdm  * Create a batch for native LDAP lookup.
274479ac375Sdm  */
275479ac375Sdm static
276479ac375Sdm idmap_retcode
idmap_nldap_lookup_batch_start(int nqueries,idmap_nldap_query_state_t ** qs)277479ac375Sdm idmap_nldap_lookup_batch_start(int nqueries, idmap_nldap_query_state_t **qs)
278479ac375Sdm {
279479ac375Sdm 	idmap_nldap_query_state_t	*s;
280479ac375Sdm 
281479ac375Sdm 	s = calloc(1, sizeof (*s) +
282479ac375Sdm 	    (nqueries - 1) * sizeof (idmap_nldap_q_t));
283479ac375Sdm 	if (s == NULL)
284479ac375Sdm 		return (IDMAP_ERR_MEMORY);
285479ac375Sdm 	if (__ns_ldap_list_batch_start(&s->batch) != NS_LDAP_SUCCESS) {
286479ac375Sdm 		free(s);
287479ac375Sdm 		return (IDMAP_ERR_MEMORY);
288479ac375Sdm 	}
289479ac375Sdm 	s->nqueries = nqueries;
290479ac375Sdm 	s->flag = NS_LDAP_KEEP_CONN;
291479ac375Sdm 	*qs = s;
292479ac375Sdm 	return (IDMAP_SUCCESS);
293479ac375Sdm }
294479ac375Sdm 
295479ac375Sdm /*
296479ac375Sdm  * Add a lookup by winname request to the batch.
297479ac375Sdm  */
298479ac375Sdm static
299e8c27ec8Sbaban idmap_retcode
idmap_nldap_bywinname_batch_add(idmap_nldap_query_state_t * qs,const char * winname,const char * windomain,int is_user,char ** dn,char ** attr,char ** value,char ** unixname,uid_t * pid,idmap_retcode * rc)300479ac375Sdm idmap_nldap_bywinname_batch_add(idmap_nldap_query_state_t *qs,
301479ac375Sdm 	const char *winname, const char *windomain, int is_user,
302479ac375Sdm 	char **dn, char **attr, char **value,
303479ac375Sdm 	char **unixname, uid_t *pid, idmap_retcode *rc)
304e8c27ec8Sbaban {
305479ac375Sdm 	idmap_nldap_q_t		*q;
306479ac375Sdm 	const char		*db, *filter, *udata;
307479ac375Sdm 	int			flen, ulen, wksid = 0;
308479ac375Sdm 	char			*s_winname, *s_windomain;
309479ac375Sdm 	const char		**attrs;
310479ac375Sdm 	const char		*pwd_attrs[] = {UID, UIDNUMBER, NULL, NULL};
311479ac375Sdm 	const char		*grp_attrs[] = {CN, GIDNUMBER, NULL, NULL};
312479ac375Sdm 
313479ac375Sdm 	s_winname = s_windomain = NULL;
314479ac375Sdm 	q = &(qs->queries[qs->qid++]);
315479ac375Sdm 	q->unixname = unixname;
316479ac375Sdm 	q->pid = pid;
317479ac375Sdm 	q->rc = rc;
318479ac375Sdm 	q->is_user = is_user;
319479ac375Sdm 	q->dn = dn;
320479ac375Sdm 	q->attr = attr;
321479ac375Sdm 	q->value = value;
322479ac375Sdm 
323479ac375Sdm 	if (is_user) {
324479ac375Sdm 		db = "passwd";
32508f0d8daSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL,
32608f0d8daSafshin salek ardakani - Sun Microsystems - Irvine United States 		    NULL, NULL) == IDMAP_SUCCESS) {
327479ac375Sdm 			filter = _F_GETPWWNAMWK;
328479ac375Sdm 			udata = _F_GETPWWNAMWK_SSD;
329479ac375Sdm 			wksid = 1;
330479ac375Sdm 		} else if (windomain != NULL) {
331479ac375Sdm 			filter = _F_GETPWWNAMDOM;
332479ac375Sdm 			udata = _F_GETPWWNAMDOM_SSD;
333479ac375Sdm 		} else {
334479ac375Sdm 			*q->rc = IDMAP_ERR_DOMAIN_NOTFOUND;
335479ac375Sdm 			goto errout;
336479ac375Sdm 		}
337479ac375Sdm 		pwd_attrs[2] = qs->nldap_winname_attr;
338479ac375Sdm 		attrs = pwd_attrs;
339479ac375Sdm 	} else {
340479ac375Sdm 		db = "group";
34108f0d8daSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL,
34208f0d8daSafshin salek ardakani - Sun Microsystems - Irvine United States 		    NULL, NULL) == IDMAP_SUCCESS) {
343479ac375Sdm 			filter = _F_GETGRWNAMWK;
344479ac375Sdm 			udata = _F_GETGRWNAMWK_SSD;
345479ac375Sdm 			wksid = 1;
346479ac375Sdm 		} else if (windomain != NULL) {
347479ac375Sdm 			filter = _F_GETGRWNAMDOM;
348479ac375Sdm 			udata = _F_GETGRWNAMDOM_SSD;
349479ac375Sdm 		} else {
350479ac375Sdm 			*q->rc = IDMAP_ERR_DOMAIN_NOTFOUND;
351479ac375Sdm 			goto errout;
352479ac375Sdm 		}
353479ac375Sdm 		grp_attrs[2] = qs->nldap_winname_attr;
354479ac375Sdm 		attrs = grp_attrs;
355479ac375Sdm 	}
356479ac375Sdm 
357e8c27ec8Sbaban 	/*
358479ac375Sdm 	 * Sanitize names. No need to sanitize qs->nldap_winname_attr
359479ac375Sdm 	 * because if it contained any of the special characters then
360479ac375Sdm 	 * it would have been rejected by the function that reads it
361479ac375Sdm 	 * from the SMF config. LDAP attribute names can only contain
362479ac375Sdm 	 * letters, digits or hyphens.
363e8c27ec8Sbaban 	 */
364479ac375Sdm 	s_winname = sanitize_for_ldap_filter(winname);
365479ac375Sdm 	if (s_winname == NULL) {
366479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
367479ac375Sdm 		goto errout;
368479ac375Sdm 	}
369479ac375Sdm 	/* windomain could be NULL for names of well-known SIDs */
370479ac375Sdm 	if (windomain != NULL) {
371479ac375Sdm 		s_windomain = sanitize_for_ldap_filter(windomain);
372479ac375Sdm 		if (s_windomain == NULL) {
373479ac375Sdm 			*q->rc = IDMAP_ERR_MEMORY;
374479ac375Sdm 			goto errout;
375479ac375Sdm 		}
376479ac375Sdm 	}
377479ac375Sdm 
378479ac375Sdm 	/* Construct the filter and udata using snprintf. */
379479ac375Sdm 	if (wksid) {
380479ac375Sdm 		flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr,
381479ac375Sdm 		    s_winname) + 1;
382479ac375Sdm 		ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr,
383479ac375Sdm 		    s_winname) + 1;
384479ac375Sdm 	} else {
385479ac375Sdm 		flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr,
386479ac375Sdm 		    s_winname, s_windomain) + 1;
387479ac375Sdm 		ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr,
388479ac375Sdm 		    s_winname, s_windomain) + 1;
389479ac375Sdm 	}
390479ac375Sdm 
391479ac375Sdm 	q->filter = malloc(flen);
392479ac375Sdm 	if (q->filter == NULL) {
393479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
394479ac375Sdm 		goto errout;
395479ac375Sdm 	}
396479ac375Sdm 	q->udata = malloc(ulen);
397479ac375Sdm 	if (q->udata == NULL) {
398479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
399479ac375Sdm 		goto errout;
400479ac375Sdm 	}
401479ac375Sdm 
402479ac375Sdm 	if (wksid) {
403479ac375Sdm 		(void) snprintf(q->filter, flen, filter,
404479ac375Sdm 		    qs->nldap_winname_attr, s_winname);
405479ac375Sdm 		(void) snprintf(q->udata, ulen, udata,
406479ac375Sdm 		    qs->nldap_winname_attr, s_winname);
407479ac375Sdm 	} else {
408479ac375Sdm 		(void) snprintf(q->filter, flen, filter,
409479ac375Sdm 		    qs->nldap_winname_attr, s_winname, s_windomain);
410479ac375Sdm 		(void) snprintf(q->udata, ulen, udata,
411479ac375Sdm 		    qs->nldap_winname_attr, s_winname, s_windomain);
412479ac375Sdm 	}
413479ac375Sdm 
414479ac375Sdm 	if (s_winname != winname)
415479ac375Sdm 		free(s_winname);
416479ac375Sdm 	if (s_windomain != windomain)
417479ac375Sdm 		free(s_windomain);
418479ac375Sdm 
419479ac375Sdm 	q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
420479ac375Sdm 	    merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
421479ac375Sdm 	    &q->errorp, &q->lrc, NULL, q->udata);
422479ac375Sdm 
423479ac375Sdm 	if (IS_NLDAP_RC_FATAL(q->lrc))
424479ac375Sdm 		return (nldaprc2retcode(q->lrc));
425479ac375Sdm 	return (IDMAP_SUCCESS);
426479ac375Sdm 
427479ac375Sdm errout:
428479ac375Sdm 	/* query q and its content will be freed by batch_release */
429479ac375Sdm 	if (s_winname != winname)
430479ac375Sdm 		free(s_winname);
431479ac375Sdm 	if (s_windomain != windomain)
432479ac375Sdm 		free(s_windomain);
433479ac375Sdm 	return (*q->rc);
434479ac375Sdm }
435479ac375Sdm 
436479ac375Sdm /*
437479ac375Sdm  * Add a lookup by uid/gid request to the batch.
438479ac375Sdm  */
439479ac375Sdm static
440479ac375Sdm idmap_retcode
idmap_nldap_bypid_batch_add(idmap_nldap_query_state_t * qs,uid_t pid,int is_user,char ** dn,char ** attr,char ** value,char ** winname,char ** windomain,char ** unixname,idmap_retcode * rc)441479ac375Sdm idmap_nldap_bypid_batch_add(idmap_nldap_query_state_t *qs,
442479ac375Sdm 	uid_t pid, int is_user, char **dn, char **attr, char **value,
443479ac375Sdm 	char **winname, char **windomain,
444479ac375Sdm 	char **unixname, idmap_retcode *rc)
445479ac375Sdm {
446479ac375Sdm 	idmap_nldap_q_t		*q;
447479ac375Sdm 	const char		*db, *filter, *udata;
448479ac375Sdm 	int			len;
449479ac375Sdm 	const char		**attrs;
450479ac375Sdm 	const char		*pwd_attrs[] = {UID, NULL, NULL};
451479ac375Sdm 	const char		*grp_attrs[] = {CN, NULL, NULL};
452479ac375Sdm 
453479ac375Sdm 	q = &(qs->queries[qs->qid++]);
454479ac375Sdm 	q->winname = winname;
455479ac375Sdm 	q->windomain = windomain;
456479ac375Sdm 	q->unixname = unixname;
457479ac375Sdm 	q->rc = rc;
458479ac375Sdm 	q->is_user = is_user;
459479ac375Sdm 	q->dn = dn;
460479ac375Sdm 	q->attr = attr;
461479ac375Sdm 	q->value = value;
462479ac375Sdm 
463479ac375Sdm 	if (is_user) {
464479ac375Sdm 		db = "passwd";
465479ac375Sdm 		filter = _F_GETPWUID;
466479ac375Sdm 		udata = _F_GETPWUID_SSD;
467479ac375Sdm 		pwd_attrs[1] = qs->nldap_winname_attr;
468479ac375Sdm 		attrs = pwd_attrs;
469479ac375Sdm 	} else {
470479ac375Sdm 		db = "group";
471479ac375Sdm 		filter = _F_GETGRGID;
472479ac375Sdm 		udata = _F_GETGRGID_SSD;
473479ac375Sdm 		grp_attrs[1] = qs->nldap_winname_attr;
474479ac375Sdm 		attrs = grp_attrs;
475479ac375Sdm 	}
476479ac375Sdm 
477479ac375Sdm 	len = snprintf(NULL, 0, filter, pid) + 1;
478479ac375Sdm 	q->filter = malloc(len);
479479ac375Sdm 	if (q->filter == NULL) {
480479ac375Sdm 		*q->rc = IDMAP_ERR_MEMORY;
481479ac375Sdm 		return (IDMAP_ERR_MEMORY);
482