众所周知,如果我将自己添加到一个新组,则直到我注销并重新登录后,该更改才会反映出来:
$ sudo adduser me newgroup
$ groups
me sudo
$ groups me
me sudo newgroup
$
这种奇怪的行为是因为groups
由 shell 解释并且不显示新的组成员身份。但groups me
实际上是引用/etc/group
,因此显示了新的成员资格。
但我觉得奇怪的是,新的 shell 没有注意到这个变化:
$ bash
$ groups
me sudo
据我所知,反映新组成员资格的方法是 (1)newgrp
或sg
或su
(2) 注销并重新登录。
因此bash
必须以某种方式将组列表传递给其子级。它不在环境中(我尝试过printenv
),也不在内核的task_struct中(只有gid、egid、sgid和fsgid)。
我不知道怎么办。
答案1
组由进程从其父进程继承。 Bash 在这件事上别无选择。以 root 身份运行的进程可以根据请求获取新的补充组;不以 root 身份运行的进程只能放弃补充组。
不带参数的命令groups
返回它自己的组列表(从其父级继承):真实组、有效组和补充组。该命令在用户和组数据库中group SOMEUSER
查找关联的组。SOMEUSER
登录时,在登录过程从根用户切换到目标用户之前,作为登录过程的一部分,根据用户和组数据库分配组。命令newgrp
、su
和sg
能够在运行时获取额外的组,因为它是设定值根;他们的代码是以这样的方式编写的:他们只会授予用户在登录时将被授予的组(除了 root 可以获得它想要的任何组)。
在Linux内核中,进程的UID和GID被记录在struct cred
。补充组位于group_info
指向一个的字段中struct group_info
其中包含一个组 ID 数组。
答案2
这些组是在登录期间在删除权限之前分配的。你的 shell 不能简单地为自己分配新的组,否则它作为一个安全系统将毫无用处;进程所属的组由内核维护。查看cat /proc/$$/status
示例的输出并查看 Groups: 行;这是您的 shell 所在组的明确列表($$ 是 shell 进程 ID 的快捷方式)。
该groups username
命令将查看 /etc/groups (如您所说)并仅显示用户配置所属的组。如果没有用户名,groups 命令仅显示 /proc/$$/status 组列表,即进程所属的实际当前组。