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