![为什么通过 tmux 进行 SSH 登录后新组未激活?](https://linux22.com/image/1583468/%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%9A%E8%BF%87%20tmux%20%E8%BF%9B%E8%A1%8C%20SSH%20%E7%99%BB%E5%BD%95%E5%90%8E%E6%96%B0%E7%BB%84%E6%9C%AA%E6%BF%80%E6%B4%BB%EF%BC%9F.png)
这是我的情况:
- 我已为我的用户添加了一个新组。
- 我已确认
/etc/group
设置正确。 - 如果我这样做,
su - myuser
则显示该组id -a
- 但是登录退出并再次登录(通过
ssh
)不会重新加载该组:id -a
才不是显示新组
这是因为 SSH 连接正在重复使用具有旧组设置的某些进程。
这是什么?
附加信息:
- 我正在使用
tmux
,但在客户端上。我要 ssh 连接的服务器(以及我要更改组的位置)没有tmux
运行。 - 这可能与 ssh 连接共享有关。
答案1
因为该
ssh
连接正在重复使用具有旧组设置的某些进程
在您提到 SSH 连接共享之后,很明显这是罪魁祸首。为了理解这个问题,让我们看看 Linux 中的进程如何携带有关其所有者的信息。
产生新进程
所有进程都源自 PID 为 1(init
或upstart
或systemd
,无论什么)且属于用户的进程root
。进程可以自我复制,请参阅man 2 fork
;或者它可以用另一个映像替换自己的映像,请参阅man 3 exec
。程序的常用方法是A产生程序乙是分叉,因此暂时有两个实例A,然后执行乙(新的A变成乙)现在A(父进程)和乙(子进程)。
每个进程都带有关于其所有者和组的信息,请参阅man 2 getuid
、、man 2 getgid
。man 2 getgroups
当生成子进程时,它通常会继承此信息。
为了创建属于 之外的用户的进程root
,特权进程在某个时候必须更改其所有者。它使用setuid(2)
、setgid(2)
和setgroups(2)
类似来实现这一点。通常会给出所需的 UID,并从中派生出组(包括补充组)。这是新组活跃的时刻。
非特权进程生成后,其子进程(如果有)将直接继承该信息,而无需向操作系统查询当前的用户所属的组集。此时新组无法激活。但也有例外:像su
、sg
或 这样的程序sudo
,它们带有 setuid 标志,并由root
start 拥有特权。在它们确保用户被允许执行操作后,情况与已经讨论过的情况相同,新组将激活。
因此su - myuser
注意到了新组,因为它在后台更改了用户。检索当前的用户所属的组集是此过程的一部分。
另一方面,它id
显示了它从 shell 继承的内容。这些信息很旧;它来自其特权祖先操纵其用户 ID 的时候。
注意id myuser
会注意到新的组。Soleid
检索与自身相关的信息(与getgroups(2)
和因此),同时id myuser
查询操作系统当前的关于所选用户的信息。
结论是:如果新组是某个特权进程的后代,您的 shell(及其子进程)将会注意到该新组,因此root
和您的用户之间的转换发生在添加组之后。(正式说明:从到root
的转换root
没有什么不同;重要的是重新设置所有权的行为)。
在实践中
/dev/tty2
左右(没有 SSH)
我可以通过标准文本控制台登录(/dev/tty2
或类似)。进程树的相关部分是:
systemd───login───bash───pstree
^^^^^^^^^^^^^^^ these are owned by root
^^^^^^^^^^^^^ these are owned by my user
将我的用户添加到新组并在另一个 tty 中登录后:
systemd─┬─login───bash
└─login───bash───pstree
^^^^^^^^^^^^^^^ these are owned by root
^^^^^^^^^^^^^ these are owned by my user
因为第二个bash
是在我进行更改后从特权用户生成的login
,所以它会知道新组。在这个基本情况下,“注销并再次登录”方法有效。
GUI(仍然没有 SSH)
考虑进程树的一个示例部分:
systemd───plasmashell───konsole───bash
^^^^^^^ this is owned by root
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ these are owned by my user
将我的用户添加到新组后,中的新 shell(新选项卡)konsole
不会看到变化。xterm
如果我从 KDE Plasma ( plasmashell
) 生成它,也不会看到。但如果我通过 登录/dev/tty2
,正确设置并导出DISPLAY
变量,然后从那里生成xterm
,则 shell 中的xterm
将要看到更改。在两种情况下xterm
都显示在同一个 KDE 桌面上,但第一种情况(间接地)源自很久以前(在更改之前)切换用户的特权进程;第二种情况(间接地)源自一分钟前(在更改之后)切换用户的特权进程。
SSH
在我的 Debian sshd
(SSH 守护进程)中,反复分叉后,进程树的相关部分如下:
systemd───sshd───sshd───sshd───bash
^^^^^^^^^^^^^^^^^^^^^ these are owned by root
^^^^^^^^^^^ these are owned by my user
第二次连接后,没有连接共享:
systemd───sshd─┬─sshd───sshd───bash
└─sshd===sshd───bash───pstree
^^^^^^^^^^^^^^^^^^^^^ these are owned by root
^^^^^^^^^^^^^^^^^^^^ these are owned by my user
假设我同时将我的用户添加到一个新组。我标记的“链接”===
表示sshd
在更改后,某个特权用户产生了一个非特权用户。后者及其后代都知道这个新组。
有了连接共享,情况就有所不同:
systemd───sshd───sshd───sshd─┬─bash
└─bash───pstree
^^^^^^^^^^^^^^^^^^^^^ these are owned by root
^^^^^^^^^^^^^^^^^^^^ these are owned by my user
在这种情况下,新的bash
从老的 sshd
由我的用户拥有。这sshd
包含有关我的组的旧信息,新组bash
继承了它。
我相信你的情况也会发生同样的情况。
tmux
问题不仅限于sshd
。 以 为例tmux
。 在一般情况下,使用tmux
,在用户登录后,tmux
可以直接作为登录 shell 启动,也可以间接从(非tmux
)登录 shell 启动(手动或像从.bashrc
;带或不带exec
)。 该工具作为客户端连接到tmux
用户拥有的服务器。 如果尚未为该特定用户设置服务器,它将被启动。 服务器启动“最终”shell。 进程树可能如下所示:
systemd─┬─login───bash───tmux: client
└─tmux: server─┬─3*[bash]
└─bash───pstree
在我将用户添加到新组后,新bash
生成的用户login
确实可以看到该组。新的 tmux
服务器及其子服务器将会看到它。但是已经运行 tmux
服务器及其子服务器则不然;即使对于在我将用户添加到新组后产生的子服务器(shell),情况也是如此。
要明确的是:tmux
客户端和服务器与 SSH 客户端和服务器无关;它们都在同一台机器上运行。tmux
只有在发生更改的地方运行时才会有关系。您提到tmux
只在 SSH 的客户端上,而更改是在 SSH 的服务器端进行的;所以对你来说tmux
无关紧要。
假设我已经知道了tmux
更改发生的位置。为了让内部的新 shelltmux
注意到新组,我需要退出(不是分离,而是真正退出)内部正在运行的所有内容tmux
,这样我的tmux
服务器也会退出,因此可以重新诞生。关闭服务器应该可行,但是这样做有明显的缺点。
从技术上讲,启动单独的tmux
服务器是可行的。如果我不需要连接到已经运行的会话,这就是要走的路。请参阅中的-L
和。如果在我登录后自动运行,我可能需要绕过这一点才能通过,例如:-S
man 1 tmux
tmux
-L
ssh -t user@host tmux -L foo