52

ディレクトリが現在のプロセスのuidによって書き込み可能かどうかをテストできます。

if [ -w $directory ] ; then echo 'Eureka!' ; fi

しかし、ディレクトリが他のuidによって書き込み可能かどうかをテストする方法を誰かが提案できますか?

私のシナリオは、MySQL Serverインスタンスを管理していて、slow-queryログファイルの場所を一時的に変更したいというものです。これを行うには、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特権を持っているとは想定できないため、 依存しないソリューションが必要です。

4

8 に答える 8

31

これが、長い回り道のチェック方法です。

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
于 2012-12-31T17:42:14.780 に答える
10

それはテストを行うことができます:

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

説明:

テストは1つだけで(if)、ループもフォークもありません。

+注意:stat -Lc 代わりに使用したstat -cので、これはシンボリックリンクでも機能します!

したがって、条件は 次の場合です

  • の統計を正常に読み取り$directory、に割り当てることができましたdirVals
  • そして
    • (所有者の一致フラグUserWriteableが存在します)
    • またはフラグOtherWriteableが存在します
    • または(フラグGroupWriteabeが存在し 、かつ
      • AND$wantedUserのメンバーリストを正常に評価できましたgMember
      • フィールド2を最後にマージして作成された文字列は、$gMemberbeginOfSting -Or-something-followed-by-a-space、直後にターゲットのグループ(${dirVals[1]})、直後にa-space-followed-by-something-Or-endOfStringと一致します。。)。

その後、新年あけましておめでとうございます

グループのテストは2番目のフォークを意味するので(そして私はそのような呼び出しをできるだけ減らすのが大好きです)、これは実行される最後のテストです。

古い

単に:

su - mysql -c "test -w '$directory'" && echo yes
yes

また:

if su - mysql -s /bin/sh -c "test -w '$directory'" ; then 
    echo 'Eureka!'
  fi

注:最初に、開発したことを二重引用符で囲むように警告して$directoryください。

于 2012-12-31T16:31:16.443 に答える
8

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"

この場合、42mysqlユーザーのuidです。必要に応じて、独自の値に置き換えてください。

UPDATE(sudo特権のないユーザーをサポートするため)
bashスクリプトを変更ユーザーに取得するには、 (「ユーザーIDの切り替え」)sudu機能が必要になります。この回答suidで指摘されているように、これはセキュリティ上の制限であり、回避するにはハックが必要です。このブログを回避する「方法」の例については、このブログを確認してください(私はテスト/試行していないため、成功を確認できません)。

可能であれば、suid(try)の許可が与えられたスクリプトをCで作成することをお勧めしますchmod 4755 file-name。次に、Cスクリプトから呼び出しsetuid(#)て、現在のユーザーのIDを設定し、Cアプリケーションからコード実行を続行するか、必要なコマンドを実行する別のbashスクリプトを実行することができます。これもかなりハッキーな方法ですが、sudo以外の方法としては、おそらく最も簡単な方法の1つです(私の意見では)。

于 2012-12-31T16:31:34.480 に答える
7

@chepnerの回答を機能させるには、いくつかの変更を加える必要があったため、コピーと貼り付けを簡単にするために、アドホックスクリプトをここに投稿します。これはマイナーなリファクタリングのみであり、私はchepnerの回答に賛成しました。受け入れられた回答がこれらの修正で更新された場合、私は私のものを削除します。私はすでにその答えに私が苦労したことを指摘するコメントを残しました。

私はBashismsを廃止したかったので、配列をまったく使用していません。((算術評価))はまだ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

コメントがなければ、これはかなりコンパクトですらあります。

于 2014-04-28T09:50:21.980 に答える
3

面白い可能性の1つ(ただし、bashではなくなりました)は、mysqlが所有するsuidフラグを使用してCプログラムを作成することです。

ステップ1。

この素晴らしい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;
}

ステップ2。

コンパイル:

gcc -Wall -ocaniwrite caniwrite.c

ステップ3。

好きなフォルダに移動します。/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数の引数を使用して呼び出すことができます。すべてのディレクトリー(またはファイル)が書き込み可能である場合、戻りコードはtrueです。そうでない場合、戻りコードはfalseです。

于 2012-12-31T17:47:17.667 に答える
2

渡されたユーザーがファイル/ディレクトリの所有者であるか、そのファイル/ディレクトリへの書き込みアクセス権を持つグループのメンバーである場合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

少なくともこれらのテストから、このメソッドはファイルの所有権とグループの書き込みアクセスを考慮して意図したとおりに機能します:-)

于 2013-01-17T16:11:19.267 に答える
2

問題のフォルダで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
于 2014-07-18T18:35:13.353 に答える
2

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つ目はチェックするディレクトリです。誰でも書き込み可能な権限を探し、指定されたユーザーのグループをループして、ディレクトリがユーザーグループにあり、書き込み可能かどうかを確認します。いずれかがヒットすると、検出フラグが設定され、Eurekaが出力されます。最後に。

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!'
于 2015-01-17T04:39:58.173 に答える