mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
libc/grp: add getgrouplist()
Add getgrouplist() to the C library. It scans the group database for a user's supplementary groups and always reports the primary group first. Without CONFIG_LIBC_GROUP_FILE only the primary group is returned, since no membership information is available. The group file is read through lib_get_tempbuffer()/lib_put_tempbuffer() to avoid a heap allocation on every lookup. Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
parent
1685e8ff7b
commit
a9b72ed796
6 changed files with 223 additions and 2 deletions
|
|
@ -72,6 +72,8 @@ int getgrgid_r(gid_t gid, FAR struct group *grp,
|
|||
FAR char *buf, size_t buflen,
|
||||
FAR struct group **result);
|
||||
int initgroups(FAR const char *user, gid_t group);
|
||||
int getgrouplist(FAR const char *user, gid_t group, FAR gid_t *groups,
|
||||
FAR int *ngroups);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#
|
||||
# ##############################################################################
|
||||
set(SRCS lib_getgrgid.c lib_getgrgidr.c lib_getgrnam.c lib_getgrnamr.c
|
||||
lib_initgroups.c)
|
||||
lib_initgroups.c lib_getgrouplist.c)
|
||||
|
||||
if(CONFIG_LIBC_GROUP_FILE)
|
||||
list(APPEND SRCS lib_find_grpfile.c lib_grp_globals.c)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
# Add the grp C files to the build
|
||||
|
||||
CSRCS += lib_getgrgid.c lib_getgrgidr.c lib_getgrnam.c lib_getgrnamr.c
|
||||
CSRCS += lib_initgroups.c
|
||||
CSRCS += lib_initgroups.c lib_getgrouplist.c
|
||||
|
||||
ifeq ($(CONFIG_LIBC_GROUP_FILE),y)
|
||||
CSRCS += lib_find_grpfile.c lib_grp_globals.c
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@
|
|||
#include <string.h>
|
||||
#include <grp.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/lib/lib.h>
|
||||
|
||||
#include "grp/lib_grp.h"
|
||||
|
||||
|
|
@ -41,6 +44,19 @@
|
|||
typedef CODE int (grp_foreach_match_t)(FAR const struct group *entry,
|
||||
uintptr_t arg);
|
||||
|
||||
/* Context used by grp_match_user() to accumulate the group IDs of all the
|
||||
* groups that a given user is a member of.
|
||||
*/
|
||||
|
||||
struct grp_user_s
|
||||
{
|
||||
FAR const char *user; /* User name to search for */
|
||||
gid_t group; /* Primary group to skip (avoid duplicate) */
|
||||
FAR gid_t *grouplist; /* Output array of group IDs */
|
||||
int maxgroups; /* Number of slots in grouplist */
|
||||
int count; /* Number of group IDs found so far */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
|
@ -93,6 +109,61 @@ static int grp_match_gid(FAR const struct group *entry, uintptr_t arg)
|
|||
return match_gid == entry->gr_gid ? 1 : 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: grp_match_user
|
||||
*
|
||||
* Description:
|
||||
* Called for each record in the group file. If the user (passed via the
|
||||
* context in arg) is a member of the group, its group ID is appended to
|
||||
* the caller's output array. Always returns 0 so that every record in
|
||||
* the file is visited and the total number of matching groups is counted.
|
||||
*
|
||||
* Input Parameters:
|
||||
* entry - The parsed group file record
|
||||
* arg - A pointer to the grp_user_s search context
|
||||
*
|
||||
* Returned Value:
|
||||
* = 0 : Always, so that iteration continues to the end of the file.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int grp_match_user(FAR const struct group *entry, uintptr_t arg)
|
||||
{
|
||||
FAR struct grp_user_s *ctx = (FAR struct grp_user_s *)arg;
|
||||
FAR char **member;
|
||||
|
||||
/* The primary group has already been accounted for by the caller. Skip
|
||||
* it here to avoid reporting it twice.
|
||||
*/
|
||||
|
||||
if (entry->gr_gid == ctx->group)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check whether the user is listed as a member of this group. */
|
||||
|
||||
for (member = entry->gr_mem; *member != NULL; member++)
|
||||
{
|
||||
if (strcmp(*member, ctx->user) == 0)
|
||||
{
|
||||
/* Append the group ID if there is room in the output array. Keep
|
||||
* counting regardless so the caller learns the required size.
|
||||
*/
|
||||
|
||||
if (ctx->count < ctx->maxgroups)
|
||||
{
|
||||
ctx->grouplist[ctx->count] = entry->gr_gid;
|
||||
}
|
||||
|
||||
ctx->count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: grp_foreach
|
||||
*
|
||||
|
|
@ -337,3 +408,54 @@ int grp_findby_gid(gid_t gid, FAR struct group *entry, FAR char *buffer,
|
|||
|
||||
return grp_foreach(grp_match_gid, (uintptr_t)gid, entry, buffer, buflen);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: grp_findby_user
|
||||
*
|
||||
* Description:
|
||||
* Scan the group file and collect the group IDs of all groups that have
|
||||
* 'user' as a member, excluding the primary group 'group'.
|
||||
*
|
||||
* Input Parameters:
|
||||
* user - The user name to search for
|
||||
* group - The primary group ID to exclude from the search
|
||||
* grouplist - Location to return the matching group IDs
|
||||
* maxgroups - The number of slots available in grouplist
|
||||
* count - On input, the number of group IDs already stored in
|
||||
* grouplist. On output, the total number of group IDs found
|
||||
* (which may exceed maxgroups).
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success. A negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int grp_findby_user(FAR const char *user, gid_t group,
|
||||
FAR gid_t *grouplist, int maxgroups, FAR int *count)
|
||||
{
|
||||
struct grp_user_s ctx;
|
||||
struct group entry;
|
||||
FAR char *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = lib_get_tempbuffer(GRPBUF_RESERVE_SIZE);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctx.user = user;
|
||||
ctx.group = group;
|
||||
ctx.grouplist = grouplist;
|
||||
ctx.maxgroups = maxgroups;
|
||||
ctx.count = *count;
|
||||
|
||||
ret = grp_foreach(grp_match_user, (uintptr_t)&ctx, &entry, buffer,
|
||||
GRPBUF_RESERVE_SIZE);
|
||||
|
||||
*count = ctx.count;
|
||||
lib_put_tempbuffer(buffer);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
|
|
|||
95
libs/libc/grp/lib_getgrouplist.c
Normal file
95
libs/libc/grp/lib_getgrouplist.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/****************************************************************************
|
||||
* libs/libc/grp/lib_getgrouplist.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <grp.h>
|
||||
|
||||
#include "grp/lib_grp.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: getgrouplist
|
||||
*
|
||||
* Description:
|
||||
* The getgrouplist() function scans the group database to obtain the list
|
||||
* of groups that 'user' belongs to. The group 'group' (typically the
|
||||
* primary group ID from the password database) is always included in the
|
||||
* returned list and is stored as the first element.
|
||||
*
|
||||
* Input Parameters:
|
||||
* user - The user name whose group membership is queried.
|
||||
* group - An additional group ID (the primary group) to include.
|
||||
* groups - Location to return the list of group IDs.
|
||||
* ngroups - On input, the number of slots available in groups. On output,
|
||||
* the actual number of group IDs found.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the number of group IDs found is returned. If the number of
|
||||
* groups exceeds the available space, -1 is returned and ngroups is set to
|
||||
* the number of group IDs that would have been returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int getgrouplist(FAR const char *user, gid_t group, FAR gid_t *groups,
|
||||
FAR int *ngroups)
|
||||
{
|
||||
int maxgroups = *ngroups;
|
||||
int count;
|
||||
|
||||
/* The primary group is always reported first. */
|
||||
|
||||
if (maxgroups > 0)
|
||||
{
|
||||
groups[0] = group;
|
||||
}
|
||||
|
||||
count = 1;
|
||||
|
||||
#ifdef CONFIG_LIBC_GROUP_FILE
|
||||
/* Scan the group file for any supplementary groups that 'user' belongs to
|
||||
* and append their group IDs to the list.
|
||||
*/
|
||||
|
||||
grp_findby_user(user, group, groups, maxgroups, &count);
|
||||
#else
|
||||
/* Without a group file there is no membership information, so only the
|
||||
* primary group is reported.
|
||||
*/
|
||||
|
||||
UNUSED(user);
|
||||
#endif
|
||||
|
||||
/* If the caller's buffer was too small, report the required size and
|
||||
* return failure. Otherwise, return the number of group IDs stored.
|
||||
*/
|
||||
|
||||
*ngroups = count;
|
||||
return count > maxgroups ? -1 : count;
|
||||
}
|
||||
|
|
@ -83,6 +83,8 @@ int grp_findby_name(FAR const char *gname, FAR struct group *entry,
|
|||
FAR char *buffer, size_t buflen);
|
||||
int grp_findby_gid(gid_t gid, FAR struct group *entry, FAR char *buffer,
|
||||
size_t buflen);
|
||||
int grp_findby_user(FAR const char *user, gid_t group,
|
||||
FAR gid_t *grouplist, int maxgroups, FAR int *count);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue