我想找到特定用户无法读取的文件。
假设用户名是“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=r
as -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 -readable
assome-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
...