てきとうなメモ

本の感想とか技術メモとか

suやsudoにおけるPATH

suとかsudoとかrootになる方法はいくつかあるけど、/usr/local/binにパスが通っていないことがあった。
で、なんでかなと。

centos7の環境で確認すると以下のようになる。

$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin
$ su
# echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin
# exit
$ su -
# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
# exit
$ sudo -s
# echo $PATH
/sbin:/bin:/usr/sbin:/usr/bin
# exit
$ sudo -i
# echo $PATH
/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
# exit

結構違う。

まず、suした時はsuを実行したユーザのPATHを引き継ぐ。

su -した時は以下manにあるように

-, -l, --login
シェルをログインシェルにする。すなわち以下のような取り扱いをする: すべての環境変数を解除する。その上で `TERM'、 `HOME'、 `SHELL' を前述 のように設定し、
`USER'、 `LOGNAME' (スーパーユーザーであっても)を同 じく前述のように設定する。続いて `PATH' をコンパイル時のデフォルト値に 設定する。ディレクトリを user
のホームディレクトリに変更する。シェル名の前に `-' を付加し、シェルに ログイン時のスタートアップファイルを読ませる。

コンパイル時のデフォルトのPATH+シェルのログイン時のスタートアップファイルになる。

コンパイル時のデフォルトはutil-linux(centos7のsuを含む)のソースコードを見ると

// util-linux-2.23.2/login-utils/su-common.c 
  if (pw->pw_uid)
    r = logindefs_setenv("PATH", "ENV_PATH", _PATH_DEFPATH);

  else if ((r = logindefs_setenv("PATH", "ENV_ROOTPATH", NULL)) != 0)
    r = logindefs_setenv("PATH", "ENV_SUPATH", _PATH_DEFPATH_ROOT);

となっていて

// util-linux-2.23.2/include/pathnames.h
#undef _PATH_DEFPATH
#define _PATH_DEFPATH           "/usr/local/bin:/bin:/usr/bin"

#undef _PATH_DEFPATH_ROOT
#define _PATH_DEFPATH_ROOT      "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"

となっているので

/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

さらに、/root/.bash_profileに

PATH=$PATH:$HOME/bin

が書かれているので/root/binが追加されている。

sudoした場合はそもそもデフォルトでsecure_pathの設定がしているので、

# /etc/sudoers
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

上記のパスがベースになり、シェルを普通に実行する場合(-s)とログインシェルとして実行する場合(-i)との違いがある。

ログインシェルだと/etc/profileも読み込まれるので

# /etc/profile
# Path manipulation
if [ "$EUID" = "0" ]; then
    pathmunge /usr/sbin
    pathmunge /usr/local/sbin
else
    pathmunge /usr/local/sbin after
    pathmunge /usr/sbin after
fi

が実行されて/usr/local/sbinが付加される。