/* group.c - group entry lookup routines This file was part of the nss_ldap library (as ldap-grp.c) which has been forked into the nss-ldapd library. Copyright (C) 1997-2006 Luke Howard Copyright (C) 2006 West Consulting Copyright (C) 2006, 2007 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_LBER_H #include #endif #ifdef HAVE_LDAP_H #include #endif #if defined(HAVE_THREAD_H) #include #elif defined(HAVE_PTHREAD_H) #include #endif #include "ldap-nss.h" #include "util.h" #include "common.h" #include "log.h" #include "cfg.h" /* FIXME: fix following problem: if the entry has multiple cn fields we may end up sending the wrong cn, we should return the requested cn instead, otherwise write an entry for each cn */ struct name_list { char *name; struct name_list *next; }; #ifdef HAVE_USERSEC_H typedef struct ldap_initgroups_args { char *grplist; size_t listlen; int depth; struct name_list *known_groups; int backlink; } ldap_initgroups_args_t; #else typedef struct ldap_initgroups_args { gid_t group; long int *start; long int *size; gid_t **groups; long int limit; int depth; struct name_list *known_groups; int backlink; } ldap_initgroups_args_t; #endif /* HAVE_USERSEC_H */ #define LDAP_NSS_MAXGR_DEPTH 16 /* maximum depth of group nesting for getgrent()/initgroups() */ #if LDAP_NSS_NGROUPS > 64 #define LDAP_NSS_BUFLEN_GROUP (1024 + (LDAP_NSS_NGROUPS * (sizeof (char *) + LOGNAME_MAX))) #else #define LDAP_NSS_BUFLEN_GROUP 1024 #endif /* LDAP_NSS_NGROUPS > 64 */ #ifndef LOGNAME_MAX #define LOGNAME_MAX 8 #endif /* LOGNAME_MAX */ #ifndef UID_NOBODY #define UID_NOBODY (-2) #endif #ifndef GID_NOBODY #define GID_NOBODY UID_NOBODY #endif static enum nss_status ng_chase (const char *dn, ldap_initgroups_args_t * lia); static enum nss_status ng_chase_backlink (const char ** membersOf, ldap_initgroups_args_t * lia); /* * Add a nested netgroup or group to the namelist */ static enum nss_status _nss_ldap_namelist_push(struct name_list **head,const char *name) { struct name_list *nl; log_log(LOG_DEBUG,"==> _nss_ldap_namelist_push (%s)", name); nl = (struct name_list *) malloc (sizeof (*nl)); if (nl == NULL) { log_log(LOG_DEBUG,"<== _nss_ldap_namelist_push"); return NSS_STATUS_TRYAGAIN; } nl->name = strdup (name); if (nl->name == NULL) { log_log(LOG_DEBUG,"<== _nss_ldap_namelist_push"); free (nl); return NSS_STATUS_TRYAGAIN; } nl->next = *head; *head = nl; log_log(LOG_DEBUG,"<== _nss_ldap_namelist_push"); return NSS_STATUS_SUCCESS; } /* * Cleanup nested netgroup or group namelist. */ static void _nss_ldap_namelist_destroy(struct name_list **head) { struct name_list *p, *next; log_log(LOG_DEBUG,"==> _nss_ldap_namelist_destroy"); for (p = *head; p != NULL; p = next) { next = p->next; if (p->name != NULL) free (p->name); free (p); } *head = NULL; log_log(LOG_DEBUG,"<== _nss_ldap_namelist_destroy"); } /* * Check whether we have already seen a netgroup or group, * to avoid loops in nested netgroup traversal */ static int _nss_ldap_namelist_find(struct name_list *head,const char *netgroup) { struct name_list *p; int found = 0; log_log(LOG_DEBUG,"==> _nss_ldap_namelist_find"); for (p = head; p != NULL; p = p->next) { if (strcasecmp (p->name, netgroup) == 0) { found++; break; } } log_log(LOG_DEBUG,"<== _nss_ldap_namelist_find"); return found; } /* * Range retrieval logic was reimplemented from example in * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/searching_using_range_retrieval.asp */ static enum nss_status do_parse_range (const char *attributeType, const char *attributeDescription, int *start, int *end) { enum nss_status stat = NSS_STATUS_NOTFOUND; char *attribute; size_t attributeTypeLength; size_t attributeDescriptionLength; char *p; #ifdef HAVE_STRTOK_R char *st = NULL; #endif *start = 0; *end = -1; if (strcasecmp (attributeType, attributeDescription) == 0) { return NSS_STATUS_SUCCESS; } attributeDescriptionLength = strlen (attributeDescription); attributeTypeLength = strlen (attributeType); if (attributeDescriptionLength < attributeTypeLength) { /* could not be a subtype */ return NSS_STATUS_NOTFOUND; } /* XXX need to copy as strtok() is destructive */ attribute = strdup (attributeDescription); if (attribute == NULL) { return NSS_STATUS_TRYAGAIN; } #ifndef HAVE_STRTOK_R for (p = strtok (attribute, ";"); p != NULL; p = strtok (NULL, ";")) #else for (p = strtok_r (attribute, ";", &st); p != NULL; p = strtok_r (NULL, ";", &st)) #endif /* !HAVE_STRTOK_R */ { char *q; if (p == attribute) { if (strcasecmp (p, attributeType) != 0) { free (attribute); return NSS_STATUS_NOTFOUND; } } else if (strncasecmp (p, "range=", sizeof ("range=") - 1) == 0) { p += sizeof ("range=") - 1; q = strchr (p, '-'); if (q == NULL) { free (attribute); return NSS_STATUS_NOTFOUND; } *q++ = '\0'; *start = strtoul (p, (char **) NULL, 10); if (strcmp (q, "*") == 0) *end = -1; else *end = strtoul (q, (char **) NULL, 10); stat = NSS_STATUS_SUCCESS; break; } } free (attribute); return stat; } static enum nss_status do_get_range_values (LDAPMessage * e, const char *attributeType, int *start, int *end, char ***pGroupMembers) { enum nss_status stat = NSS_STATUS_NOTFOUND; BerElement *ber = NULL; char *attribute; *pGroupMembers = NULL; for (attribute = _nss_ldap_first_attribute (e, &ber); attribute != NULL; attribute = _nss_ldap_next_attribute (e, ber)) { stat = do_parse_range (attributeType, attribute, start, end); if (stat == NSS_STATUS_SUCCESS) { *pGroupMembers = _nss_ldap_get_values (e, attribute); if (*pGroupMembers == NULL) { stat = NSS_STATUS_NOTFOUND; } else if ((*pGroupMembers)[0] == NULL) { ldap_value_free (*pGroupMembers); *pGroupMembers = NULL; stat = NSS_STATUS_NOTFOUND; } } #ifdef HAVE_LDAP_MEMFREE ldap_memfree (attribute); #endif if (stat == NSS_STATUS_SUCCESS) break; } if (ber != NULL) ber_free (ber, 0); return stat; } /* * Format an attribute with description as: * attribute;range=START-END */ static enum nss_status do_construct_range_attribute (const char *attribute, int start, int end, char **buffer, size_t * buflen, const char **pAttributeWithRange) { size_t len; char startbuf[32], endbuf[32]; snprintf (startbuf, sizeof (startbuf), "%u", start); if (end != -1) snprintf (endbuf, sizeof (endbuf), "%u", end); else snprintf (endbuf, sizeof (endbuf), "*"); len = strlen (attribute) + sizeof (";range=") - 1; len += strlen (startbuf) + 1 /* - */ + strlen (endbuf); len++; /* \0 */ if (*buflen < len) return NSS_STATUS_TRYAGAIN; *pAttributeWithRange = *buffer; snprintf (*buffer, len, "%s;range=%s-%s", attribute, startbuf, endbuf); *buffer += len; *buflen -= len; return NSS_STATUS_SUCCESS; } /* * Expand group members, including nested groups */ static enum nss_status do_parse_group_members (LDAPMessage * e, char ***pGroupMembers, size_t * pGroupMembersCount, size_t * pGroupMembersBufferSize, int *pGroupMembersBufferIsMalloced, char **buffer, size_t * buflen, int *depth, struct name_list **pKnownGroups) /* traversed groups */ { enum nss_status stat = NSS_STATUS_SUCCESS; char **dnValues = NULL; char **uidValues = NULL; char **groupMembers; size_t groupMembersCount, i; char **valiter; /* support for range retrieval */ const char *uniquemember_attr; const char *uniquemember_attrs[2]; LDAPMessage *res = NULL; int start, end = 0; char *groupdn = NULL; uniquemember_attr = ATM (LM_GROUP, uniqueMember); uniquemember_attrs[0] = uniquemember_attr; uniquemember_attrs[1] = NULL; if (*depth > LDAP_NSS_MAXGR_DEPTH) { return NSS_STATUS_NOTFOUND; } i = *pGroupMembersCount; /* index of next member */ groupMembers = *pGroupMembers; groupdn = _nss_ldap_get_dn (e); if (groupdn == NULL) { stat = NSS_STATUS_NOTFOUND; goto out; } if (_nss_ldap_namelist_find (*pKnownGroups, groupdn)) { stat = NSS_STATUS_NOTFOUND; goto out; } /* store group DN for nested group loop detection */ stat = _nss_ldap_namelist_push (pKnownGroups, groupdn); if (stat != NSS_STATUS_SUCCESS) { goto out; } do { if (e == NULL) { stat = NSS_STATUS_NOTFOUND; goto out; } groupMembersCount = 0; /* number of members in this group */ (void) do_get_range_values (e, uniquemember_attrs[0], &start, &end, &dnValues); if (dnValues != NULL) { groupMembersCount += ldap_count_values (dnValues); } uidValues = _nss_ldap_get_values (e, ATM (LM_GROUP, memberUid)); if (uidValues != NULL) { groupMembersCount += ldap_count_values (uidValues); } /* * Check whether we need to increase the group membership buffer. * As an optimization the buffer is preferentially allocated off * the stack */ if ((i + groupMembersCount) * sizeof (char *) >= *pGroupMembersBufferSize) { *pGroupMembersBufferSize = (i + groupMembersCount + 1) * sizeof (char *); *pGroupMembersBufferSize += (LDAP_NSS_NGROUPS * sizeof (char *)) - 1; *pGroupMembersBufferSize -= (*pGroupMembersBufferSize % (LDAP_NSS_NGROUPS * sizeof (char *))); if (*pGroupMembersBufferIsMalloced == 0) { groupMembers = *pGroupMembers; *pGroupMembers = NULL; /* force malloc() */ } *pGroupMembers = (char **) realloc (*pGroupMembers, *pGroupMembersBufferSize); if (*pGroupMembers == NULL) { *pGroupMembersBufferIsMalloced = 0; /* don't try to free */ stat = NSS_STATUS_TRYAGAIN; goto out; } if (*pGroupMembersBufferIsMalloced == 0) { memcpy (*pGroupMembers, groupMembers, i * sizeof (char *)); groupMembers = NULL; /* defensive programming */ *pGroupMembersBufferIsMalloced = 1; } } groupMembers = *pGroupMembers; /* Parse distinguished name members */ if (dnValues != NULL) { for (valiter = dnValues; *valiter != NULL; valiter++) { LDAPMessage *res; enum nss_status parseStat; int isNestedGroup = 0; char *uid; uid = strrchr (*valiter, '#'); if (uid != NULL) { *uid = '\0'; } parseStat = _nss_ldap_dn2uid (*valiter, &groupMembers[i], buffer, buflen, &isNestedGroup, &res); if (parseStat == NSS_STATUS_SUCCESS) { if (isNestedGroup == 0) { /* just a normal user which we have flattened */ i++; continue; } (*depth)++; parseStat = do_parse_group_members (_nss_ldap_first_entry (res), &groupMembers, &i, pGroupMembersBufferSize, pGroupMembersBufferIsMalloced, buffer, buflen, depth, pKnownGroups); (*depth)--; if (parseStat == NSS_STATUS_TRYAGAIN) { stat = NSS_STATUS_TRYAGAIN; goto out; } ldap_msgfree (res); } else if (parseStat == NSS_STATUS_TRYAGAIN) { stat = NSS_STATUS_TRYAGAIN; goto out; } } } /* Parse RFC 2307 (flat) members */ if (uidValues != NULL) { for (valiter = uidValues; *valiter != NULL; valiter++) { size_t len = strlen (*valiter) + 1; if (*buflen < len) { stat = NSS_STATUS_TRYAGAIN; goto out; } groupMembers[i] = *buffer; *buffer += len; *buflen -= len; memcpy (groupMembers[i++], *valiter, len); } } /* Get next range for Active Directory compat */ if (end != -1) { stat = do_construct_range_attribute (uniquemember_attr, end + 1, -1, buffer, buflen, &uniquemember_attrs[0]); if (stat == NSS_STATUS_SUCCESS) { if (dnValues != NULL) { ldap_value_free (dnValues); dnValues = NULL; } if (uidValues != NULL) { ldap_value_free (uidValues); uidValues = NULL; } if (res != NULL) { ldap_msgfree (res); res = NULL; } stat = _nss_ldap_read (groupdn, uniquemember_attrs, &res); if (stat != NSS_STATUS_SUCCESS) goto out; e = _nss_ldap_first_entry (res); } } } while (end != -1); out: if (dnValues != NULL) ldap_value_free (dnValues); if (uidValues != NULL) ldap_value_free (uidValues); if (res != NULL) ldap_msgfree (res); if (groupdn != NULL) #ifdef HAVE_LDAP_MEMFREE ldap_memfree (groupdn); #else free (groupdn); #endif *pGroupMembers = groupMembers; *pGroupMembersCount = i; return stat; } /* * "Fix" group membership list into caller provided buffer, * and NULL terminate. */ static enum nss_status do_fix_group_members_buffer (char **mallocedGroupMembers, size_t groupMembersCount, char ***pGroupMembers, char **buffer, size_t * buflen) { size_t len; len = (groupMembersCount + 1) * sizeof (char *); if (bytesleft (*buffer, *buflen, char *) < len) { return NSS_STATUS_TRYAGAIN; } align (*buffer, *buflen, char *); *pGroupMembers = (char **) *buffer; *buffer += len; *buflen -= len; memcpy (*pGroupMembers, mallocedGroupMembers, groupMembersCount * sizeof (char *)); (*pGroupMembers)[groupMembersCount] = NULL; return NSS_STATUS_SUCCESS; } static enum nss_status _nss_ldap_parse_gr (LDAPMessage * e, struct ldap_state * pvt, void *result, char *buffer, size_t buflen) { struct group *gr = (struct group *) result; char *gid; enum nss_status stat; char **groupMembers; size_t groupMembersCount; size_t groupMembersBufferSize; char *groupMembersBuffer[LDAP_NSS_NGROUPS]; int groupMembersBufferIsMalloced; int depth; struct name_list *knownGroups = NULL; stat = _nss_ldap_assign_attrval (e, ATM (LM_GROUP, gidNumber), &gid, &buffer, &buflen); if (stat != NSS_STATUS_SUCCESS) return stat; gr->gr_gid = (*gid == '\0') ? (unsigned) GID_NOBODY : (gid_t) strtoul (gid, (char **) NULL, 10); stat = _nss_ldap_getrdnvalue (e, ATM (LM_GROUP, cn), &gr->gr_name, &buffer, &buflen); if (stat != NSS_STATUS_SUCCESS) return stat; stat = _nss_ldap_assign_userpassword (e, ATM (LM_GROUP, userPassword), &gr->gr_passwd, &buffer, &buflen); if (stat != NSS_STATUS_SUCCESS) return stat; if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS)) { groupMembers = groupMembersBuffer; groupMembersCount = 0; groupMembersBufferSize = sizeof (groupMembers); groupMembersBufferIsMalloced = 0; depth = 0; stat = do_parse_group_members (e, &groupMembers, &groupMembersCount, &groupMembersBufferSize, &groupMembersBufferIsMalloced, &buffer, &buflen, &depth, &knownGroups); if (stat != NSS_STATUS_SUCCESS) { if (groupMembersBufferIsMalloced) free (groupMembers); _nss_ldap_namelist_destroy (&knownGroups); return stat; } stat = do_fix_group_members_buffer (groupMembers, groupMembersCount, &gr->gr_mem, &buffer, &buflen); if (groupMembersBufferIsMalloced) free (groupMembers); _nss_ldap_namelist_destroy (&knownGroups); } else { stat = _nss_ldap_assign_attrvals (e, ATM (LM_GROUP, memberUid), NULL, &gr->gr_mem, &buffer, &buflen, NULL); } return stat; } /* * Add a group ID to a group list, and optionally the group IDs * of any groups to which this group belongs (RFC2307bis nested * group expansion is done by do_parse_initgroups_nested()). */ static enum nss_status do_parse_initgroups (LDAPMessage * e, struct ldap_state * pvt, void *result, char *buffer, size_t buflen) { char **values; ssize_t i; gid_t gid; ldap_initgroups_args_t *lia = (ldap_initgroups_args_t *) result; values = _nss_ldap_get_values (e, ATM (LM_GROUP, gidNumber)); if (values == NULL) { /* invalid group; skip it */ return NSS_STATUS_NOTFOUND; } if (values[0] == NULL) { /* invalid group; skip it */ ldap_value_free (values); return NSS_STATUS_NOTFOUND; } #ifdef HAVE_USERSEC_H i = strlen (values[0]); lia->grplist = realloc (lia->grplist, lia->listlen + i + 2); if (lia->grplist == NULL) { ldap_value_free (values); return NSS_STATUS_TRYAGAIN; } memcpy (lia->grplist + lia->listlen, values[0], i); lia->grplist[lia->listlen + i] = ','; lia->listlen += i + 1; ldap_value_free (values); #else gid = strtoul (values[0], (char **) NULL, 10); ldap_value_free (values); if (gid == LONG_MAX && errno == ERANGE) { /* invalid group, skip it */ return NSS_STATUS_NOTFOUND; } if (gid == lia->group) { /* primary group, so skip it */ return NSS_STATUS_NOTFOUND; } if (lia->limit > 0) { if (*(lia->start) >= lia->limit) { /* can't fit any more */ return NSS_STATUS_TRYAGAIN; } } if (*(lia->start) == *(lia->size)) { /* Need a bigger buffer */ *(lia->groups) = (gid_t *) realloc (*(lia->groups), 2 * *(lia->size) * sizeof (gid_t)); if (*(lia->groups) == NULL) { return NSS_STATUS_TRYAGAIN; } *(lia->size) *= 2; } /* weed out duplicates; is this really our responsibility? */ for (i = 0; i < *(lia->start); i++) { if ((*(lia->groups))[i] == gid) { return NSS_STATUS_NOTFOUND; } } /* add to group list */ (*(lia->groups))[*(lia->start)] = gid; (*(lia->start)) += 1; #endif /* HAVE_USERSEC_H */ return NSS_STATUS_NOTFOUND; } static enum nss_status do_parse_initgroups_nested (LDAPMessage * e, struct ldap_state * pvt, void *result, char *buffer, size_t buflen) { enum nss_status status; ldap_initgroups_args_t *lia = (ldap_initgroups_args_t *) result; char **values; char *groupdn; status = do_parse_initgroups (e, pvt, result, buffer, buflen); if (status != NSS_STATUS_NOTFOUND) { return status; } if (!_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS)) { return NSS_STATUS_NOTFOUND; } if (lia->backlink != 0) { /* * Now add the GIDs of any groups of which this group is * a member. */ values = _nss_ldap_get_values (e, ATM (LM_GROUP, memberOf)); if (values != NULL) { lia->depth++; status = ng_chase_backlink ((const char **)values, lia); lia->depth--; ldap_value_free (values); return status; } } else { /* * Now add the GIDs of any groups which refer to this group */ groupdn = _nss_ldap_get_dn (e); if (groupdn != NULL) { /* Note: there was a problem here with stat in the orriginal code */ lia->depth++; status = ng_chase (groupdn, lia); lia->depth--; #ifdef HAVE_LDAP_MEMFREE ldap_memfree (groupdn); #else free (groupdn); #endif } } return status; } static enum nss_status ng_chase(const char *dn, ldap_initgroups_args_t * lia) { struct ldap_args a; enum nss_status stat; struct ent_context *ctx=NULL; const char *gidnumber_attrs[2]; int erange; if (lia->depth > LDAP_NSS_MAXGR_DEPTH) return NSS_STATUS_NOTFOUND; if (_nss_ldap_namelist_find (lia->known_groups, dn)) return NSS_STATUS_NOTFOUND; gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber); gidnumber_attrs[1] = NULL; LA_INIT (a); LA_STRING (a) = dn; LA_TYPE (a) = LA_TYPE_STRING; if (_nss_ldap_ent_context_init_locked (&ctx) == NULL) { return NSS_STATUS_UNAVAIL; } stat = _nss_ldap_getent_ex (&a, &ctx, lia, NULL, 0, &erange, _nss_ldap_filt_getgroupsbydn, LM_GROUP, gidnumber_attrs, do_parse_initgroups_nested); if (stat == NSS_STATUS_SUCCESS) { stat = _nss_ldap_namelist_push (&lia->known_groups, dn); } _nss_ldap_ent_context_release (ctx); free (ctx); return stat; } static enum nss_status ng_chase_backlink(const char ** membersOf, ldap_initgroups_args_t * lia) { struct ldap_args a; enum nss_status stat; struct ent_context *ctx=NULL; const char *gidnumber_attrs[3]; const char **memberP; const char **filteredMembersOf; /* remove already traversed groups */ size_t memberCount, i; int erange; if (lia->depth > LDAP_NSS_MAXGR_DEPTH) return NSS_STATUS_NOTFOUND; for (memberCount = 0; membersOf[memberCount] != NULL; memberCount++) ; /* Build a list of membersOf values without any already traversed groups */ filteredMembersOf = (const char **) malloc(sizeof(char *) * (memberCount + 1)); if (filteredMembersOf == NULL) { return NSS_STATUS_TRYAGAIN; } memberP = filteredMembersOf; for (i = 0; i < memberCount; i++) { if (_nss_ldap_namelist_find (lia->known_groups, membersOf[i])) continue; *memberP = membersOf[i]; memberP++; } *memberP = NULL; if (filteredMembersOf[0] == NULL) { free (filteredMembersOf); return NSS_STATUS_NOTFOUND; } gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber); gidnumber_attrs[1] = ATM (LM_GROUP, memberOf); gidnumber_attrs[2] = NULL; LA_INIT (a); LA_STRING_LIST (a) = filteredMembersOf; LA_TYPE (a) = LA_TYPE_STRING_LIST_OR; if (_nss_ldap_ent_context_init_locked (&ctx) == NULL) { free (filteredMembersOf); return NSS_STATUS_UNAVAIL; } stat = _nss_ldap_getent_ex (&a, &ctx, lia, NULL, 0, &erange, "(distinguishedName=%s)", LM_GROUP, gidnumber_attrs, do_parse_initgroups_nested); if (stat == NSS_STATUS_SUCCESS) { enum nss_status stat2; for (memberP = filteredMembersOf; *memberP != NULL; memberP++) { stat2 = _nss_ldap_namelist_push (&lia->known_groups, *memberP); if (stat2 != NSS_STATUS_SUCCESS) { stat = stat2; break; } } } free (filteredMembersOf); _nss_ldap_ent_context_release (ctx); free (ctx); return stat; } static int _nss_ldap_test_initgroups_ignoreuser(const char *user) { char **p; if (nslcd_cfg == NULL) return 0; if (nslcd_cfg->ldc_initgroups_ignoreusers == NULL) return 0; for (p = nslcd_cfg->ldc_initgroups_ignoreusers; *p != NULL; p++) { if (strcmp (*p, user) == 0) return 1; } return 0; } static enum nss_status group_bymember(const char *user, long int *start, long int *size, long int limit, int *errnop) { ldap_initgroups_args_t lia; int erange = 0; char *userdn = NULL; LDAPMessage *res, *e; static const char *no_attrs[] = { NULL }; const char *filter; struct ldap_args a; enum nss_status stat; struct ent_context *ctx=NULL; const char *gidnumber_attrs[3]; enum ldap_map_selector map = LM_GROUP; LA_INIT (a); LA_STRING (a) = user; LA_TYPE (a) = LA_TYPE_STRING; log_log(LOG_DEBUG,"==> group_bymember (user=%s)", LA_STRING (a) ); lia.depth = 0; lia.known_groups = NULL; _nss_ldap_enter (); /* initialize schema */ stat = _nss_ldap_init (); if (stat != NSS_STATUS_SUCCESS) { log_log(LOG_DEBUG,"<== group_bymember (init failed)"); _nss_ldap_leave (); return stat; } if (_nss_ldap_test_initgroups_ignoreuser (LA_STRING (a))) { log_log(LOG_DEBUG,"<== group_bymember (user ignored)"); _nss_ldap_leave (); return NSS_STATUS_NOTFOUND; } lia.backlink = _nss_ldap_test_config_flag (NSS_LDAP_FLAGS_INITGROUPS_BACKLINK); if (lia.backlink != 0) { filter = _nss_ldap_filt_getpwnam_groupsbymember; LA_STRING2 (a) = LA_STRING (a); LA_TYPE (a) = LA_TYPE_STRING_AND_STRING; gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber); gidnumber_attrs[1] = ATM (LM_GROUP, memberOf); gidnumber_attrs[2] = NULL; map = LM_PASSWD; } else { if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS)) { /* lookup the user's DN. */ stat = _nss_ldap_search_s (&a, _nss_ldap_filt_getpwnam, LM_PASSWD, no_attrs, 1, &res); if (stat == NSS_STATUS_SUCCESS) { e = _nss_ldap_first_entry (res); if (e != NULL) { userdn = _nss_ldap_get_dn (e); } ldap_msgfree (res); } } else { userdn = NULL; } if (userdn != NULL) { LA_STRING2 (a) = userdn; LA_TYPE (a) = LA_TYPE_STRING_AND_STRING; filter = _nss_ldap_filt_getgroupsbymemberanddn; } else { filter = _nss_ldap_filt_getgroupsbymember; } gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber); gidnumber_attrs[1] = NULL; } if (_nss_ldap_ent_context_init_locked(&ctx)==NULL) { log_log(LOG_DEBUG,"<== group_bymember (ent_context_init failed)"); _nss_ldap_leave (); return NSS_STATUS_UNAVAIL; } stat = _nss_ldap_getent_ex (&a, &ctx, (void *) &lia, NULL, 0, errnop, filter, map, gidnumber_attrs, do_parse_initgroups_nested); if (userdn != NULL) ldap_memfree (userdn); _nss_ldap_namelist_destroy (&lia.known_groups); _nss_ldap_ent_context_release (ctx); free (ctx); _nss_ldap_leave (); /* * We return NSS_STATUS_NOTFOUND to force the parser to be called * for as many entries (i.e. groups) as exist, for all * search descriptors. So confusingly this means "success". */ if (stat != NSS_STATUS_SUCCESS && stat != NSS_STATUS_NOTFOUND) { log_log(LOG_DEBUG,"<== group_bymember (not found)"); if (erange) errno = ERANGE; return stat; } log_log(LOG_DEBUG,"<== group_bymember (success)"); return NSS_STATUS_SUCCESS; } /* macros for expanding the NSLCD_GROUP macro */ #define NSLCD_STRING(field) WRITE_STRING(fp,field) #define NSLCD_TYPE(field,type) WRITE_TYPE(fp,field,type) #define NSLCD_STRINGLIST(field) WRITE_STRINGLIST_NULLTERM(fp,field) #define GROUP_NAME result.gr_name #define GROUP_PASSWD result.gr_passwd #define GROUP_GID result.gr_gid #define GROUP_MEMBERS result.gr_mem int nslcd_group_byname(TFILE *fp) { int32_t tmpint32,tmp2int32,tmp3int32; char name[256]; struct ldap_args a; /* these are here for now until we rewrite the LDAP code */ struct group result; char buffer[1024]; int errnop; int retv; /* read request parameters */ READ_STRING_BUF2(fp,name,sizeof(name)); /* log call */ log_log(LOG_DEBUG,"nslcd_group_byname(%s)",name); /* static buffer size check */ if (1024