2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. 2N/A/* String which may need to be removed from beginning of group password */ 2N/A/* AD-specific, used in search filter to resolve group memberships. */ 2N/A/* Group attributes filters */ 2N/A * These filters are used to get all the containing groups (immediate parents) 2N/A * DNs (user's full DN) in just one ldap search request. The reason why 2N/A * the uniqueMember part is repeated is to cover different servers' behavior. 2N/A * Some allow a wild card search to match DNs with optional unique identifier 2N/A * and some would only match DN exactly (i.e., optional unique ID not allowed). 2N/A * These filters are used to get all the containing groups (immediate parents) 2N/A * of a group by searching with member and uniqueMember DNs (user's full DN) 2N/A * in just one ldap search request. The reason why the uniqueMember part is 2N/A * repeated is the same as the above filters. 2N/A * The next two filters are used to retrieve entries from AD. Both cause 2N/A * server side group expansion. The first one asks for all group member 2N/A * entries to be returned in just one search. The second one requests 2N/A * all parent groups (including nested ones) to be returned in one search. 2N/A/* Each reallocation adds _PSEARCH_BUF_BLK more bytes to a packed buffer */ 2N/A * Max. number of recursive calls to go down to find child groups 2N/A * or to go up to find all the parent groups. This limit only 2N/A * affects the users who use the ODSEE or OpenLDAP servers. 2N/A * AD is not affected due to the LDAP_MATCHING_RULE_IN_CHAIN 2N/A * server-side group expansion. 2N/A * The values of the member and uniqueMember attributes are in DN 2N/A * syntax, and specify either user members or group members. If group, 2N/A * then they are nested groups. To evaluate group membership that is 2N/A * defined using the member and/or uniqueMember attributes, nss_ldap 2N/A * needs to do dn2uid searches (by calling __ns_ldap_read_dn) with the 2N/A * member DNs to obtain the names of the user members or the DNs of 2N/A * the nested groups. For nested groups, the dn2uid searches will be 2N/A * done recursively until all members have been resolved to user names 2N/A * or until the maximum level of recursion has been reached. To 2N/A * improve performance, the dn2uid search results need to be cached. 2N/A * nss_ldap will resolve the group membership specified by any or all 2N/A * of the memberUid, member, and uniqueMember attributes. The result 2N/A * will be that a group has membership that is the union of all three 2N/A * with duplicates removed. 2N/A * A dn2uid search with a user DN would return the name of the user. 2N/A * A dn2uid search with a group DN may return a series of user names 2N/A * a series of user DNs (user members of the group), and/or a series 2N/A * of group DNs (group members of the group). 2N/A * The result of dn2uid search is placed in the data section of the 2N/A * packed buffer. See below where the nscd dn2uid cache is described 2N/A * about how the nscd is tapped into to cache the dn2uid search results. 2N/A * The packed result of the dn2uid search has up to four sections: 2N/A * - a structure, _dn2uid_res_t 2N/A * - a series of user names 2N/A * The _dn2uid_res_t structure has the following elements: 2N/A * indicates a user or group entry 2N/A * number of user names that follows this structure 2N/A * Number of DNs that follows the base DN. These DNs 2N/A * are either the DN of a user or that of a nested group. 2N/A * If a DN has the same base DN as that stored in this 2N/A * structure, it will be truncated to have only the non-base 2N/A * DN part, with a ',' added to the end to indicate that it's 2N/A * length of the base DN 2N/A * max. length of member DN. This is used to allocate one shared 2N/A * space big enough to hold the member DNs one at a time. 2N/A * Where in the buffer the base DN starts. The first 2N/A * byte of this structure is offset 0. 2N/A * -- next_byte_offset 2N/A * Where in the buffer to add the next data item. The first 2N/A * byte of this structure is offset 0. 2N/A * Current size of the data area in the packed buffer. This 2N/A * size includes the size of the _dn2uid_res_t structure. 2N/A * are not used, the user name list is created entirely from the 2N/A * values of the memberuid attribute returned in the group 2N/A * search. Otherwise, it could also be from the user name (uid 2N/A * attribute) of the dn2uid search of a user DN. The base DN 2N/A * and the user/group DNs will only be set if there are member 2N/A * or uniqueMember attributes in the search results. 2N/A * So the data layout in the data section of the packed buffer is 2N/A * struct [ "username1" [ "username2 " ...]] ["baseDN"] 2N/A * [ "user or group DN 1" [ "user or group DN 2" ...]] 2N/A * When processing a getGroupsbyMember request, nss_ldap first 2N/A * translates the given member (a user name) into the DN of the 2N/A * user entry. It then does a group search with a filter 2N/A * (|(memberuid=<user name>)((member=<user DN>)(uniqueMember=<user DN>)) 2N/A * and asks for the gidNumber, memberUid, member, uniqueMember, and 2N/A * memberOf attributes. The returned groups are all the groups having 2N/A * this user as a member. The gidNumber of the groups will be added 2N/A * to the gid number list to be returned as the output. The present of 2N/A * the memberOf attribute in a group entry is used as an indication that 2N/A * the group is a member of a nested group, so the DN of the group 2N/A * will be used to do further memberof searches. This will be done 2N/A * recursively until all parent groups are found or the maximum level 2N/A * of recursion is reached. 2N/A * The result of a memberof search is placed in the data section 2N/A * of the packed buffer. The packed result of the search has up to 2N/A * - a structure, _memberof_res_t 2N/A * - a series of gid number and group DN pairs 2N/A * The _memberof_res_t structure has the following elements: 2N/A * number of the containing groups 2N/A * number of group DNs that need a further group search 2N/A * length of the base DN 2N/A * max. length of group DN. This is used to allocate one shared 2N/A * space big enough to hold the group DNs one at a time. 2N/A * indicate a no sorting search should be done next 2N/A * Where in the buffer the base DN starts. The first 2N/A * byte of this structure is offset 0. 2N/A * -- next_byte_offset 2N/A * Where in the buffer to add the next data item. The first 2N/A * byte of this structure is offset 0. 2N/A * Current size of the data area in the packed buffer. This 2N/A * size includes the size of the _memberof_res_t structure. 2N/A * containing group found. The gid umber will always be set but the DN 2N/A * of the group may be an empty string, which means no further group 2N/A * search is necessary. The gid numbers and group DNs are null-terminated 2N/A * strings. The DNs are also truncated if they have the same base DNs 2N/A * as that stored in the _memberof_res_t structure. 2N/A * So the layout of the search result in the data section of the 2N/A * packed buffer is as follows: 2N/A * struct ["baseDN"] [ "gidnumber1" "groupDN1" [ "gidnumber1" "groupDN2" ...]] 2N/A * gr_attrs lists the attributes needed for generating a group(4) entry. 2N/A/* gr_attrs2 lists the group attributes that may need schema mapping. */ 2N/A * gr_attrs3 is for processing the member DN list from a dn2uid lookup. 2N/A * Do not change the order, _G_UNIQUEMEMBER should always be the second one. 2N/A * gr_attrs4 is used for schema mapping a group entry returned 2N/A * from a dn2uid lookup. 2N/A * gr_attrs5 is used when searching groups with both memberuid and DN. 2N/A * The presence of any memberOf attributes indicates whether a group 2N/A * gr_attrs6 is used when searching groups with a member DN. 2N/A * The presence of any memberOf attributes indicates whether 2N/A * a group is a nested one. 2N/A/* pw_attrs is used to translate a user's uid to DN */ 2N/A/* Use this attribute to ask for server type from libsldap. */ 2N/A "__ns_ldap_op_attr_server_type",
2N/A/* nss_ldap's dn2uid cache */ 2N/A/* nss_ldap's memberof cache */ 2N/A * For memberof cache search, the UID tag indicates a search with a uid 2N/A * as the key is being performed. The GROUP_DN tag indicates a group DN 2N/A * as the key. GROUP_DN_NS indicates a group DN key but with no result 2N/A * sorting on the server side. 2N/A * userdata consumed by the TLE_group_member_cb callback function 2N/A * userdata consumed by the TLE_memberof_cb callback function 2N/A * attribute list used by an AD member Transitive Link 2N/A * attribute list used by an AD memberof Transitive Link 2N/A/* Test to see if string 'a' begins with string 'b'. */ 2N/A * See if string 'a' ends with string 'b', and is longer. 2N/A * Return the pointer to where in 'a' string 'b' begins. 2N/A/* Test to see if a group is a nested group. */ 2N/A * Use the memberOf attribute (or for DSEE, isMemberOf) to 2N/A * determine if this group is a nested group. If present, 2N/A/* Loop and compare to see if an item is in a counted list. */ 2N/A * The following code enables and uses/fills the dn2uid cache. 2N/A * The dn2uid cache uses the caching features of nscd if nscd 2N/A * The nss backend taps into nscd cache using 2 APIs: 2N/A * _nss_cache_create - to init a backend cache 2N/A * _nss_cache_get - to search the cache. This API requires 2 callbacks 2N/A * getkey - performs the nss_packed_getkey operation 2N/A * psearch- performs the nss_psearch operation 2N/A * The expectation is that get receives a properly formed packed buffer 2N/A * and processes the specific search request, packing the results into 2N/A * the buffer. psearch performs the actual lookup, while getkey returns 2N/A * the necessary key information for psearch and for cache test operations. 2N/A * So that the system does not fail if nscd is disabled, the real APIs 2N/A * are provided as weak symbols to APIs that return error on create 2N/A * The format of the result packing is project private and subject to 2N/A * change. See the comments on the structures, _dn2uid_res_t and 2N/A * _memberof_res_t, above for the layout of the search results. 2N/A * Local _nss_cache_get performs the actual lookup if not running in the 2N/A /* fake _nss_cache_get just calls psearch (no caching) */ 2N/A * Setup the dn2uid cache if this is the first time call. 2N/A /* Return if the dn2uid cache setup has been done of tried. */ 2N/A /* Return if just done of tried. */ 2N/A /* Not running in nscd ? */ 2N/A * Setup the memberof cache if this is the first time call. 2N/A /* Return if the memberof cache setup has been done of tried. */ 2N/A /* Return if just done of tried. */ 2N/A /* Not running in nscd ? */ 2N/A/* Find the search key from the packed buffer header. */ 2N/A/* Add a member uid to the member list. */ 2N/A /* Add member to the list */ 2N/A /* It is fine if member is already in the list */ 2N/A * Add a dn2uid data string 'str' to the data area in the packed buffer, 2N/A * '*bufpp', expand the packed buffer if necessary. 2N/A /* expand the buffer if not enough room to add the string */ 2N/A /* adjust pointers */ 2N/A /* Cast to void * eliminates lint warning */ 2N/A /* adjust buffer length */ 2N/A/* Generate an attributed mapped attr list to be used by a dn2uid lookup. */ 2N/A/* Perform schema mapping on a group entry returned from a dn2uid lookup. */ 2N/A /* Make sure it's a group entry. */ 2N/A /* not a posixGroup entry, return NSS_NOTFOUND */ 2N/A * Find the memberUid, member, and uniqueMember attributes, 2N/A * that could be schema mapped to use a different name, to 2N/A * change the name back. gr_attrs4[] contains "memberUid", 2N/A * "member", and "uniqueMember". gr_attrs2[] contains the 2N/A * name of the attributes that may be schema mapped. 2N/A * in_attrs[] contains the corresponding mapped gr_attrs2[] 2N/A * names that may be seen in the result group entry. 2N/A * A value for the uniqueMember attribute is a DN followed 2N/A * by an optional hash (#) and uniqueIdentifier. 2N/A * For example, uniqueMember: cn=aaa,dc=bbb,dc=ccc #1234 2N/A * This function remove the optional # and uniqueIdentifier. 2N/A /* invalid DN if no '=' and '#' should be after all RDNs */ 2N/A * Perform a dn2uid lookup using the input packed buffer. 2N/A * A dn2uid lookup does an LDAP search with the input 2N/A * user or group DN and returns the dn2uid result data 2N/A * in the data area of the packed buffer. See the comments 2N/A * above about the specific of a dn2uid lookup and the layout 2N/A * of the dn2uid result data. 2N/A * Get the DN entry from the server. Specify 'passwd' as the service 2N/A * first, in case this DN is that of a posixAccount (user) entry, so 2N/A * that schema mapping for the passwd service will be done by libsldap. 2N/A * Also need to map the requested group attributes here, in case this DN 2N/A * points to a posixGroup (group) entry, in which case, libsldap won't 2N/A * do the schema mapping because the service specified is not 'group'. 2N/A * We do this extra schema mapping because we want to try to get 2N/A * the user or group entry in just one call to __ns_ldap_read_dn(). 2N/A * There is schema mapping for the group database, so map the 2N/A * group attributes so that the ldap server knows which attrs 2N/A /* posixAccount or posixGroup dn ? */ 2N/A * Not a posixAccount entry, should be a posixGroup one. 2N/A * Perform schema mapping as it's not done by libsldap. 2N/A /* pack up and return results */ 2N/A /* found a posixAccount (user) dn, pack up the user name */ 2N/A /* found a posixGroup dn, pack up the users and dns */ 2N/A /* for attrs: _G_MEMBER & _G_UNIQUEMEMBER */ 2N/A /* Process member (DN) */ 2N/A * get the configured base DN so that it's not repeated 2N/A * in every member DN saved 2N/A /* point to start of base DN */ 2N/A /* use non-basedn part if possible */ 2N/A * If uniqueMember, drop the optional uniqueIdentifier. 2N/A * remember max. DN length seen so far 2N/A /* if dn ends with basedn */ 2N/A * This last ',' denotes basedn. 2N/A /* Return NSS_NOTFOUND if no new data added. */ 2N/A * No group member found. Returning NSS_NOTFOUND 2N/A * makes it a negative nscd cache if running in 2N/A/* Set up a packed buffer and perform a cache search. */ 2N/A /* space needed for cache name: cache_name_len_round_up */ 2N/A /* space needed for tag and key: keylen_round_up */ 2N/A * Space needed for the packed buffer header: 2N/A * sizeof (nss_pheader_t) + sizeof (nss_dbd_t) + 2N/A * cache_name_len_round_up + keylen_round_up. 2N/A * Total space needed: packed buffer header size + 2N/A * requested data size (start_size). See code below 2N/A * for the consturction of the packed buffer header. 2N/A /* Populate the packed buffer with a request */ 2N/A /* perform the cache search */ 2N/A * Given a group or member (user) DN, search the nscd group or passwd cache 2N/A * to find a group or passwd entry with a matching DN. 2N/A * Check to see if the member or group is already in nscd cache. 2N/A * Search key is the rdn value. 2N/A /* skip rdn attr type and use the attr value as the search key */ 2N/A /* try search user first */ 2N/A * If user found in nscd cache and with the same DN, 2N/A * add it to the member list. 2N/A * The optional DN string is right after the regular database 2N/A * result string. pbuf->data_len indicates the sum of these 2N/A * two strings. If it's not larger than the length of the 2N/A * first string, then there is no optional DN. 2N/A /* skip server type */ 2N/A /* next try searching group */ 2N/A * If group found in nscd cache and with the same DN, 2N/A * add all members of the group to the member list. 2N/A * The optional DN string is right after the regular database 2N/A * result string. pbuf->data_len indicates the sum of these 2N/A * two strings. If it's not larger than the length of the 2N/A * first string, then there is no optional DN. 2N/A /* skip server type */ 2N/A * Given a member DN, find the corresponding user, or if the DN is that 2N/A * of a group, find all the members recursively until the maximum level 2N/A * of recursion is reached. The users or groups could be from the nscd 2N/A * cache or from the ldap servers. 2N/A * If the depth of recursion reaches DN2UID_MAX_RECURSIVE_CALL 2N/A * then stop and return NSS_SUCCESS. 2N/A /* create the dn2uid nscd backend cache if not done yet */ 2N/A * For loop detection, check to see if dn has already been 2N/A * processed by adding it to the dnlist. It not able to add, 2N/A * then it has been processed or error occurred, ignore it. 2N/A * If running in nscd, check to see if member or 2N/A * group is already in nscd cache. 2N/A * Check to see if dn has already been searched and in nscd's 2N/A * dn2uid cache. If not running in nscd, then the local 2N/A * _nss_cache_get will be called to search the DN directly. 2N/A /* a single user id; add it to the member list */ 2N/A }
else {
/* a group entry */ 2N/A /* add all users to the member list */ 2N/A * If base DN is present, set pointer to it and 2N/A * go pass it to process the next set of data, 2N/A * If there are group DNs, get all members recursively 2N/A * by calling _nss_ldap_proc_memberDN again. 2N/A * Restore member DN if it was truncated to save 2N/A * Get a work buffer from the stack 2N/A * that can be reused. 2N/A /* drop the last ',' */ 2N/A /* If no new data added, return NSS_NOTFOUND. */ 2N/A * TLE_group_member_cb is a callback function callable by libsldap 2N/A * to process each one of the member entres returned by an AD 2N/A * Transitive Link Expansion search that request all members of 2N/A /* posixAccount or posixGroup dn ? */ 2N/A /* Not an posixAccount entry, skip. */ 2N/A /* No user name, just ignore the entry. */ 2N/A * Perform an AD Transitive Link Expansion search to get all members 2N/A * of a group entry. All member entries including those of the child 2N/A * nested groups will be returned in one search. The callback function 2N/A * TLE_group_member_cb is used to process each one of the entries. 2N/A /* Escape any special characters in the dn first. */ 2N/A * libsldap returns NS_LDAP_NOTFOUND if 2N/A * all result entries were consumed by 2N/A * the callback function. 2N/A * _nss_ldap_memberlist collects all members of a group 2N/A * (recursively if necessary) processing all: 2N/A * _G_MEMBERUID, G_MEMBER, G_UNIQUEMEMBER 2N/A * starting with the current results. Follow on 2N/A * dn2uid results may be cached. 2N/A /* process member uid, attr: _G_MEMBERUID */ 2N/A /* Determine which type of server the entry is from. */ 2N/A * If from AD, do a Transitive Link Expansion search 2N/A * to get all member entries with just one search. 2N/A /* process member (or group) DN, attrs: _G_MEMBER & _G_UNIQUEMEMBER */ 2N/A /* Process member (DN) */ 2N/A * If uniqueMember, drop the optional 2N/A * No group member is not an error, 2N/A * as groups having no users are allowed. 2N/A * _nss_ldap_group2str is the data marshaling method for the group getXbyY 2N/A * (e.g., getgrnam(), getgrgid(), getgrent()) backend processes. This method 2N/A * is called after a successful ldap search has been performed. This method 2N/A * will parse the ldap search values into the file format. 2N/A * adm::4:root,adm,daemon 2N/A /* group password could be NULL, replace it with "" */ 2N/A * Preen "{crypt}" if necessary. 2N/A * If the password does not include the {crypt} prefix 2N/A * then the password may be plain text. And thus 2N/A * perhaps crypt(3c) should be used to encrypt it. 2N/A * Currently the password is copied verbatim. 2N/A /* Rescursive member list processing */ 2N/A * Copy all the members to the output buffer. 2N/A * If no members, nss_ldap_list_dump will do 2N/A /* The front end marshaller doesn't need the trailing nulls */ 2N/A * Save the entry DN as an optional data, if 2N/A * dn to uid caching is being performed and 2N/A * not processing enumeration results and 2N/A * there's enough room in the buffer. 2N/A * Format is: (group data followed by optional DN data) 2N/A * <group data> + '\0' + '#dn:<server_type>:' + <DN> + '\0' 2N/A /* Terminate the primary result. */ 2N/A * getbynam gets a group entry by name. This function constructs an ldap 2N/A * search filter using the name invocation parameter and the getgrnam search 2N/A * filter defined. Once the filter is constructed, we searche for a matching 2N/A * entry and marshal the data results into struct group for the frontend 2N/A * process. The function _nss_ldap_group2ent performs the data marshaling. 2N/A * getbygid gets a group entry by number. This function constructs an ldap 2N/A * search filter using the name invocation parameter and the getgrgid search 2N/A * filter defined. Once the filter is constructed, we searche for a matching 2N/A * entry and marshal the data results into struct group for the frontend 2N/A * process. The function _nss_ldap_group2ent performs the data marshaling. 2N/A * setup_buf_memberof_res sets up a control block for doing 2N/A * memberof searches. The control block locates at the 2N/A * beginning of the result data area in the packed buffer. 2N/A /* get the configured baseDN */ 2N/A * Realloc the packed buffer for a memberof search if not 2N/A * enough space left. 2N/A * Buffer pointer may be changed, make sure all related 2N/A * data in the packed buffer are updated. 2N/A * pack_group_gid_dn adds the gid and DN of a group to the 2N/A * result area. If not a nested group, its DN will be stored 2N/A * as an empty string, as an indication that parent group 2N/A * searching needs not be done. 2N/A /* store only non-basedn part if possible */ 2N/A * remember max. DN length seen so far 2N/A /* if entry_dn ends with basedn */ 2N/A /* This last ',' denotes basedn. */ 2N/A /* length including 2 '\0' */ 2N/A * TLE_memberof_cb is a callback function callable by libsldap 2N/A * to process each one of the group entries returned by an AD 2N/A * memberof Transitive Link Expansion search. 2N/A * key_groupDN_psearch is a memberof psearch function that finds all 2N/A * the groups that the group identified by dn is a member of. This 2N/A * is used to resolve nested group membership. 2N/A /* Escape any special characters in the DN first. */ 2N/A * Do a search to get all the group entries which have the 2N/A * group DN as one of the values of its member or uniqueMember 2N/A * Use __ns_ldap_list() if not able to get VLV results from 2N/A * Set up the group result control block which is at the start 2N/A * Store gidnumber and entry DN from each result entry in the 2N/A /* Return NSS_NOTFOUND if no new data added. */ 2N/A * key_uid_psearch is a memberof psearch function that finds all 2N/A * the groups that the user identified by key is a member of. 2N/A * Try searching the user in nscd's passwd cache, in case 2N/A * user DN is available there. 2N/A * If found in nscd cache, get the user's DN and server type 2N/A /* check for optional data's DN tag */ 2N/A /* first get server type string */ 2N/A /* then set server type */ 2N/A /* user DN follows server type */ 2N/A * If no user DN found in cache, call __ns_ldap_list_ext to get it. 2N/A /* Determine which type of server the entry is from. */ 2N/A * Set up the group result control block which is at the start 2N/A /* Escape any special characters in the user_dn first. */ 2N/A * If the ldap server is an AD, do a Transitive Link Expansion 2N/A * search to get all parent groups in one search. 2N/A * Use a callback function to process each result entry. 2N/A * userdata is the callback control block. 2N/A * Done if no error and have result data. 2N/A * libsldap returns NS_LDAP_NOTFOUND if 2N/A * all result entries were consumed by 2N/A * the callback function. 2N/A * Otherwise clean up incomplete result data in the buffer 2N/A * by resetting the result control block. 2N/A * Not AD, or the Transitive Link Expansion search didn't work, 2N/A * do a search to get all the group entries which have the 2N/A * key as a memberuid or user_dn as one of the values of its 2N/A * member or uniqueMember attribute. 2N/A * If the ldap server is an openLDAP, don't sort the results 2N/A * as there's no order rule for most attributes. 2N/A * Store gidnumber and entry DN from each result entry in the 2N/A * Check to see if this group is found by a matched username. 2N/A * Not matched ? Most likely, unamename not listed as 2N/A * one of the memberUid attribute values, skip. 2N/A /* Return NSS_NOTFOUND if no new data added. */ 2N/A * _nss_ldap_memberof_psearch is the top level psearch function for 2N/A * memberof searches. The search key stored in the packed buffer 2N/A * header is tagged to indicate whether the search key is a member uid 2N/A * or group DN. If uid, key_uid_psearch will be called. Otherwise, 2N/A * key_groupDN_psearch will be called. 2N/A /* Searching with a member uid or group DN ? */ 2N/A * get_parent_gids find all groups, including nested ones, that a user 2N/A * is a member of and write the gid number of these groups in the output 2N/A * gid array. It may call itself recursively when dealing with nested 2N/A * group. The nest level is limited by MEMBEROF_MAX_RECURSIVE_CALL. 2N/A * If the depth of recursion reaches MEMBEROF_MAX_RECURSIVE_CALL 2N/A * then stop and return NSS_SUCCESS. 2N/A /* create the memberof nscd backend cache if not done yet */ 2N/A * For loop detection, check to see if key has already been 2N/A * processed by adding it to the grlist. If not able to add, 2N/A * then it has been processed or error occurred, ignore it. 2N/A * Check to see if memberof result available in nscd's memberof cache. 2N/A * If not, get it from the LDAP server. 2N/A /* add gids to the output gid array */ 2N/A /* Skip DN of the group entry, it will be processed later. */ 2N/A /* no need to add if already in the output */ 2N/A /* already exists */ 2N/A /* ignore duplicate gid */ 2N/A * Done if no group DNs to process, i.e., no nested groups. 2N/A /* group DN always follows the gid string, so move pass gid */ 2N/A /* if NULL group DN, not a nested group, nothing to do */ 2N/A /* Restore group DN if it was truncated to save space. */ 2N/A * Get a work buffer from the stack 2N/A * that can be reused. 2N/A /* drop the last ',' */ 2N/A * basedn is the first string after the 2N/A * If server is an openLDAP, do a no result sorting 2N/A /* move pass group DN */ 2N/A * getbymember returns all groups a user is defined in. This function 2N/A * uses different architectural procedures than the other group backend 2N/A * system calls because it's a private interface. This function constructs 2N/A * an ldap search filter using the name invocation parameter. Once the 2N/A * filter is constructed, we search for all matching groups counting 2N/A * and storing each group name, gid, etc. Data marshaling is used for 2N/A * group processing. The function _nss_ldap_group2ent() performs the 2N/A * (const char *)argp->username; (size_t)strlen(argp->username); 2N/A * (gid_t)argp->gid_array; (int)argp->maxgids; 2N/A * (int)argp->numgids; 2N/A * Return NSS_SUCCESS only if array is full.