ssh-env - ssh実行時に環境変数を設定/変更したい
目的
sshでリモートホストでコマンドを実行するときに、PATHやその他の環境変数を設定して実行したい。
例えば、勝手にコマンドのバージョンアップができない重要なサーバで、自分のホーム以下にインストールしたコマンドをssh経由で実行したいのだが、PATHが/usr/local/binなどにしか通っていなくて困っている。
sshのmanによると…
試してみる
~/.ssh/environment
PATH=~/bin:$PATH
と書いて、確認すると、
% ssh ss71-build printenv | grep PATH PATH=/usr/local/bin:/bin:/usr/bin
変わってない。
~/.ssh/rc
PATH=~/bin:$PATH export PATH
と書いて、確認すると、
% ssh ss71-build printenv | grep PATH PATH=/usr/local/bin:/bin:/usr/bin
やはり変わってない。
サーバの設定を確認して、再挑戦
#PermitUserEnvironment no
環境変数指定ができない設定になっていた(sshのデフォルトがこうなってるみたい)。
ここを、"PermitUserEnvironment=yes" にして sshd 再起動後試してみると、
% ssh ss71-build printenv | grep PATH zsh: command not found: printenv
printenvが無い?
はっ、もしや$PATHが展開されてない?と思い、"$PATH"→"/usr/bin"と書き直して試したら、
% ssh ss71-build printenv | grep PATH PATH=~/bin:/usr/bin
今度は変化した。
ただし、rc の方は変化無し。
ソースを見てみる
手元のRHEL4WSではのsshのバージョンは
% ssh -v OpenSSH_3.9p1, OpenSSL 0.9.7a Feb 19 2003
なので、openssh-3.9p1 のソースを参照する。
PermitUserEnvironment の利用箇所
servconf.cにて、定義している。大文字・小文字関係ないんだ…。
static struct { const char *name; ServerOpCodes opcode; } keywords[] = { .... { "permituserenvironment", sPermitUserEnvironment }, .... };
parse_token()にて、渡されたtokenがkeywords[]のいずれかに一致するか調べてる。parse_token()は、server側/client側の両方で使う関数で、keywordsをそれぞれ使い分けて、同じ関数を共用している。
PermitUserEnvironment が "Yes" の時は、options->permit_user_env=-1 とする。ちなみに options はグローバル変数。なんつーか、大雑把な作り。
一方、permit_user_env の参照箇所は、
- auth_parse_options() in auth-options.c : こちらは authorized_keys の中での "env=" の処理なので、今回は違う
- do_setup_env() in session.c : こちらが .ssh/environment を読む箇所
この部分の抜粋:
/* read $HOME/.ssh/environment. */ if (options.permit_user_env && !options.use_login) { snprintf(buf, sizeof buf, "%.200s/.ssh/environment", strcmp(pw->pw_dir, "/") ? pw->pw_dir : ""); read_environment_file(&env, &envsize, buf); }
read_environment_file() の中の処理は、
- 1000行になるまで処理(1000行目以降はエラーを表示して処理中止)
- 行頭のスペースとタブをスキップして、
- 先頭文字が '#' か改行なら無視、
- '=' が行内に無ければwarning表示(処理は続行)
- child_set_env() で、子プロセス用のenv領域などを確保して格納
- 最後に、確保したenvを上(do_child)に返す
そして、do_child()内で、execveの第三引数に env を指定、と。
setenv(3)を使って設定しているわけじゃないから(それじゃroot権限で環境変数が変わるから、考えたら危険だね)、~/.ssh/rc で export しても変わらなった理由も納得。