
さて、まずこの質問を何度も受けましたが、与えられた答えが完全に満足していないことを知っています。状況は次のとおりです。私は完全に自動化され、一度起動すると、相互作用を必要としないという目標を持って、さまざまなメンテナンスタスクを自動化するために多くのスクリプトを書いています。多くの場合、さまざまなタスク(たとえば、インストールなど)にroot権限が必要な場合がありますが、コマンドやブロック全体(wgetやネットワークからインポートされたアーカイブ抽出など)を実行するのが好きではありません。イベントで最悪のダメージを制限するスーパーユーザー権限。明らかに私の目標を達成するには、またはコマンドに基づいて権限を削除して再取得してsudo
スクリプトを呼び出す必要があります。su
ここではいくつかのオプションを検討しましたが、完全に満足していないので、ここで専門家に相談して、どちらが最善の解決策であるかを知りたいです(他の人もコードを理解しやすく論理的に構造化したいという目的で)。公開済み):
1.)非rootユーザーとして実行されるビットを外部ファイルに分割し、を使用してデフォルトのスクリプトでそのファイルを実行しますsu <user> -c /path/to/file
。しかし、このアプローチにはいくつかの欠点があります。まず、スクリプトの論理構造が壊れ、理解し、読みにくくなり、変数を定義して使用すると問題が発生します。
2.)短縮するエイリアスまたは関数を定義しますsu <user> -c "command"
。スクリプトの80%がこの権限プレフィックスを持っているので、これは非常に悪い考えです。それ以外にも、複数行のコマンドには問題があります(rootで実行したくないコマンドを含む構造と同じ場合)。
su <user> << EOF << ... EOF
3.)コードブロック全体を正しく処理するには、このようなものが必要です。これは私を悩ませる問題の1つである構文の強調がない最もエレガントなソリューションです(スクリプトの論理構造が破壊されないため)。私が試したすべての主要な編集者は、ここのドキュメント内のブロック全体に1つの色を使用します。構文を強調せずにスクリプトの80%を読むことはお勧めできません。
これを処理する本当にエレガントな方法はありませんか?引用符なしでそのようなものはsu <user> -c ( ...)
素晴らしいです。それとも別のシェルに切り替える必要がありますか? (今、bashを使用しているので、zshにEUID変数または同様の設定を許可する機能があると聞きました)
答え1
with zsh
、asで実行してroot
設定した場合
EUID=1000
euid は 1000 に設定されます。実際のuidはまだ0に設定されているため、EUID 0に戻ることができます。実行しているすべてのプログラムは実行して権限を再取得することができますが、setuid()
マルウェアから保護するのではなく、不注意な損傷を防ぐことが目的であればこれで十分です。
#! /bin/zsh -
GID=1000 # optional
EUID=1000 # drop *effective* privileges
some-potentially-harmful-command-that-doesnt-need-superuser
and-another
EUID=0 some-command-that-needs-superuser
more-non-privileged-commands
EUID=0 UID=1000 # now drop privileges with no coming back
# alternatively:
# USERNAME=stephane # sets uid, gid, supplementary groups... based on the user db
コマンド期間中にEUID / UIDを設定できます。
UID=1000 the-command
ただし、そうでないUID
場合、または組み込みまたは機能の場合、他のUSERNAME
プロセスはフォークされないため、実際のユーザーIDを回復することはできません。the-command
zsh
//サブシェルに設定することもできますEUID
。UID
USERNAME
(EUID=0 USERNAME=stephane; untrusted-application)
(後でユーザーを切り替えるためにEUIDを0に設定しました。)
答え2
一つの解決策はメタプログラミング:権限のないさまざまなコードスニペットを別々のファイルとして生成し、プリプロセッサを使用して最終ファイルを生成します。このようにして、プログラムはそれを個々のビットまたは全体として簡単に読み取ることができます。プロセス間通信はファイルを使用して行う必要がありますが、これは少し面倒ですが、特権情報が不正なファイルに漏れる可能性がはるかに少なくなります(すべての情報を明示的に「漏洩」する必要があるため)。
privileged.sh
:
echo "Privileged user: $(whoami)"
su - somebody <<'EOF'
%unprivileged.sh%
EOF
unprivileged.sh
:
echo "Unprivileged user: $(whoami)"
preprocessor.sh
:
while IFS= read -r line
do
if [[ $line =~ ^%([^%]*)%$ ]]
then
cat "${BASH_REMATCH[1]}"
else
printf '%s\n' "$line"
fi
done < privileged.sh > program.sh
テスト実行:
$ bash preprocessor.sh
$ sudo bash program.sh
Privileged user: root
Unprivileged user: somebody