如何在考虑用户权限的情况下执行文件/目录操作?

Nat*_*man 8 unix privileges file-manipulation

我有一个服务器应用程序将在系统帐户下运行,因为在任何给定时间,它将代表系统上的任何用户处理请求.这些请求包含操作文件系统的指令.

这是一个问题:程序需要在执行操作时记住特定用户的特权.例如,如果其权限是,joe则无法修改./home/larry755

目前我的策略是这样的

  • 获取文件的所有者/组
  • 将其与尝试执行操作的用户的用户ID /组ID进行比较
  • 如果匹配(或者如果不匹配),请使用文件中权限字段的相应部分来允许或拒绝该操作

这是明智的吗?有更简单的方法吗?

起初,我正在考虑在用户的帐户下运行应用程序的多个实例 - 但这不是一个选项,因为那时只有一个实例可以侦听给定的TCP端口.

Rob*_*sak 3

看一下samba的例子就可以做到这一点。samba 守护进程以 root 身份运行,但会尽快分叉并采用普通用户的凭据。

Unix 系统有两组独立的凭据:真实用户/组 ID 和有效用户/组 ID。真实集标识您的实际身份,有效集定义您可以访问的内容。如果您是 root 用户,您可以根据需要更改有效 uid/gid(包括更改为普通用户并再次更改),因为您的真实用户/组 ID 在转换过程中仍保持 root 状态。因此,在单个进程中执行此操作的另一种方法是根据seteuid/gid需要来回应用不同用户的权限。如果您的服务器守护进程以 root 身份运行或已经这样做,CAP_SETUID那么这将是允许的。

但是,请注意,如果您能够随心所欲地切换有效 uid/gid,并且您的应用程序被破坏,那么该破坏可能会将有效 uid/gid 切换回 0,并且您可能会遇到严重的安全漏洞。这就是为什么明智的做法是尽快永久删除所有权限,包括您的真实用户 uid/gid。

因此,以 root 身份运行单个侦听套接字是正常且更安全的做法,然后通过调用 来分叉并更改真实和有效的用户 ID setuid。那么就无法变回来了。您的分叉进程将具有已编辑的套接字,accept()因为它是分叉的。每个进程只是关闭它们不需要的文件描述符;套接字保持活动状态,因为它们被相反进程中的文件描述符引用。

您还可以尝试通过自己单独检查权限来强制执行权限,但我希望很明显,这可能容易出错,有很多边缘情况并且更有可能出错(例如,它不适用于 POSIX ACL)除非你也专门实现了这一点)。

所以,你有三个选择:

  1. Fork 和setgid()/setuid()给你想要的用户。如果需要沟通,请在分叉之前使用pipe(2)或。socketpair(2)
  2. 不要根据需要分叉和seteuid()/setegid()绕过(不太安全:更有可能意外损害您的服务器)。
  3. 不要弄乱系统凭据;手动执行权限(不太安全:更有可能获得错误的授权)。

如果您需要与守护进程进行通信,那么尽管通过套接字或管道进行通信可能会比较困难,但第一个选项确实是正确的安全方法。例如,了解ssh 如何进行权限分离。您可能还会考虑是否可以更改您的体系结构,以便进程可以只共享一些内存或磁盘空间,而不是进行任何通信。

您提到您考虑为每个用户运行一个单独的进程,但需要一个侦听 TCP 端口。你仍然可以这样做。只需让一个主守护进程监听 TCP 端口并向每个用户守护进程分发请求并根据需要进行通信(例如,通过 Unix 域套接字)。这实际上与拥有一个分叉主守护进程几乎相同;我认为后者会更容易实施。

进一步阅读:credentials(7)联机帮助页。另请注意,Linux 有文件系统 uid/gids;除了发送信号等其他内容之外,这几乎与有效的 uid/gids 相同。如果您的用户没有 shell 访问权限并且无法运行任意代码,那么您无需担心差异。