17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6cb5caa98Sdjl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2220e6d5c5Ssc  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24a3bcc60dSMatt Barden  *
25a3bcc60dSMatt Barden  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
26*d7ab8532SJason King  * Copyright 2020 Joyent, Inc.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <grp.h>
307c478bd9Sstevel@tonic-gate #include "ldap_common.h"
314c6ae461SPaul B. Henson #include <string.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /* String which may need to be removed from beginning of group password */
347c478bd9Sstevel@tonic-gate #define	_CRYPT		"{CRYPT}"
357c478bd9Sstevel@tonic-gate #define	_NO_PASSWD_VAL	""
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /* Group attributes filters */
387c478bd9Sstevel@tonic-gate #define	_G_NAME		"cn"
397c478bd9Sstevel@tonic-gate #define	_G_GID		"gidnumber"
407c478bd9Sstevel@tonic-gate #define	_G_PASSWD	"userpassword"
41695ef821SGordon Ross #define	_G_MEMUID	"memberuid"
42695ef821SGordon Ross #define	_G_MEM_DN	"member"	/* DN */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #define	_F_GETGRNAM	"(&(objectClass=posixGroup)(cn=%s))"
457c478bd9Sstevel@tonic-gate #define	_F_GETGRNAM_SSD	"(&(%%s)(cn=%s))"
46f48205beScasper #define	_F_GETGRGID	"(&(objectClass=posixGroup)(gidNumber=%u))"
47f48205beScasper #define	_F_GETGRGID_SSD	"(&(%%s)(gidNumber=%u))"
484c6ae461SPaul B. Henson 
494c6ae461SPaul B. Henson /*
50695ef821SGordon Ross  * When searching for groups in which a specified user is a member,
51695ef821SGordon Ross  * there are a few different membership schema that might be in use.
52695ef821SGordon Ross  * We'll use a filter that should work with an of the common ones:
53695ef821SGordon Ross  * "memberUid=NAME", or "member=DN" (try uniquemember too?)
54695ef821SGordon Ross  * The first parameter in the filter string is replaced by username,
55695ef821SGordon Ross  * and the remaining ones by the full DN.
564c6ae461SPaul B. Henson  */
57695ef821SGordon Ross #define	_F_GETGRMEM "(&(objectClass=posixGroup)" \
58695ef821SGordon Ross 	"(|(memberUid=%s)(member=%s)))"
59695ef821SGordon Ross #define	_F_GETGRMEM_SSD	"(&(%%s)" \
60695ef821SGordon Ross 	"(|(memberUid=%s)(member=%s)))"
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static const char *gr_attrs[] = {
637c478bd9Sstevel@tonic-gate 	_G_NAME,
647c478bd9Sstevel@tonic-gate 	_G_GID,
657c478bd9Sstevel@tonic-gate 	_G_PASSWD,
66695ef821SGordon Ross 	_G_MEMUID,
67695ef821SGordon Ross 	_G_MEM_DN,
687c478bd9Sstevel@tonic-gate 	(char *)NULL
697c478bd9Sstevel@tonic-gate };
707c478bd9Sstevel@tonic-gate 
71695ef821SGordon Ross static int
72695ef821SGordon Ross getmembers_UID(char **bufpp, int *lenp, ns_ldap_attr_t *members);
73695ef821SGordon Ross static int
74695ef821SGordon Ross getmembers_DN(char **bufpp, int *lenp, ns_ldap_attr_t *members);
75695ef821SGordon Ross 
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
78cb5caa98Sdjl  * _nss_ldap_group2str is the data marshaling method for the group getXbyY
797c478bd9Sstevel@tonic-gate  * (e.g., getgrnam(), getgrgid(), getgrent()) backend processes. This method
807c478bd9Sstevel@tonic-gate  * is called after a successful ldap search has been performed. This method
81cb5caa98Sdjl  * will parse the ldap search values into the file format.
82cb5caa98Sdjl  * e.g.
83cb5caa98Sdjl  *
84cb5caa98Sdjl  * adm::4:root,adm,daemon
85cb5caa98Sdjl  *
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static int
_nss_ldap_group2str(ldap_backend_ptr be,nss_XbyY_args_t * argp)89cb5caa98Sdjl _nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
907c478bd9Sstevel@tonic-gate {
91cb5caa98Sdjl 	int		i;
927c478bd9Sstevel@tonic-gate 	int		nss_result;
93cb5caa98Sdjl 	int		buflen = 0, len;
94cb5caa98Sdjl 	char		*buffer = NULL;
957c478bd9Sstevel@tonic-gate 	ns_ldap_result_t	*result = be->result;
962b4a7802SBaban Kenkre 	char		**gname, **passwd, **gid, *password, *end;
972b4a7802SBaban Kenkre 	char		gid_nobody[NOBODY_STR_LEN];
982b4a7802SBaban Kenkre 	char		*gid_nobody_v[1];
99cb5caa98Sdjl 	ns_ldap_attr_t	*members;
1007c478bd9Sstevel@tonic-gate 
1012b4a7802SBaban Kenkre 	(void) snprintf(gid_nobody, sizeof (gid_nobody), "%u", GID_NOBODY);
1022b4a7802SBaban Kenkre 	gid_nobody_v[0] = gid_nobody;
1037c478bd9Sstevel@tonic-gate 
104cb5caa98Sdjl 	if (result == NULL)
105cb5caa98Sdjl 		return (NSS_STR_PARSE_PARSE);
106cb5caa98Sdjl 	buflen = argp->buf.buflen;
107cb5caa98Sdjl 
108cb5caa98Sdjl 	if (argp->buf.result != NULL) {
109cb5caa98Sdjl 		if ((be->buffer = calloc(1, buflen)) == NULL) {
110cb5caa98Sdjl 			nss_result = NSS_STR_PARSE_PARSE;
111cb5caa98Sdjl 			goto result_grp2str;
1127c478bd9Sstevel@tonic-gate 		}
113cb5caa98Sdjl 		buffer = be->buffer;
114cb5caa98Sdjl 	} else
115cb5caa98Sdjl 		buffer = argp->buf.buffer;
116cb5caa98Sdjl 
117cb5caa98Sdjl 	nss_result = NSS_STR_PARSE_SUCCESS;
118cb5caa98Sdjl 	(void) memset(buffer, 0, buflen);
119cb5caa98Sdjl 
120cb5caa98Sdjl 	gname = __ns_ldap_getAttr(result->entry, _G_NAME);
121cb5caa98Sdjl 	if (gname == NULL || gname[0] == NULL || (strlen(gname[0]) < 1)) {
122cb5caa98Sdjl 		nss_result = NSS_STR_PARSE_PARSE;
123cb5caa98Sdjl 		goto result_grp2str;
1247c478bd9Sstevel@tonic-gate 	}
125cb5caa98Sdjl 	passwd = __ns_ldap_getAttr(result->entry, _G_PASSWD);
126cb5caa98Sdjl 	if (passwd == NULL || passwd[0] == NULL || (strlen(passwd[0]) == 0)) {
127cb5caa98Sdjl 		/* group password could be NULL, replace it with "" */
128cb5caa98Sdjl 		password = _NO_PASSWD_VAL;
129cb5caa98Sdjl 	} else {
1307c478bd9Sstevel@tonic-gate 		/*
131cb5caa98Sdjl 		 * Preen "{crypt}" if necessary.
132cb5caa98Sdjl 		 * If the password does not include the {crypt} prefix
133cb5caa98Sdjl 		 * then the password may be plain text.  And thus
134cb5caa98Sdjl 		 * perhaps crypt(3c) should be used to encrypt it.
135cb5caa98Sdjl 		 * Currently the password is copied verbatim.
1367c478bd9Sstevel@tonic-gate 		 */
137cb5caa98Sdjl 		if (strncasecmp(passwd[0], _CRYPT, strlen(_CRYPT)) == 0)
138cb5caa98Sdjl 			password = passwd[0] + strlen(_CRYPT);
139cb5caa98Sdjl 		else
140cb5caa98Sdjl 			password = passwd[0];
1417c478bd9Sstevel@tonic-gate 	}
142cb5caa98Sdjl 	gid = __ns_ldap_getAttr(result->entry, _G_GID);
143cb5caa98Sdjl 	if (gid == NULL || gid[0] == NULL || (strlen(gid[0]) < 1)) {
144cb5caa98Sdjl 		nss_result = NSS_STR_PARSE_PARSE;
145cb5caa98Sdjl 		goto result_grp2str;
1467c478bd9Sstevel@tonic-gate 	}
1472b4a7802SBaban Kenkre 	/* Validate GID */
1482b4a7802SBaban Kenkre 	if (strtoul(gid[0], &end, 10) > MAXUID)
1492b4a7802SBaban Kenkre 		gid = gid_nobody_v;
15018bdb8a7Smichen 	len = snprintf(buffer, buflen, "%s:%s:%s:", gname[0], password, gid[0]);
151cb5caa98Sdjl 	TEST_AND_ADJUST(len, buffer, buflen, result_grp2str);
152cb5caa98Sdjl 
153695ef821SGordon Ross 	members = __ns_ldap_getAttrStruct(result->entry, _G_MEMUID);
154695ef821SGordon Ross 	if (members != NULL && members->attrvalue != NULL) {
155695ef821SGordon Ross 		nss_result = getmembers_UID(&buffer, &buflen, members);
156695ef821SGordon Ross 		if (nss_result != 0)
157695ef821SGordon Ross 			goto result_grp2str;
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate 
160695ef821SGordon Ross 	members = __ns_ldap_getAttrStruct(result->entry, _G_MEM_DN);
161695ef821SGordon Ross 	if (members != NULL && members->attrvalue != NULL) {
162695ef821SGordon Ross 		nss_result = getmembers_DN(&buffer, &buflen, members);
163695ef821SGordon Ross 		if (nss_result != 0)
164cb5caa98Sdjl 			goto result_grp2str;
165cb5caa98Sdjl 	}
166695ef821SGordon Ross 
167cb5caa98Sdjl 	/* The front end marshaller doesn't need the trailing nulls */
168cb5caa98Sdjl 	if (argp->buf.result != NULL)
169cb5caa98Sdjl 		be->buflen = strlen(be->buffer);
170cb5caa98Sdjl result_grp2str:
1717c478bd9Sstevel@tonic-gate 	(void) __ns_ldap_freeResult(&be->result);
172cb5caa98Sdjl 	return (nss_result);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate 
175695ef821SGordon Ross /*
176695ef821SGordon Ross  * Process the list values from the "memberUid" attribute of the
177695ef821SGordon Ross  * current group.  Note that this list is often empty, and we
178695ef821SGordon Ross  * get the real list of members via getmember_DN (see below).
179695ef821SGordon Ross  */
180695ef821SGordon Ross static int
getmembers_UID(char ** bufpp,int * lenp,ns_ldap_attr_t * members)181695ef821SGordon Ross getmembers_UID(char **bufpp, int *lenp, ns_ldap_attr_t *members)
182695ef821SGordon Ross {
183695ef821SGordon Ross 	char	*member_str, *strtok_state;
184695ef821SGordon Ross 	char	*buffer;
185695ef821SGordon Ross 	int	buflen;
186695ef821SGordon Ross 	int	i, len;
187695ef821SGordon Ross 	int	nss_result = 0;
188695ef821SGordon Ross 	int	firsttime;
189695ef821SGordon Ross 
190695ef821SGordon Ross 	buffer = *bufpp;
191695ef821SGordon Ross 	buflen = *lenp;
192695ef821SGordon Ross 	firsttime = (buffer[-1] == ':');
193695ef821SGordon Ross 
194695ef821SGordon Ross 	for (i = 0; i < members->value_count; i++) {
195695ef821SGordon Ross 		member_str = members->attrvalue[i];
196695ef821SGordon Ross 		if (member_str == NULL)
197695ef821SGordon Ross 			goto out;
198695ef821SGordon Ross 
199695ef821SGordon Ross #ifdef DEBUG
200695ef821SGordon Ross 		(void) fprintf(stdout, "getmembers_UID: uid=<%s>\n",
201695ef821SGordon Ross 		    member_str);
202695ef821SGordon Ross #endif
203695ef821SGordon Ross 		/*
204695ef821SGordon Ross 		 * If not a valid Unix user name, or
205695ef821SGordon Ross 		 * not valid in ldap, just skip.
206695ef821SGordon Ross 		 */
207695ef821SGordon Ross 		if (member_str[0] == '\0' ||
208695ef821SGordon Ross 		    strpbrk(member_str, " ,:=") != NULL)
209695ef821SGordon Ross 			continue;
210695ef821SGordon Ross 
21121ec5af7SToomas Soome 		if (firsttime) {
212695ef821SGordon Ross 			len = snprintf(buffer, buflen, "%s", member_str);
21321ec5af7SToomas Soome 			firsttime = 0;
21421ec5af7SToomas Soome 		} else {
215695ef821SGordon Ross 			len = snprintf(buffer, buflen, ",%s", member_str);
21621ec5af7SToomas Soome 		}
217695ef821SGordon Ross 		TEST_AND_ADJUST(len, buffer, buflen, out);
218695ef821SGordon Ross 	}
219695ef821SGordon Ross 
220695ef821SGordon Ross out:
221695ef821SGordon Ross 	*bufpp = buffer;
222695ef821SGordon Ross 	*lenp = buflen;
223695ef821SGordon Ross 	return (nss_result);
224695ef821SGordon Ross }
225695ef821SGordon Ross 
226695ef821SGordon Ross /*
227695ef821SGordon Ross  * Process the list values from the "member" attribute of the
228695ef821SGordon Ross  * current group.  Note that this list is ONLY one that can be
229695ef821SGordon Ross  * assumed to be non-empty.  The problem here is that this list
230695ef821SGordon Ross  * contains the list of members as "distinguished names" (DN),
231695ef821SGordon Ross  * and we want the Unix names (known here as "uid").  We must
232695ef821SGordon Ross  * lookup the "uid" for each DN in the member list.  Example:
233695ef821SGordon Ross  * CN=Doe\, John,OU=Users,DC=contoso,DC=com => john.doe
234695ef821SGordon Ross  */
235695ef821SGordon Ross static int
getmembers_DN(char ** bufpp,int * lenp,ns_ldap_attr_t * members)236695ef821SGordon Ross getmembers_DN(char **bufpp, int *lenp, ns_ldap_attr_t *members)
237695ef821SGordon Ross {
238695ef821SGordon Ross 	ns_ldap_error_t *error = NULL;
239695ef821SGordon Ross 	char	*member_dn, *member_uid;
240695ef821SGordon Ross 	char	*buffer;
241695ef821SGordon Ross 	int	buflen;
242695ef821SGordon Ross 	int	i, len;
243*d7ab8532SJason King 	int	nss_result = 0; /* used by TEST_AND_ADJUST macro */
244695ef821SGordon Ross 	int	firsttime;
245695ef821SGordon Ross 
246695ef821SGordon Ross 	buffer = *bufpp;
247695ef821SGordon Ross 	buflen = *lenp;
248695ef821SGordon Ross 	firsttime = (buffer[-1] == ':');
249695ef821SGordon Ross 
250695ef821SGordon Ross 	for (i = 0; i < members->value_count; i++) {
251695ef821SGordon Ross 		member_dn = members->attrvalue[i];
252695ef821SGordon Ross 		if (member_dn == NULL)
253695ef821SGordon Ross 			goto out;
254695ef821SGordon Ross 
255695ef821SGordon Ross 		/*
256695ef821SGordon Ross 		 * The attribute name was "member", so these should be
257695ef821SGordon Ross 		 * full distinguished names (DNs).  We need to loookup
258695ef821SGordon Ross 		 * the Unix UID (name) for each.
259695ef821SGordon Ross 		 */
260695ef821SGordon Ross #ifdef DEBUG
261695ef821SGordon Ross 		(void) fprintf(stdout, "getmembers_DN: dn=%s\n",
262695ef821SGordon Ross 		    member_dn);
263695ef821SGordon Ross #endif
264695ef821SGordon Ross 		if (member_dn[0] == '\0')
265695ef821SGordon Ross 			continue;
266695ef821SGordon Ross 
267*d7ab8532SJason King 		if (__ns_ldap_dn2uid(member_dn,
268*d7ab8532SJason King 		    &member_uid, NULL, &error) != NS_LDAP_SUCCESS) {
269695ef821SGordon Ross 			(void) __ns_ldap_freeError(&error);
270695ef821SGordon Ross 			error = NULL;
271695ef821SGordon Ross 			continue;
272695ef821SGordon Ross 		}
273695ef821SGordon Ross #ifdef DEBUG
274695ef821SGordon Ross 		(void) fprintf(stdout, "getmembers_DN: uid=<%s>\n",
275695ef821SGordon Ross 		    member_uid);
276695ef821SGordon Ross #endif
277695ef821SGordon Ross 		/* Skip invalid names. */
278695ef821SGordon Ross 		if (member_uid[0] == '\0' ||
279695ef821SGordon Ross 		    strpbrk(member_uid, " ,:=") != NULL) {
280695ef821SGordon Ross 			free(member_uid);
281695ef821SGordon Ross 			continue;
282695ef821SGordon Ross 		}
283695ef821SGordon Ross 
28421ec5af7SToomas Soome 		if (firsttime) {
285695ef821SGordon Ross 			len = snprintf(buffer, buflen, "%s", member_uid);
28621ec5af7SToomas Soome 			firsttime = 0;
28721ec5af7SToomas Soome 		} else {
288695ef821SGordon Ross 			len = snprintf(buffer, buflen, ",%s", member_uid);
28921ec5af7SToomas Soome 		}
290695ef821SGordon Ross 		free(member_uid);
291695ef821SGordon Ross 		TEST_AND_ADJUST(len, buffer, buflen, out);
292695ef821SGordon Ross 	}
293695ef821SGordon Ross 
294695ef821SGordon Ross out:
295695ef821SGordon Ross 	*bufpp = buffer;
296695ef821SGordon Ross 	*lenp = buflen;
297695ef821SGordon Ross 	return (nss_result);
298695ef821SGordon Ross }
299695ef821SGordon Ross 
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate  * getbynam gets a group entry by name. This function constructs an ldap
3027c478bd9Sstevel@tonic-gate  * search filter using the name invocation parameter and the getgrnam search
3037c478bd9Sstevel@tonic-gate  * filter defined. Once the filter is constructed, we searche for a matching
3047c478bd9Sstevel@tonic-gate  * entry and marshal the data results into struct group for the frontend
3057c478bd9Sstevel@tonic-gate  * process. The function _nss_ldap_group2ent performs the data marshaling.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate static nss_status_t
getbynam(ldap_backend_ptr be,void * a)3097c478bd9Sstevel@tonic-gate getbynam(ldap_backend_ptr be, void *a)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
3127c478bd9Sstevel@tonic-gate 	char		searchfilter[SEARCHFILTERLEN];
3137c478bd9Sstevel@tonic-gate 	char		userdata[SEARCHFILTERLEN];
3147c478bd9Sstevel@tonic-gate 	char		groupname[SEARCHFILTERLEN];
3157c478bd9Sstevel@tonic-gate 	int		ret;
3167c478bd9Sstevel@tonic-gate 
31718bdb8a7Smichen 	if (_ldap_filter_name(groupname, argp->key.name, sizeof (groupname)) !=
31818bdb8a7Smichen 	    0)
3197c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	ret = snprintf(searchfilter, sizeof (searchfilter),
3227c478bd9Sstevel@tonic-gate 	    _F_GETGRNAM, groupname);
3237c478bd9Sstevel@tonic-gate 	if (ret >= sizeof (searchfilter) || ret < 0)
3247c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	ret = snprintf(userdata, sizeof (userdata), _F_GETGRNAM_SSD, groupname);
3277c478bd9Sstevel@tonic-gate 	if (ret >= sizeof (userdata) || ret < 0)
3287c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
33118bdb8a7Smichen 	    _GROUP, searchfilter, NULL, _merge_SSD_filter, userdata));
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * getbygid gets a group entry by number. This function constructs an ldap
3377c478bd9Sstevel@tonic-gate  * search filter using the name invocation parameter and the getgrgid search
3387c478bd9Sstevel@tonic-gate  * filter defined. Once the filter is constructed, we searche for a matching
3397c478bd9Sstevel@tonic-gate  * entry and marshal the data results into struct group for the frontend
3407c478bd9Sstevel@tonic-gate  * process. The function _nss_ldap_group2ent performs the data marshaling.
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate static nss_status_t
getbygid(ldap_backend_ptr be,void * a)3447c478bd9Sstevel@tonic-gate getbygid(ldap_backend_ptr be, void *a)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
3477c478bd9Sstevel@tonic-gate 	char searchfilter[SEARCHFILTERLEN];
3487c478bd9Sstevel@tonic-gate 	char userdata[SEARCHFILTERLEN];
3497c478bd9Sstevel@tonic-gate 	int ret;
3507c478bd9Sstevel@tonic-gate 
3512b4a7802SBaban Kenkre 	if (argp->key.uid > MAXUID)
3522b4a7802SBaban Kenkre 		return ((nss_status_t)NSS_NOTFOUND);
3532b4a7802SBaban Kenkre 
3547c478bd9Sstevel@tonic-gate 	ret = snprintf(searchfilter, sizeof (searchfilter),
355f48205beScasper 	    _F_GETGRGID, argp->key.uid);
3567c478bd9Sstevel@tonic-gate 	if (ret >= sizeof (searchfilter) || ret < 0)
3577c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	ret = snprintf(userdata, sizeof (userdata),
360f48205beScasper 	    _F_GETGRGID_SSD, argp->key.uid);
3617c478bd9Sstevel@tonic-gate 	if (ret >= sizeof (userdata) || ret < 0)
3627c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
36518bdb8a7Smichen 	    _GROUP, searchfilter, NULL, _merge_SSD_filter, userdata));
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 
370695ef821SGordon Ross /*
371695ef821SGordon Ross  * Use a custom attributes list for getbymember, because the LDAP
372695ef821SGordon Ross  * query for this requests a list of groups, and the result can be
373695ef821SGordon Ross  * very large if it includes the list of members with each group.
374695ef821SGordon Ross  * We don't need or want the list of members in this case.
375695ef821SGordon Ross  */
376695ef821SGordon Ross static const char *grbymem_attrs[] = {
377695ef821SGordon Ross 	_G_NAME,	/* cn */
378695ef821SGordon Ross 	_G_GID,		/* gidnumber */
379695ef821SGordon Ross 	(char *)NULL
380695ef821SGordon Ross };
381695ef821SGordon Ross 
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate  * getbymember returns all groups a user is defined in. This function
3847c478bd9Sstevel@tonic-gate  * uses different architectural procedures than the other group backend
3857c478bd9Sstevel@tonic-gate  * system calls because it's a private interface. This function constructs
3867c478bd9Sstevel@tonic-gate  * an ldap search filter using the name invocation parameter. Once the
3877c478bd9Sstevel@tonic-gate  * filter is constructed, we search for all matching groups counting
3887c478bd9Sstevel@tonic-gate  * and storing each group name, gid, etc. Data marshaling is used for
3897c478bd9Sstevel@tonic-gate  * group processing. The function _nss_ldap_group2ent() performs the
3907c478bd9Sstevel@tonic-gate  * data marshaling.
3917c478bd9Sstevel@tonic-gate  *
3927c478bd9Sstevel@tonic-gate  * (const char *)argp->username;	(size_t)strlen(argp->username);
3937c478bd9Sstevel@tonic-gate  * (gid_t)argp->gid_array;		(int)argp->maxgids;
3947c478bd9Sstevel@tonic-gate  * (int)argp->numgids;
3957c478bd9Sstevel@tonic-gate  */
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate static nss_status_t
getbymember(ldap_backend_ptr be,void * a)3987c478bd9Sstevel@tonic-gate getbymember(ldap_backend_ptr be, void *a)
3997c478bd9Sstevel@tonic-gate {
400695ef821SGordon Ross 	ns_ldap_error_t		*error = NULL;
4017c478bd9Sstevel@tonic-gate 	int			i, j, k;
4027c478bd9Sstevel@tonic-gate 	int			gcnt = (int)0;
403695ef821SGordon Ross 	char			**groupvalue;
4047c478bd9Sstevel@tonic-gate 	nss_status_t		lstat;
4057c478bd9Sstevel@tonic-gate 	struct nss_groupsbymem	*argp = (struct nss_groupsbymem *)a;
4067c478bd9Sstevel@tonic-gate 	char			searchfilter[SEARCHFILTERLEN];
4077c478bd9Sstevel@tonic-gate 	char			userdata[SEARCHFILTERLEN];
4087c478bd9Sstevel@tonic-gate 	char			name[SEARCHFILTERLEN];
409695ef821SGordon Ross 	char			escdn[SEARCHFILTERLEN];
4107c478bd9Sstevel@tonic-gate 	ns_ldap_result_t	*result;
4117c478bd9Sstevel@tonic-gate 	ns_ldap_entry_t		*curEntry;
412695ef821SGordon Ross 	char			*dn;
4137c478bd9Sstevel@tonic-gate 	gid_t			gid;
414695ef821SGordon Ross 	int			ret1, ret2;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (strcmp(argp->username, "") == 0 ||
4177c478bd9Sstevel@tonic-gate 	    strcmp(argp->username, "root") == 0)
4187c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (_ldap_filter_name(name, argp->username, sizeof (name)) != 0)
4217c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
4227c478bd9Sstevel@tonic-gate 
4234c6ae461SPaul B. Henson 	/*
4244c6ae461SPaul B. Henson 	 * Look up the user DN in ldap. If it's not found, search solely by
4254c6ae461SPaul B. Henson 	 * username.
4264c6ae461SPaul B. Henson 	 */
427695ef821SGordon Ross 	lstat = __ns_ldap_uid2dn(name, &dn, NULL, &error);
428695ef821SGordon Ross 	if (lstat != (nss_status_t)NS_LDAP_SUCCESS) {
429695ef821SGordon Ross 		/* Can't get DN.  Use bare name */
430695ef821SGordon Ross 		(void) __ns_ldap_freeError(&error);
4314c6ae461SPaul B. Henson 		dn = name;
432695ef821SGordon Ross 	}
433695ef821SGordon Ross 	/* Note: must free dn if != name */
4344c6ae461SPaul B. Henson 
435695ef821SGordon Ross 	/*
436695ef821SGordon Ross 	 * Compose filter patterns
437695ef821SGordon Ross 	 */
438695ef821SGordon Ross 	ret1 = snprintf(searchfilter, sizeof (searchfilter),
439695ef821SGordon Ross 	    _F_GETGRMEM, name, dn);
440695ef821SGordon Ross 	ret2 = snprintf(userdata, sizeof (userdata),
441695ef821SGordon Ross 	    _F_GETGRMEM_SSD, name, dn);
442695ef821SGordon Ross 	if (dn != name)
443695ef821SGordon Ross 		free(dn);
444695ef821SGordon Ross 	if (ret1 >= sizeof (searchfilter) || ret1 < 0)
4457c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
446695ef821SGordon Ross 	if (ret2 >= sizeof (userdata) || ret2 < 0)
4477c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
4487c478bd9Sstevel@tonic-gate 
4494c6ae461SPaul B. Henson 	/*
450695ef821SGordon Ross 	 * Query for groups matching the filter.
4514c6ae461SPaul B. Henson 	 */
45218bdb8a7Smichen 	lstat = (nss_status_t)_nss_ldap_nocb_lookup(be, NULL,
453695ef821SGordon Ross 	    _GROUP, searchfilter, grbymem_attrs,
454695ef821SGordon Ross 	    _merge_SSD_filter, userdata);
4557c478bd9Sstevel@tonic-gate 	if (lstat != (nss_status_t)NS_LDAP_SUCCESS)
4567c478bd9Sstevel@tonic-gate 		return ((nss_status_t)lstat);
4577c478bd9Sstevel@tonic-gate 	if (be->result == NULL)
4587c478bd9Sstevel@tonic-gate 		return (NSS_NOTFOUND);
459695ef821SGordon Ross 
460695ef821SGordon Ross 	/*
461695ef821SGordon Ross 	 * Walk the query result, collecting GIDs.
462695ef821SGordon Ross 	 */
4637c478bd9Sstevel@tonic-gate 	result = (ns_ldap_result_t *)be->result;
4647c478bd9Sstevel@tonic-gate 	curEntry = (ns_ldap_entry_t *)result->entry;
465695ef821SGordon Ross 	gcnt = (int)argp->numgids;
466695ef821SGordon Ross 	for (i = 0; i < result->entries_count; i++) {
467695ef821SGordon Ross 
468695ef821SGordon Ross 		/*
469695ef821SGordon Ross 		 * Does this group have a gidNumber attr?
470695ef821SGordon Ross 		 */
471695ef821SGordon Ross 		groupvalue = __ns_ldap_getAttr(curEntry, _G_GID);
472695ef821SGordon Ross 		if (groupvalue == NULL || groupvalue[0] == NULL) {
473695ef821SGordon Ross 			/* Drop this group from the list */
474695ef821SGordon Ross 			goto next_group;
475a3bcc60dSMatt Barden 		}
476695ef821SGordon Ross 
477695ef821SGordon Ross 		/*
478695ef821SGordon Ross 		 * Convert it to a numeric GID
479695ef821SGordon Ross 		 */
480695ef821SGordon Ross 		errno = 0;
481695ef821SGordon Ross 		gid = (gid_t)strtol(groupvalue[0], (char **)NULL, 10);
482695ef821SGordon Ross 		if (errno != 0)
483695ef821SGordon Ross 			goto next_group;
484695ef821SGordon Ross 
485695ef821SGordon Ross 		/*
486695ef821SGordon Ross 		 * If we don't already have this GID, add it.
487695ef821SGordon Ross 		 */
488695ef821SGordon Ross 		if (argp->numgids < argp->maxgids) {
489695ef821SGordon Ross 			for (k = 0; k < argp->numgids; k++) {
490695ef821SGordon Ross 				if (argp->gid_array[k] == gid) {
491695ef821SGordon Ross 					/* already have it */
492695ef821SGordon Ross 					goto next_group;
4937c478bd9Sstevel@tonic-gate 				}
4947c478bd9Sstevel@tonic-gate 			}
495695ef821SGordon Ross 			argp->gid_array[argp->numgids++] = gid;
4967c478bd9Sstevel@tonic-gate 		}
497695ef821SGordon Ross 
498695ef821SGordon Ross 	next_group:
4997c478bd9Sstevel@tonic-gate 		curEntry = curEntry->next;
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
502cb5caa98Sdjl 	(void) __ns_ldap_freeResult((ns_ldap_result_t **)&be->result);
5037c478bd9Sstevel@tonic-gate 	if (gcnt == argp->numgids)
5047c478bd9Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
5057c478bd9Sstevel@tonic-gate 
50620e6d5c5Ssc 	/*
50720e6d5c5Ssc 	 * Return NSS_SUCCESS only if array is full.
50820e6d5c5Ssc 	 * Explained in <nss_dbdefs.h>.
50920e6d5c5Ssc 	 */
51020e6d5c5Ssc 	return ((nss_status_t)((argp->numgids == argp->maxgids)
51120e6d5c5Ssc 	    ? NSS_SUCCESS
51220e6d5c5Ssc 	    : NSS_NOTFOUND));
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate static ldap_backend_op_t gr_ops[] = {
5167c478bd9Sstevel@tonic-gate 	_nss_ldap_destr,
5177c478bd9Sstevel@tonic-gate 	_nss_ldap_endent,
5187c478bd9Sstevel@tonic-gate 	_nss_ldap_setent,
5197c478bd9Sstevel@tonic-gate 	_nss_ldap_getent,
5207c478bd9Sstevel@tonic-gate 	getbynam,
5217c478bd9Sstevel@tonic-gate 	getbygid,
5227c478bd9Sstevel@tonic-gate 	getbymember
5237c478bd9Sstevel@tonic-gate };
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate /*ARGSUSED0*/
5277c478bd9Sstevel@tonic-gate nss_backend_t *
_nss_ldap_group_constr(const char * dummy1,const char * dummy2,const char * dummy3)5287c478bd9Sstevel@tonic-gate _nss_ldap_group_constr(const char *dummy1, const char *dummy2,
52921ec5af7SToomas Soome     const char *dummy3)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	return ((nss_backend_t *)_nss_ldap_constr(gr_ops,
53318bdb8a7Smichen 	    sizeof (gr_ops)/sizeof (gr_ops[0]), _GROUP, gr_attrs,
53418bdb8a7Smichen 	    _nss_ldap_group2str));
5357c478bd9Sstevel@tonic-gate }
536