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

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

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

假设用户名是“user123”,并且他们位于名为“user123”的组中。我想找到那些由 user123 拥有且 u+r 打开的文件;如果文件属于 user123 组,则 g+r 应该打开;否则它可以打开 o+r。

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

sudo -u user123 find /start ! -readable -ls

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

find /start \( -user user123 ! -perm -u=r  \) -o \( -group user123 ! -perm -g=r  \) -ls

但它列出了这个文件:

272118    4 -rw-------   1 user123   user123       3243 Jul  3 19:50 /start/blah/blah/file.txt

/start该文件是user123 拥有且关闭的唯一文件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

这样可行!

原作为何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

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

答案1

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

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

如果没有实际将所有 uid 和 gid 切换为用户的 uid 和 gid 并进行检查,则很难实现与系统相同的逻辑。

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

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

或者与perl

find . -print0 | sudo -u some-user perl -Mfiletest=access -l -0ne '
  print unless -r'

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

在某些情况下运行find -readableassome-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 \)

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

答案2

逻辑是错误的。您认为该文件不应该被列出,因为它由用户拥有user123并设置了用户位r。但是,它被列出是因为它符合第二个条件(它由组拥有user123并且组的r位未设置)。

您的第二个版本之所以有效,是因为以下原因之一德摩根定律:对一组语句进行逻辑“或”运算的否定在逻辑上等同于对各个语句进行“与”运算的否定。换句话说:

 ! ( A || B || C ) == ( !A && !B && !C )

所以工作find是寻找一个文件

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

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

  • 由用户拥有user123且该用户无法读取或
  • 归群组所有user123,并且该群组无法读取或(如果您已完成)
  • 不是世界可读的

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

编辑

顺便说一句(在查看您的个人资料后),我是您的 O'Reilly 书的忠实粉丝:)

答案3

测试环境:

$ sudo tree -fp /tmp/del
/tmp/del
├── [drwxr-xr-x]  /tmp/del/1
│   └── [-rw-r--r--]  /tmp/del/1/f1
├── [d---------]  /tmp/del/2
│   └── [-rw-------]  /tmp/del/2/f1  <-- this filepath is not accessible for ! root
└── [drwxr-xr-x]  /tmp/del/3
    └── [-rw-r--r--]  /tmp/del/3/f1

完整输出:

$ sudo find /tmp/del/ -type f -exec sudo -u user123 ls {} \;
/tmp/del/3/f1
/tmp/del/1/f1
ls: cannot access '/tmp/del/2/f1': Permission denied  <-- required filepath

“脏”所需输出:

# Just redirect stdout
>/dev/null sudo find /tmp/del/ -type f -exec sudo -u user123 ls {} \; 
ls: cannot access '/tmp/del/2/f1': Permission denied

可重用的代码

只需隐藏stdout并显示stderr它即可:

function xfind() { 2>&1 >/dev/null sudo find "${2}" -type f -exec sudo -u "${1}" ls {} \; | grep -o "cannot access .*$"; }

“生产”用法示例:我在 root 的主页中看不到的内容:

$ xfind $USER /root
cannot access '/root/.cache/dconf/user': Permission denied
cannot access '/root/.cache/gstreamer-1.0/registry.x86_64.bin': Permission denied
...

相关内容