現在のプロセスのuidによってディレクトリが書き込み可能かどうかをテストできます。
if [ -w $directory ] ; then echo 'Eureka!' ; fi
しかし、誰かがother 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
しかし、もちろんそれは架空のテスト述語です。
明確化:スクリプトのユーザーがsu特権を持っていると想定できないため、su
に依存しないソリューションが必要です。
これは、遠回りの長いチェック方法です。
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
それはテストを行うことができます:
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
説明:
oneテスト(if)、ループなしおよびフォークなしのみがあります。
+注意:stat -Lc
の代わりにstat -c
を使用したので、これはシンボリックリンクでも機能します!
したがって、条件はif、
$directory
の統計を正常に読み取り、dirVals
に割り当てることができました。$wantedUser
のメンバーリストをgMember
に正常に割り当てることができました[〜#〜] and [〜#〜]$gMember
の最後にマージして作成された文字列は、すぐにbeginOfSting-Or-something-followed-by-a-spaceと一致しますその後にターゲットのグループ(${dirVals[1]}
)、直後にa-space-followed-by-by-some-Or-endOfStringが続きます。 )その後 echo Happy new year!
グループのテストは2番目のforkを暗示しているので(そして、このような呼び出しを可能な限り減らすのが大好きです)、これが最後のテストです。
旧:
単に:
su - mysql -c "test -w '$directory'" && echo yes
yes
または:
if su - mysql -s /bin/sh -c "test -w '$directory'" ; then
echo 'Eureka!'
fi
注:$directory
を開発したために、最初に二重引用符で囲むように警告してください!
Sudo
を使用して、スクリプトでテストを実行できます。例えば:
_Sudo -u mysql -H sh -c "if [ -w $directory ] ; then echo 'Eureka' ; fi"
_
これを行うには、もちろんスクリプトを実行するユーザーにSudo
特権が必要です。
ユーザー名の代わりにuidが明示的に必要な場合は、次も使用できます。
_Sudo -u \#42 -H sh -c "if [ -w $directory ] ; then echo 'Eureka' ; fi"
_
この場合、_42
_はmysql
ユーザーのuidです。必要に応じて、独自の値に置き換えてください。
[〜#〜] update [〜#〜](非Sudo特権ユーザーをサポートするため)
bashスクリプトを取得してsudu
なしでユーザーを変更するには、suid
(「ユーザーIDの切り替え」)の機能が必要です。 this answer で指摘されているように、これは回避策としてハックが必要なセキュリティ制限です。 このブログ をチェックして、回避方法の例について確認してください(テスト/試していないため、成功したかどうかは確認できません)。
私の推奨事項は、可能であれば、suid(_chmod 4755 file-name
_を試してください)を許可するスクリプトをCで作成することです。次に、Cスクリプトからsetuid(#)
を呼び出して現在のユーザーのIDを設定し、Cアプリケーションからコード実行を続行するか、必要なコマンドを実行する別のbashスクリプトを実行させることができます。これもかなりハッキーな方法ですが、Sudo以外の代替方法に関しては、おそらく最も簡単な方法の1つです(私の意見では)。
@chepnerの答えを機能させるためにいくつかの変更を加える必要があったため、簡単にコピー&ペーストできるようにアドホックスクリプトをここに投稿しています。それはマイナーなリファクタリングのみであり、私はchepnerの答えを支持しました。受け入れられた回答がこれらの修正で更新された場合、私は削除します。私は問題に直面したことを指摘するその答えにコメントをすでに残しています。
バシズムを廃止したかったので、配列をまったく使用していません。 ((
算術評価))
はまだBash専用の機能であるため、結局Bashにこだわっています。
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
コメントがなければ、これはかなりコンパクトです。
面白い可能性の1つ(ただし、bashではありません)は、mysqlが所有するsuidフラグを使用してCプログラムを作成することです。
この素晴らしいCソースファイルを作成し、caniwrite.c
(申し訳ありませんが、私はいつも名前を選ぶのが嫌でした):
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char* argv[]) {
int i;
for(i=1;i<argc;++i) {
if(eaccess(argv[i],W_OK)) {
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
コンパイル:
gcc -Wall -ocaniwrite caniwrite.c
好きなフォルダに移動します、/usr/local/bin/
適切な選択であるため、所有権を変更し、suidフラグを設定します(これをrootとして実行します)。
# mv -nv caniwrite /usr/local/bin
# chown mysql:mysql /usr/local/bin/caniwrite
# chmod +s /usr/local/bin/caniwrite
できた!
次のように呼び出します:
if caniwrite folder1; then
echo "folder1 is writable"
else
echo "folder1 is not writable"
fi
実際には、caniwrite
を必要な数の引数で呼び出すことができます。 allディレクトリ(またはファイル)が書き込み可能な場合、戻りコードはtrueになり、そうでない場合、戻りコードはfalseになります。
alias wbyu='_(){ local -i FND=0; if [[ $# -eq 2 ]]; then for each in $(groups "$1" | awk "{\$1=\"\";\$2=\"\"; print \$0}"); do (($(find "${2}" \( -perm /220 -o -group "$each" -a -perm /g+w \) 2>/dev/null | wc -l))) && FND=1; done; else echo "Usage: wbyu <user> <file|dir>"; fi; (($FND)) && echo "Eureka!"; }; _'
エイリアスに入れて、2つの引数を取ります。1つ目はユーザーで、2つ目はチェックするディレクトリです。誰でも書き込み可能な権限を探し、指定されたユーザーのグループをループして、ディレクトリがユーザーグループにあり、書き込み可能かどうかを確認します。最後に。
IOW:
FND=0
USER=user1
DIR=/tmp/test
for each in $(groups "$USER" | awk '{$1="";$2=""; print $0}'); do
(($(find "$DIR" \( -perm /220 -o -group "$each" -a -perm /g+w \)\
2>/dev/null | wc -l))) && FND=1
done
(($FND)) && echo 'Eureka!'
問題のフォルダでmkdirを試してみてください。より信頼性が高い...
mkdir your_directory/
[[ $? -ne 0 ]] && echo "fatal" || echo "winner winner chicken dinner.."
または?
# -- run the following commands as the_User_ID
Sudo su - the_User_ID << BASH
mkdir your_directory/
[[ $? -ne 0 ]] && echo "fatal" || echo "winner winner chicken dinner.."
BASH
渡されたユーザーがファイル/ディレクトリの所有者であるか、そのファイル/ディレクトリへの書き込みアクセス権を持つグループのメンバーである場合にcan_user_write_to_file
を返す関数1
を作成しました。そうでない場合、メソッドは0
を返します。
## Method which returns 1 if the user can write to the file or
## directory.
##
## $1 :: user name
## $2 :: file
function can_user_write_to_file() {
if [[ $# -lt 2 || ! -r $2 ]]; then
echo 0
return
fi
local user_id=$(id -u ${1} 2>/dev/null)
local file_owner_id=$(stat -c "%u" $2)
if [[ ${user_id} == ${file_owner_id} ]]; then
echo 1
return
fi
local file_access=$(stat -c "%a" $2)
local file_group_access=${file_access:1:1}
local file_group_name=$(stat -c "%G" $2)
local user_group_list=$(groups $1 2>/dev/null)
if [ ${file_group_access} -ge 6 ]; then
for el in ${user_group_list-nop}; do
if [[ "${el}" == ${file_group_name} ]]; then
echo 1
return
fi
done
fi
echo 0
}
それをテストするために、ちょっとしたテスト関数を書きました。
function test_can_user_write_to_file() {
echo "The file is: $(ls -l $2)"
echo "User is:" $(groups $1 2>/dev/null)
echo "User" $1 "can write to" $2 ":" $(can_user_write_to_file $1 $2)
echo ""
}
test_can_user_write_to_file root /etc/fstab
test_can_user_write_to_file invaliduser /etc/motd
test_can_user_write_to_file torstein /home/torstein/.xsession
test_can_user_write_to_file torstein /tmp/file-with-only-group-write-access
少なくともこれらのテストから、メソッドはファイルの所有権とグループの書き込みアクセスを考慮して意図したとおりに機能します:-)