Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C `initgroups`如何调用`setgroups`来初始化用户的补充组ID列表?_C_Linux_Usergroups - Fatal编程技术网

C `initgroups`如何调用`setgroups`来初始化用户的补充组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

来自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。实际上,这样的函数类似于

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;
}