C `initgroups`如何调用`setgroups`来初始化用户的补充组ID列表?
来自APUE setgroups函数通常从initgroups函数调用, 通过函数getgrent读取整个组文件, setgrent和endgrent,这是我们前面描述并确定的 用户名的组成员身份。然后它调用setgroups来 初始化用户的补充组ID列表 initgroups可以将用户名作为参数,而setgroups不将用户名作为参数。那么initgroups如何调用setgroups来初始化任意用户的补充组ID列表呢 谢谢。setgroups在当前进程上运行,而不是用户。initgroups获取用户名作为参数,查找用户的组,然后将该组列表传递给setgroups以修改当前进程的补充组列表 这通常在登录时完成,用户名是您登录时使用的名称。登录进程设置其组列表,然后执行登录shell。组列表由登录会话中的所有其他进程继承。当Barmar回答上述问题时,我认为深入了解一下细节可能会有所帮助 那么initgroups如何调用setgroups来初始化任意用户的补充组ID列表呢 initgroups使用或类似的内部工具扫描组数据库,以构建要使用setgroups设置的补充组列表 换句话说,setgroups是操作当前进程的补充组ID的接口。initgroups是一个helper函数,它扫描组数据库以构建指定用户所属的所有组ID的列表,并调用setgroups将该组作为补充组ID安装 以下是initgroups的一个示例实现: gidarray_free、gidarray_add、gidarray_size和gidarray_ptr是上面函数下面列出的帮助函数,用于管理组ID数组 实际上,当特权根进程放弃特权并切换到特定用户的标识时,它会设置中指定的用户和组ID,以及中指定的补充组ID。实际上,这样的函数类似于C `initgroups`如何调用`setgroups`来初始化用户的补充组ID列表?,c,linux,usergroups,C,Linux,Usergroups,来自APUE setgroups函数通常从initgroups函数调用, 通过函数getgrent读取整个组文件, setgrent和endgrent,这是我们前面描述并确定的 用户名的组成员身份。然后它调用setgroups来 初始化用户的补充组ID列表 initgroups可以将用户名作为参数,而setgroups不将用户名作为参数。那么initgroups如何调用setgroups来初始化任意用户的补充组ID列表呢 谢谢。setgroups在当前进程上运行,而不是用户。initgroups
int drop_privileges(const char *username)
{
struct passwd *pw;
/* Find out the user and group ID. */
pw = getpwnam(username);
if (!pw) {
errno = ENOENT; /* For "no such user" */
return -1;
}
/* Initialize supplementary groups. */
if (initgroups(username, pw->pw_gid) == -1)
return -1;
/* Set real, effective, and saved group ID. */
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
return -1;
/* Omitted: Dropping Linux capabilities. */
/* Drop privileges by setting real, effective, and saved user ID. */
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
return -1;
/* Now this process has the identity and thus privileges
of user 'username', and no more. */
return 0;
}
删除权限时还需要考虑其他相关细节,特别是,文件和设备的访问检查通常只在打开时进行,因此泄漏特权打开的文件是一个问题,但以上只是其中用户和组标识部分的工作原理的粗略说明
请注意,您可以使用Coreutils的实用程序部分,因此应在所有系统上安装该部分,以检查当前进程的标识。例如,id-un显示与当前用户id匹配的用户名,id-gn显示与当前组id匹配的组名,id-gn列出与补充组id匹配的组名
同样,您可以使用作为C库一部分安装的实用程序来检查用户和密码数据库:getent passwd显示用户数据库的公共字段,getent passwd username显示用户数据库中用户“username”的公共字段,getent group显示组数据库的公共字段,getent group groupname显示组数据库中组“groupname”的公共字段。它在当前进程上运行,而不是在用户上运行。
#include <grp.h> /* on Linux and Solaris */
int initgroups(const char *username, gid_t basegid);
int initgroups(const char *name, gid_t group)
{
gidarray gids = GIDARRAY_INIT;
struct group *gr;
size_t i;
/* Initialize the gids list to the specified group. */
if (gidarray_add(&gids, group)) {
errno = ENOMEM;
return -1;
}
/* Loop through the group database. */
setgrent();
while (1) {
errno = 0;
gr = getgrent();
if (!gr) {
/* End of groups, or an error? */
if (errno) {
const int saved_errno = errno;
gidarray_free(&gids);
endgrent();
errno = saved_errno;
return -1;
}
/* No error, just end of groups. */
break;
}
/* Is there is no member list, this group is not interesting. */
if (!gr->gr_mem)
continue;
/* Check if the user is listed in this group member list. */
for (i = 0; gr->gr_mem[i] != NULL; i++) {
if (!strcmp(gr->gr_mem[i], name)) {
/* Yes; add to list, break out of this for loop. */
if (gidarray_add(&gids, gr->gr_gid)) {
gidarray_free(&gids);
endgrent();
errno = ENOMEM;
return -1;
}
break;
}
}
}
endgrent();
/* Set the supplementary group list. */
if (setgroups(gidarray_size(&gids), gidarray_ptr(&gids)) == -1) {
const int saved_errno = errno;
gidarray_free(&gids);
errno = saved_errno;
return -1;
}
gidarray_free(&gids);
return 0;
}
typedef struct {
size_t max;
size_t num;
gid_t *gid;
} gidarray;
#define GIDARRAY_INIT { 0, 0, NULL }
static void gidarray_free(gidarray *garr)
{
if (garr) {
free(garr->gid);
garr->max = 0;
garr->num = 0;
garr->gid = NULL;
}
}
static size_t gidarray_size(gidarray *garr)
{
return (garr) ? garr->num : 0;
}
static gid_t *gidarray_ptr(gidarray *garr)
{
return (garr) ? garr->gid : NULL;
}
static int gidarray_add(gidarray *garr, const gid_t gid)
{
/* Check if already included. */
size_t i = garr->num;
while (i-->0)
if (garr->gid[i] == gid)
return 0;
if (garr->num >= garr->max) {
size_t max = (garr->num | 15) + 17;
void *tmp;
tmp = realloc(garr->gid, max * sizeof garr->gid[0]);
if (!tmp)
return -1;
garr->gid = tmp;
garr->max = max;
}
garr->gid[garr->num++] = gid;
return 0;
}
int drop_privileges(const char *username)
{
struct passwd *pw;
/* Find out the user and group ID. */
pw = getpwnam(username);
if (!pw) {
errno = ENOENT; /* For "no such user" */
return -1;
}
/* Initialize supplementary groups. */
if (initgroups(username, pw->pw_gid) == -1)
return -1;
/* Set real, effective, and saved group ID. */
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
return -1;
/* Omitted: Dropping Linux capabilities. */
/* Drop privileges by setting real, effective, and saved user ID. */
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
return -1;
/* Now this process has the identity and thus privileges
of user 'username', and no more. */
return 0;
}