Scu*_*ort 5 permissions recursive
我需要将一个用户和一个目录传递给一个脚本,并让它吐出该目录中用户具有读访问权限的文件夹/文件的列表。MS 有一个名为 AccessChk for Windows 的工具可以做到这一点,但在 Unix 端是否存在类似的东西?我发现一些代码可以为特定文件夹或文件执行此操作,但我需要它来遍历目录。
find "$dir" ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -r'
Run Code Online (Sandbox Code Playgroud)
您需要询问系统用户是否具有读取权限。唯一可靠的方法是将有效 uid、有效 gid 和补充 gid 切换为用户的并使用access(R_OK)
系统调用(即使这对某些系统/配置有一些限制)。
让我们考虑一下 $user 需要什么才能获得读取权限/foo/file.txt
(假设没有/foo
并且/foo/file.txt
是符号链接)?
他需要:
/
(无需读取)/foo
(无需读取)/foo/file.txt
您已经可以看到,仅检查 的权限的方法file.txt
不起作用,因为file.txt
即使用户没有/
或 的搜索权限,它们也可以说是可读的/foo
。
还有一种方法,如:
sudo -u "$user" find / -readable
Run Code Online (Sandbox Code Playgroud)
也不会工作,因为它不会报告用户没有读取访问权限的目录中的文件(因为无法列出其内容而find
运行$user
),即使他可以读取它们。
如果我们忘记 ACL 或其他安全措施(apparmor、SELinux...)而只关注传统的权限和所有权属性,要获得给定的(搜索或读取)权限,那已经相当复杂且难以用find
.
你需要:
在find
语法上,这里以 uid 1 和 gids 1 和 2 的用户为例,这将是:
find / -type d \
\( \
-user 1 \( -perm -u=x -o -prune \) -o \
\( -group 1 -o -group 2 \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user 1 \( ! -perm -u=r -o -print \) -o \
\( -group 1 -o -group 2 \) \( ! -perm -g=r -o -print \) -o \
! -perm -o=r -o -print
Run Code Online (Sandbox Code Playgroud)
那个修剪用户没有搜索权限的目录和其他类型的文件(符号链接被排除,因为它们不相关),检查读取访问权限。
或者对于$user
从用户数据库中检索到的任意成员及其组成员身份:
groups=$(id -G "$user" | sed 's/ / -o -group /g'); IFS=" "
find / -type d \
\( \
-user "$user" \( -perm -u=x -o -prune \) -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" \( ! -perm -u=r -o -print \) -o \
\( -group $groups \) \( ! -perm -g=r -o -print \) -o \
! -perm -o=r -o -print
Run Code Online (Sandbox Code Playgroud)
这里最好的方法是以 root 身份下降树并检查每个文件的用户权限。
find / ! -type l -exec sudo -u "$user" sh -c '
for file do
[ -r "$file" ] && printf "%s\n" "$file"
done' sh {} +
Run Code Online (Sandbox Code Playgroud)
或与perl
:
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -r'
Run Code Online (Sandbox Code Playgroud)
或与zsh
:
files=(/**/*(D^@))
USERNAME=$user
for f ($files) {
[ -r $f ] && print -r -- $f
}
Run Code Online (Sandbox Code Playgroud)
这些解决方案依赖于access(2)
系统调用。那不是重现系统用来检查访问权限的算法,而是要求系统使用相同的算法(考虑权限、ACL...)进行检查,它会使用您尝试打开用于阅读的文件,因此是最接近可靠解决方案的方法。
现在,所有这些解决方案都试图识别用户可能打开以进行阅读的文件路径,这与用户可能能够阅读内容的路径不同。要回答这个更通用的问题,需要考虑以下几点:
/a/b/file
但如果他拥有file
(并且具有对 的搜索访问权限/a/b
,并且他拥有对系统的 shell 访问权限),那么他将能够更改 的权限file
并授予自己访问权限。/a/b
但没有搜索权限,则情况相同。/a/b/file
因为他没有搜索访问权限/a
或/a/b
,但该文件可能有一个硬链接,/b/c/file
例如,在这种情况下,他可能能够/a/b/file
通过其/b/c/file
路径打开它来读取内容。/a
,但/a/b
可能被绑定安装在 中/c
,因此他可以file
通过/c/file
其他路径打开阅读。找到$user
能够读取的路径。要解决 1 或 2,我们不能再依赖access(2)
系统调用了。我们可以调整我们的find -perm
方法来假设对目录的搜索访问权限,或者在您是所有者后立即对文件进行读取访问权限:
groups=$(id -G "$user" | sed 's/ / -o -group /g'); IFS=" "
find / -type d \
\( \
-user "$user" -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" -print -o \
\( -group $groups \) \( ! -perm -g=r -o -print \) -o \
! -perm -o=r -o -print
Run Code Online (Sandbox Code Playgroud)
我们可以通过记录设备和 inode 编号或 $user 具有读取权限的所有文件并报告具有这些 dev+inode 编号的所有文件路径来解决 3 和 4。这一次,我们可以使用更可靠的 access(2)
基于方法:
就像是:
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -0lne 'print 0+-r,$_' |
perl -l -0ne '
($w,$p) = /(.)(.*)/;
($dev,$ino) = stat$p or next;
$writable{"$dev,$ino"} = 1 if $w;
push @{$p{"$dev,$ino"}}, $p;
END {
for $i (keys %writable) {
for $p (@{$p{$i}}) {
print $p;
}
}
}'
Run Code Online (Sandbox Code Playgroud)
并将这两个解决方案与:
{ solution1; solution2
} | perl -l -0ne 'print unless $seen{$_}++'
Run Code Online (Sandbox Code Playgroud)
到目前为止,如果您已经阅读了所有内容,应该很清楚,其中至少一部分仅涉及权限和所有权,而不是可能授予或限制读取访问权限的其他功能(ACL、其他安全功能...)。当我们分几个阶段处理它时,如果在脚本运行时创建/删除/重命名文件/目录或修改它们的权限/所有权,其中一些信息可能是错误的,例如在拥有数百万个文件的繁忙文件服务器上.
所有这些代码都是标准的(POSIX,Unixt
位),除了:
-print0
是一个 GNU 扩展,现在也被其他一些实现支持。对于find
缺乏支持的实现,您可以-exec printf '%s\0' {} +
改为使用,并替换-exec sh -c 'exec find "$@" -print0' sh {} +
为-exec sh -c 'exec find "$@" -exec printf "%s\0" {\} +' sh {} +
.perl
不是 POSIX 指定的命令,但广泛可用。您需要perl-5.6.0
或以上为-Mfiletest=access
.zsh
不是 POSIX 指定的命令。这zsh
上面的代码应与zsh的-3(1995)及以上的工作。sudo
不是 POSIX 指定的命令。只要系统配置允许perl
以给定用户身份运行,代码应该适用于任何版本。 归档时间: |
|
查看次数: |
2734 次 |
最近记录: |