ルートシェルのネストを防ぐ方法は? (POSIX)

ルートシェルのネストを防ぐ方法は? (POSIX)

次のBashエイリアスを考えてみましょう。すぐに思ったけど、深く掘り下げる時間はなかった。

alias su='sudo -s'

私はBashを実行していますが、いつか共有するためにGitHubに公開できるので、このソリューションを移植可能にしたいと思います。

人々が遭遇する可能性のある問題は、すでにルートされている状態でそのプログラム(このエイリアス)を実行することです。

デモ:

$ su
[sudo] password for vlastimil:                
# su
# su
# 
exit
# 
exit
# 
exit
$ 

ネストされたシェルセッションを防ぐ方法はありますか?

重要:私は別のファイルではなく、ユーザーとルートに同じエイリアスファイルを使用します。ソリューションは移植可能でなければなりません(POSIX)。

答え1

suAPI、セマンティクス、動作は異なるコマンドなので、sudo -sコマンドの1つを別のコマンドにエイリアスとして指定しないでください。

ここでは、ログインシェルを起動するコマンドが必要なように見えますが、root権限のないシェルから呼び出されたときにのみ可能なので、次のスクリプトを作成します。rootsudorootshell

#! /bin/sh -

die() {
  printf >&2 '%s\n' "$@"
  exit 1
}

[ "$#" -eq 0 ] || die "Usage: $0

Starts a root shell, no argument accepted."

[ "$(id -u)" -eq 0 ] && die "You're already superuser!"

exec sudo -s

システム構成のデフォルトのターゲットユーザーでない場合は、コマンド(またはシステムのuid 0ユーザー名)-u rootに追加します。sudosudo

または、スクリプトを生成したくない場合は、rootshell() (<that-code>)コードをシェルrcファイルに追加してコードをラップしてシェル関数にします($0すべてのシェルが関数名をに入力するわけではないため、関数名に変更$0)。

答え2

シンプルなソリューション、シェルエイリアス

alias su='[ $(id -u) -ne 0 ] && sudo -s || echo Already root...'

  • POSIX互換、つまりコピーして貼り付けるか、dash他のシェルサポートエイリアスをほぼ推測すると、同じ動作が発生する必要があることを意味します。

  • これがEUID私が直接の価値比較を完全に避ける理由です。


デモ:

$ su
[sudo] password for vlastimil:                
# su
Already root...
# su
Already root...
# 
exit
$ 

を使用することを考慮してsudo -s添付します。sudo -s他の変形との比較


高度なソリューション、シェルスクリプト(POSIX)

私は上記の擬似ソリューション(別名)を長い間(数年)使用してきたので、その欠点も知っています。だから私はコードレビューにスクリプトを投稿しました。スティーブン・チャジェラス、これ質問そしてそれぞれ回答そこにあります。これから使用するスクリプトをここに配置しました。

#!/bin/sh

set -o nounset -o errexit

error()
{
    printf >&2 '%s\n' "$@"
    exit 1
}

is_root()
{
    [ "$(id -u)" -eq 0 ]
}

start_root_shell()
{
    exec sudo -s
}

if [ "$#" -gt 0 ]
then
    error "Usage of $(basename "$0") script:" \
    '' \
    'Starts a root shell, no argument accepted.'
fi

if is_root
then
    error 'You are already superuser!'
fi

start_root_shell

ありがとうスティーブン・チャジェラス私に正しい方向を教えてくれました!

答え3

この答えは、ファイルの編集に依存する2つの部分に分けられますsudoers。 (あなたの例にはPOSIXがないか使用されていないsudoので、POSIX準拠に関してこの質問にどのように答えるべきかわかりませんbash。しかし、ソリューションはこれらのツールを使用するシステム間で移植可能でなければなりません。)

  1. ファイルにブール変数を設定すると、使い方を簡素化し、sudoエイリアスの使用を避けることができます。これでを使用してルートシェルにアクセスできます。shell_noargs/etc/sudoerssudosudo -s

  2. たとえば、一部のシェルでは、bash変数(たとえば)を使用してシェルレベルを追跡できます$SHLVL。これはsudo電話をかけるか、単に入力することによって追跡できますbash。これをシェルプロンプトに追加すると、現在持っているネストレベルを決定するのに役立ちます。

sudoersシステム提供のファイルを編集する代わりに独自のファイルを作成します。

sudo EDITOR=nano visudo -f /etc/sudoers.d/local

この行をファイルに追加して保存します。

# Allow sudo with no args to create a shell
Defaults        shell_noargs

# Allow bash to share its nesting level
Defaults        env_check+="SHLVL"

の場合は、(おそらくbashまたは)に移動して定義された行を見つけます。を含めるように編集してください。たとえば、私のDebianシステムでは、次のように設定されています。~/.bashrc~/.bash_profile~/.profilePS1$SHLVL

PS1='${debian_chroot:+($debian_chroot)}\u@\h:\W\$ '

次の内容を含めるように修正します$SHLVL

PS1='${debian_chroot:+($debian_chroot)}\u@\h[$SHLVL]:\W\$ '

最後に、ルート設定ファイルの編集を繰り返します。

使用しているシェルがbashこの機能を提供していない場合、$SHLVL実装するのは簡単ではありません。もしシェルは起動するたびに設定ファイルを実行します。 (sh残念ながら、POSIXはそうではありません。)

関連情報