查找用户无法读取的文件?

Tom*_*ime 13 find

我想查找特定用户无法读取的文件。

假设用户名是“user123”,他们在一个名为“user123”的组中。我想找到那些文件,如果它们归 user123 所有,则 u+r 开启;如果文件是 user123 组,则失败,它应该打开 g+r;如果失败,它可以打开 o+r。

由于 GNU find 具有“-可读”,我可以这样做:

sudo -u user123 find /start ! -readable -ls
Run Code Online (Sandbox Code Playgroud)

但是,该进程必须由没有 sudo 访问权限的用户运行。因此我尝试了这个:(它不检查 o+r 但这并不重要)

find /start \( -user user123 ! -perm -u=r  \) -o \( -group user123 ! -perm -g=r  \) -ls
Run Code Online (Sandbox Code Playgroud)

但它列出了这个文件:

272118    4 -rw-------   1 user123   user123       3243 Jul  3 19:50 /start/blah/blah/file.txt
Run Code Online (Sandbox Code Playgroud)

该文件是/startuser123 拥有的唯一文件,并且g=r关闭。就好像 find 正在解释-u=ras -g=r

我决定尝试颠倒逻辑并改为测试not ( truth )

find /etc/puppet ! \( \( -user puppet -perm -u=r  \) -o \( -group puppet -perm -g=r \) -o \( -perm -o=r \) \)  -ls
Run Code Online (Sandbox Code Playgroud)

那个有效!

为什么原版find失败了?这是find(不太可能)中的错误还是逻辑错误?

更新:我的逻辑错了。正如下面所指出的,因为 ! ( A || B || C ) == ( !A && !B && !C ) 这是两个等效的语句:

find /start ! \( \( -user user123 -perm -u=r \) -o \( -group user123 -perm -g=r \) -o \( ! \( -user user123 -o -group user123 \) -perm -o=r \) \) -ls
find /start ! \( -user user123 -perm -u=r \) ! \( -group user123 -perm -g=r \) ! \( ! \( -user user123 -o -group user123 \) -perm -o=r \) -ls
Run Code Online (Sandbox Code Playgroud)

我的目标是不必两次测试用户/组。我真正需要的是一个更复杂的 if-then-else 结构,这可能只有在有 -xor 运算符时才有可能。我可以用和/或/不构建一个异或,但它会比上面的两个解决方案更复杂。

Sté*_*las 8

要检查用户是否可以通过给定路径访问文件,还有很多事情需要考虑:

  • 文件的所有者
  • 文件组
  • 文件中的 ACL
  • 用户的 uid、gid 和补充 gid
  • 搜索访问通向该文件的任何路径组件。
  • 文件是否是符号链接
  • 权限适用于 id 0 的用户。
  • 可能更多的安全功能,如 SELinux ...

除非将所有 uid 和 gid 实际切换到用户的 uid 和 gid 并进行检查,否则很难实现与系统相同的逻辑。

使用 zsh,您可以(以 root 身份)执行以下操作:

readable() (
  USERNAME=$u
  [ -r "$REPLY" ]
)
u=some-user
print -rl -- **/*(DoN^+readable)
Run Code Online (Sandbox Code Playgroud)

或与perl

find . -print0 | sudo -u some-user perl -Mfiletest=access -l -0ne '
  print unless -r'
Run Code Online (Sandbox Code Playgroud)

也就是说,在这两种情况下,都root以相应的用户身份下降目录树,但测试文件访问权限。

在某些情况下不会运行find -readablesome-user因为它无法通过用户没有访问权限或没有读取权限(但可能有访问权限)的目录。

即使只考虑文件本身的权限和所有权(而不是 ACL 或路径组件......),您也至少需要(这里是 GNU 语法):

u=some-user; g=$(id -G "$u" | sed 's/ / -o -group /g'); IFS=" "
find . ! \( -user "$u" -perm -u=r -o \
          ! -user "$u" \( -group $g \) -perm -g=r -o \
          ! -user "$u" ! \( -group $g \) -perm -o=r \)
Run Code Online (Sandbox Code Playgroud)

这个想法是,如果文件归用户所有,则所有其他权限都无关紧要。如果不是,则如果该文件由任何用户组拥有,则“其他”权限无关紧要。


Jos*_* R. 7

逻辑是错误的。你认为这个文件不应该被列出,因为它归user123用户所有并且r设置了用户的位。但是,它被列出是因为它与第二个条件匹配(它归组所有user123并且组的r位未设置)。

您的第二个版本之所以有效,是因为de Morgan 定律之一:否定一组语句的逻辑 ORing 在逻辑上等同于 ANDing 对单个语句的否定。换句话说:

 ! ( A || B || C ) == ( !A && !B && !C )
Run Code Online (Sandbox Code Playgroud)

所以工作find正在寻找一个文件

  • 不是(由用户拥有user123并由所述用户读取)并且
  • 不是(归组所有user123并且可由所述组读取)并且
  • 不是世界可读的。

而第一个find正在寻找一个文件

  • 归用户所有user123且该用户不可读或
  • 归组所有user123且该组不可读或(如果您已完成)
  • 不是世界可读的

因此,如您所见,将列出与上述 3 个条件中的任何一个(不一定是全部)匹配的文件。

编辑

顺便说一句(在查看您的个人资料后),我非常喜欢您的 O'Reilly 书 :)