Bil*_*win 45 directory bash file-permissions
我们可以测试目录是否可由当前进程的uid写入:
if [ -w $directory ] ; then echo 'Eureka!' ; fi
Run Code Online (Sandbox Code Playgroud)
但是,有人可以建议一种方法来测试目录是否可由其他 uid 写入?
我的方案是我正在管理MySQL Server实例,我想暂时更改慢查询日志文件的位置.我可以通过执行MySQL命令SET GLOBAL slow_query_log_file='$new_log_filename',然后禁用和启用查询日志记录来mysqld启动使用该文件.
但我希望我的脚本检查mysqld进程的uid 是否有权创建新的日志文件.所以我想做一些像(伪代码)的东西:
$ if [ -w-as-mysql-uid `basename $new_log_filename` ] ; then echo 'Eureka!' ; fi
Run Code Online (Sandbox Code Playgroud)
但当然这是一个想象的测试谓词.
澄清: 我想要一个不依赖的解决方案,su因为我无法假设我的脚本用户具有su特权.
che*_*ner 28
这是一种漫长而迂回的检查方式.
USER=johndoe
DIR=/path/to/somewhere
# Use -L to get information about the target of a symlink,
# not the link itself, as pointed out in the comments
INFO=( $(stat -L -c "%a %G %U" "$DIR") )
PERM=${INFO[0]}
GROUP=${INFO[1]}
OWNER=${INFO[2]}
ACCESS=no
if (( ($PERM & 0002) != 0 )); then
# Everyone has write access
ACCESS=yes
elif (( ($PERM & 0020) != 0 )); then
# Some group has write access.
# Is user in that group?
gs=( $(groups $USER) )
for g in "${gs[@]}"; do
if [[ $GROUP == $g ]]; then
ACCESS=yes
break
fi
done
elif (( ($PERM & 0200) != 0 )); then
# The owner has write access.
# Does the user own the file?
[[ $USER == $OWNER ]] && ACCESS=yes
fi
Run Code Online (Sandbox Code Playgroud)
那可以做测试:
if read -a dirVals < <(stat -Lc "%U %G %A" $directory) && (
( [ "$dirVals" == "$wantedUser" ] && [ "${dirVals[2]:2:1}" == "w" ] ) ||
( [ "${dirVals[2]:8:1}" == "w" ] ) ||
( [ "${dirVals[2]:5:1}" == "w" ] && (
gMember=($(groups $wantedUser)) &&
[[ "${gMember[*]:2}" =~ ^(.* |)${dirVals[1]}( .*|)$ ]]
) ) )
then
echo 'Happy new year!!!'
fi
Run Code Online (Sandbox Code Playgroud)
说明:
只有一个测试(if),没有循环,没有fork.
+ Nota:因为我使用stat -Lc 而不是stat -c,这也适用于符号链接!
所以条件是, 如果,
$directory并将其分配给dirVals,$wantedUser分配给gMember AND$gMember将匹配beginOfSting-Or-something-follow-a-space,紧接着是target的group(${dirVals[1]}),紧接着是a-space-follow-something-Or-endOfString.)然后呼应新年快乐!
由于小组的测试意味着第二个分支(我希望尽可能减少这样的调用),这是最后一个要做的测试.
老:
只是:
su - mysql -c "test -w '$directory'" && echo yes
yes
Run Code Online (Sandbox Code Playgroud)
要么:
if su - mysql -s /bin/sh -c "test -w '$directory'" ; then
echo 'Eureka!'
fi
Run Code Online (Sandbox Code Playgroud)
Nota:警告首先用双引号括起来进行$directory开发!
您可以使用sudo在脚本中执行测试.例如:
sudo -u mysql -H sh -c "if [ -w $directory ] ; then echo 'Eureka' ; fi"
Run Code Online (Sandbox Code Playgroud)
为此,执行脚本的用户sudo当然需要特权.
如果您明确需要uid而不是用户名,您还可以使用:
sudo -u \#42 -H sh -c "if [ -w $directory ] ; then echo 'Eureka' ; fi"
Run Code Online (Sandbox Code Playgroud)
在这种情况下,42是mysql用户的uid .如果需要,替换您自己的价值.
更新(以支持非sudo特权用户)
要获得一个bash脚本来更改用户而不sudu需要能力suid("切换用户ID").正如这个答案所指出的,这是一个安全限制,需要黑客来解决.查看这个博客,了解"如何"解决它的一个例子(我没有测试/尝试过,所以我无法确认它是否成功).
如果可能的话,我的建议是在C中编写一个脚本,该脚本具有suid(try chmod 4755 file-name)的权限.然后,您可以setuid(#)从C脚本调用以设置当前用户的id,并从C应用程序继续执行代码,或让它执行单独的bash脚本,该脚本运行您需要/想要的任何命令.这也是一个非常糟糕的方法,但就非sudo替代方案而言,它可能是最简单的(在我看来).
因为我必须对@chepner的答案进行一些更改才能使其正常工作,所以我在这里发布了我的临时脚本,以便于复制和粘贴。这只是一个较小的重构,我赞成chepner的回答。如果接受的答案已通过这些修复程序更新,我将删除我的。我已经对该答案发表了评论,指出了我遇到的麻烦。
我想消除Bashisms,所以这就是为什么我根本不使用数组的原因。在((算术评估))仍然是一个猛砸特有的功能,所以我毕竟停留在猛砸。
for f; do
set -- $(stat -Lc "0%a %G %U" "$f")
(("$1" & 0002)) && continue
if (("$1" & 0020)); then
case " "$(groups "$USER")" " in *" "$2" "*) continue ;; esac
elif (("$1" & 0200)); then
[ "$3" = "$USER" ] && continue
fi
echo "$0: Wrong permissions" "$@" "$f" >&2
done
Run Code Online (Sandbox Code Playgroud)
没有评论,这甚至相当紧凑。