我正在创建一个将在 Linux 机器上运行的实用程序。为了便于讨论,我们假设它类似于 make。
情况是这样的:有时,当您运行该实用程序时,它会在您运行的目录中创建文件,并且这些文件需要以与执行该工具的用户相同的用户/组创建。这是“make main.o”场景 - 从 main.c 创建 main.o。当您以自己的用户身份运行该实用程序时,这将是默认设置,这很好。
有时,当您运行该实用程序时,它会在 /usr/local/bin 等中创建文件,这些文件需要 root:root。这是“sudo make install”方案 - 在 root:root 下创建 /usr/local/bin/executable。当您以 root 身份运行该实用程序时,这将是默认设置,这很好。
问题是,在所有情况下,该实用程序都需要管理一些额外的缓存文件,例如 /var/cache/utility。当您以 root 身份运行该实用程序时,这些文件是 root:root,这在您下次以普通用户身份运行该实用程序时会出现问题。它们无法被删除/修改。
我想知道的是,在安装此实用程序时为其创建专用用户/组是否是个好主意?我知道 apache、svn 和其他程序都这样做。这是我能想到的唯一方法,但我愿意接受其他解决方案。
如果我确实有一个专门用于该实用程序的用户/组,那么我该如何暂时假设该用户的身份以管理缓存文件,然后在剩余的执行过程中恢复以前的身份(以用户:user 身份创建常规文件,以 root:root 身份创建系统文件)?
到目前为止我得到的是这样的:
- getpwnam(predefined_utility_user_name) // 获取 uid
- 设置 euid(实用程序 uid)
- 设置 egid (实用程序 gid)
// 在 /var/cache/utility 中执行操作
- seteuid(getuid()) // 恢复之前的 id
- setegid(getgid()) // 恢复上一个组
问题:以您自己的身份运行该实用程序时,假设预定义身份不起作用!当您以 root 身份运行时,它可以工作(显然)。
我可以将自己和其他用户添加到与该实用程序关联的组中。但是,这不起作用。那么 - 我该如何实现呢?这是个坏主意吗?
编辑:对以下建议的回应
我又读了一些书,我觉得我有一个很好的解决方案,使用你建议的 #2,它看起来像这样
该实用程序的可执行文件归 utility:utility 所有,并且具有 u+s 和 g+s 权限。因此,当我开始执行时,我分别拥有 utility 和 utility 的 euid/egid。我拥有执行该程序的用户的 ruid/rgid。因此,我可以做的是,当我开始执行时,setegid(getgid()) 和 seteuid(getuid())。这允许进程假定执行该程序的任何人的身份。我将在程序的整个持续时间内保持这一点,但在处理 /var/cache/utility 时,我使用相同的技术来假定 utility:utility 身份。
我不需要对软件进行分区,没有用户必须属于的组,可执行文件只需要自己的用户/组以及 u+s 和 g+s。我想你必须相信该程序不是恶意的,但如果你要执行它,你无论如何都必须假设这一点。你觉得呢?
答案1
为了清楚起见,您的代码的问题在于非特权用户只能设置在某些情况下,根据可执行文件的调用方式,我们需要另一种解决方案。
这是一个有趣的问题。有多种方法可以解决它。我不知道是否有公认的最佳实践解决方案,但这里有一些选择。
设置粘性组权限
/var/cache/utility
。此方法允许您的实用程序在启动器权限下运行。确保用户位于拥有的组中
/var/cache/utility
,并更改权限,以便组分配对所有内容都具有粘性。您可以通过以下方式实现这一点:mkdir /var/cache/utility chown -R :user /var/cache/utility chmod 2770 /var/cache/utility usermod -a -G users joe
现在,由于
joe
位于 中users
,当他运行您的实用程序时,一切都正常。 中任何已修改文件的组权限/var/cache/utility
将保留users
。 问题是没有一个组可以让所有用户自动属于。 因此,此方法不会自动适用于所有用户。 还有安全问题。 您的实用程序可能会/var/cache/utility
以良好的方式修改 中的文件,但这种方法会打开用户空间狂野西部的闸门。将您的实用程序分为前端和后端。
将实用程序分为前端和后端并不方便,但确实迫使您将操作界面形式化。各部分之间的通信可以采用两种常见形式:
套接字通信,无论是 unix 套接字还是 TCP 套接字。 这要求你的后端是一个服务。
命令行工具。 这比使用套接字要简单得多,并且后端不会连续运行。
这个想法是在你的后端使用 uid-execute-sticky-bit,这样它就会自动在所有者的帐户下运行,而不管当前登录的用户是谁。前端仍将根据用户的凭据运行。
看看您是否可以拆分实用程序,以便所有缓存操作都由后端执行,但其他活动则在前端执行。您可以按如下方式设置后端的 uid:
chmod u+s /usr/bin/utility-back-end
对这项技术有一个相当好的概述这里。这样对软件进行分区仍然有些不方便,但这是我所知道的最佳解决方案。以下命令将列出系统上已使用此方法的所有实用程序:
find / -xdev \( -perm -4000 \) -type f -print0 | xargs -0 ls -l
希望有所帮助。