su
目次- 0.0.1 更新履歴
- 0.0.2 要約
- 1.0.0 準備
- 1.1.0 me
- 1.1.1 meとは
- 1.1.2 me の内容
- 1.1.3 me のインストール
- 1.2.0 fact
- 1.2.1 fact とは
- 1.2.2 fact のオプション
- 1.2.3 fact の内容
- 2.0.0 su
- 2.1.0 su ver.1.4
- 2.2.0 認証の成否
- 2.3.0 プログラムの解説
- 2.3.1
/mnt/factotum
かそれとも/mnt/term/mnt/factotum
か? - 2.3.2 誰の
/mnt/factotum
か? - 2.3.3 誰の名前空間を構成するか?
- 2.3.4 cap を手にするには?
- 2.3.5 getkey とは?
- 2.3.6 分からない事
- 2.4.0 su のオプション
- 2.5.0 信頼できるユーザ
- 2.5.1 認証サーバの
/lib/ndb/auth
- 2.5.2 factotum キーの順序
- 2.6.0 su によるコマンド実行
- 2.6.1 例
- 2.7.0 su ver.1.6
更新履歴
- 2012/09/09 su ver.1.6
- 2005/01/01 su ver.1.5
- 2004/12/11 su ver.1.4
要約
ここではユーザ ID が変化するプログラムを紹介する。そのようなプログラムのコアの部分は cap であり、それは他の頁で su の古い版とともに解説されている。従ってここではプログラム中での factotum の利用の仕方が解説の中心になる。su ver.1.4 では factotum とのインターフェースを追加した。su ver.1.5 は小さな改訂であり、認証部分に関しては ver.1.4 と違いは無い。コマンド実行に関して相対パスを扱えるようにしただけである。
準備
su を紹介する前に、su の成果を調べるためのツールをまず紹介する。me
meとは
コマンドme
はプロセスを生成するユーザ ID とファイルを生成するユーザ ID を表示する。例えば me
を実行するとterm% me arisawa 111 0:00 0:00 184K Pread ps --rw-rw-rw- M 9 arisawa none 0 Dec 7 17:44 /usr/none/tmp/me
me
の実行例
me
のやっていることは単純で実際にプロセスとファイルを生成してみて生成者の ID を表示する。1行目が生成されたプロセスのユーザ ID、2行目が生成されたファイルのユーザ ID である。UNIX と異なり Plan 9 の場合にはこの2つのユーザ ID は同じとは限らない。
me の内容
me の内容は#!/bin/rc # note: chmod 777 /usr/none/tmp f=/usr/none/tmp/me ps|grep ' ps$' if(test -e $f) rm $f touch $f; ls -l $f
me の内容
である。me のインストール
me はファイルを/usr/none/tmp
に生成する。このディレクトリは Plan 9 の標準設定ではユーザ none 以外の書き込めないのでchmod 777 /usr/none/tmpを実行しておく必要がある。
me はどのユーザからも実行できるようにしておくのがよい。筆者はそのようなファイルは
/usr/local/bin
に置いている。chmod 755 /usr/local/bin/rc/meをお忘れなく。どのユーザも使えるようにするには
/bin
に自動的に追加されるようにするのが手っ取り早い。/lib/namespace
に次の行が含まれている事を確認する。. /lib/namespace.local含まれていない場合には
/lib/namespace
が古いのでシステムを更新する。
/lib/namespace.local
を作成する。
bind -a /usr/local/bin/386 /bin bind -a /usr/local/bin/rc /bin
/lib/namespace.local の内容
これで、どのユーザも me を実行できる。
fact
fact とは
factotum の内容をいろいろ変更して実験する事になるでしょうから、効率の良い factotum の管理ツールfact
を用意しました。次のように使います。term% fact --rw-r--r-- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/ctl key proto=p9sk1 dom=aichi-u.ac.jp user=arisawa !password? key proto=p9sk1 dom=aichi-u.ac.jp user=bootes !password? key proto=p9sk1 dom=aichi-u.ac.jp user=alice !password? term% fact -l -lrw------- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/confirm --rw-r--r-- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/ctl -lr-------- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/log -lrw------- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/needkey --r--r--r-- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/proto --rw-rw-rw- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/rpc term% fact -d deleting from /mnt/factotum/ctl delkey proto=p9sk1 dom=aichi-u.ac.jp user=arisawa !password? delkey proto=p9sk1 dom=aichi-u.ac.jp user=bootes !password? delkey proto=p9sk1 dom=aichi-u.ac.jp user=alice !password? send and ctl-D delkey proto=p9sk1 dom=aichi-u.ac.jp user=alice !password? term% fact -a adding to /mnt/factotum/ctl put data and ctl-D key proto=p9sk1 dom=aichi-u.ac.jp user=alice !password=xxxxx term%
fact のオプション
- -l
-
{ls -l /mnt/factotum} および {ls -l /mnt/term/mntfactotum} を表示します。
- -d
-
factotum からキーを削除します
- -a
-
factotum にキーを追加します
注:
- factotum キーの削除は、削除したいキーをマウスで選んで「
send
」で送り、ctl-D で削除されます。複数のキーを選択できます。
- factotum キーの追加は fact で表示されたキーを Plan 9 のウィンドウの編集機能を使って編集し「
send
」で送り、ctl-D で追加されます。複数のキーを選択できます。
- fact は通常は
/mnt/factotum/ctl
への書き込みによってキーの削除や追加を行いますが、場合によっては/mnt/term/mnt/factotum/ctl
にアクセスする必要があり、オプションの-d
や-a
に続く文字(1または2)によってどちらであるかを選択できます。
- パスワードの誤りは、そのキーを一旦削除しなくても、パスワードを訂正して追加すれば置き換えられます。
fact の内容
fact
の内容は次の通りです。#!/bin/rc usage='usage: fact [-adl]' fn addkey { echo adding to $1 echo 'put data and ctl-D' read -m >/$1 } fn delkey { echo deleting from $1 sed s/key/delkey/g < $1 echo 'send and ctl-D' read -m > $1 } ctl=() f=(/mnt /mnt/term/mnt)^/factotum/ctl if(test -w $f(2)) ctl=$f(2) if(test -w $f(1)) ctl=$f(1) while(~ $1 -*){ switch($1){ case -d delkey $ctl exit case -d1 delkey $f(1) exit case -d2 delkey $f(2) exit case -a addkey $ctl exit case -a1 addkey $f(1) exit case -a2 addkey $f(2) exit case -l f=(/mnt /mnt/term/mnt)^/factotum for (x in $f) if(test -e $x) ls -l $x exit case -* echo $usage exit usage } shift } for (x in $f) if(test -w $x){ ls -l $x cat $x }これを
me
と同様に /usr/local/bin/rc
に置くとよいでしょう。chmod 755
をお忘れなく。
su
su ver.1.4
コマンドsu
は UNIX の su
と同様にユーザ ID を変更する。また UNIX の sudo
の機能を併せ持っている。su
のシンタックスはsu [-fnuwD] [-p password] [user [cmd arg ...]]である。多彩な使い方ができるが、とりあえず最も基本的な使い方、すなわち
su aliceのように単にユーザ名のみを与えた場合に我々の関心を集中することにしよう。
su
はこの場合でも必要に応じてパスワードの入力を求めてくる:term% su alice password: blackcat su# me alice 122 0:00 0:00 184K Pread ps --rw-rw-rw- M 28 alice none 0 Dec 7 17:46 /usr/none/tmp/me su#入力を求められたパスワードなどの情報は、
/mnt/factotum
が su を実行するユーザのものであれば、 factotum に自動的に登録される仕組みになっている。cpu コマンドでホストにログインして su を使う場合にはbind -b /mnt/term/mnt/factotum /mnt/factotumを事前に実行しておけばユーザの端末の factotum を使用できる。端末の factotum とは独立した factotum を新たに作成したい場合には
auth/factotumあるいは secstore からキーを取り込まない場合には
auth/factotum -nを実行しておくとよい。
ユーザ名が省略された場合には (UNIX と異なり)最も弱いユーザである none が仮定される。
注意: 認証にはパスワードの他に hostdomain の値が必要である。Plan 9 の現在の版には
/dev/hostdomain
が存在する。しかしこれは今のところ利用されていない。ここは hostdomain の値を入れる場所のはずである。su
は /dev/hostdomain
を利用している。ここへの書き込みの権限はホストオーナーだけが持っている。/rc/bin/cpurc
と /rc/bin/termrc
に次のような行を入れればよい。echo -n aichi-u.ac.jp >/dev/hostdomainここに
aichi-u.ac.jp
は筆者のシステムの hostdomain でありシステム毎に異なる。/dev/hostdomain
に値が設定されていない場合には su
は hostdomain の値の入力を要求してくる。
su ver.1.4 は http://plan9.aichi-u.ac.jp/netlib/cmd/su/ から手に入る
認証の成否
ここでは bootes を Plan 9 システムのオーナー、bob を端末のオーナー、alice をユーザとする。
注意: bootes がシステムのオーナーであることは su のプログラムの中で仮定されている。
bootes や bob が su
によってパスワードなしに alice に変身できるか否かがここでの関心である。
su aliceを実行した場合にパスワードが必要であれば
su
はパスワードの入力を求める。パスワードの入力が求められなくても、su を実行するユーザの factotum に alice のパスワードが含まれていることが変身可能な理由であれば、変身にはパスワードが必要であると考えよう。すると結果は次のように纏める事ができる。
カーネル | 実行者 | パスワード | 結果(プロセス) | 結果(ファイル) |
---|---|---|---|---|
9pcdisk | bob | 無 | OK | OK |
9pcf | bob | 無 | OK | OK |
9pc | bob | 無 | OK | NO |
9pc | bob | 有 | OK | OK |
9pcauth | bootes | 無 | OK | OK |
9pcauth | bob | 無 | NO | NO |
9pcauth | bob | 有 | OK | OK |
9pccpu | bootes | 無 | OK | OK |
9pccpu | bootes | 有 | OK | OK |
9pccpu | bob | 無 | NO | NO |
9pccpu | bob | 有 | OK | OK |
この表は複雑なように見えるが、以下の点から容易に理解できる。
- ホストオーナーはローカルホストの完全な管理権を持っている。従ってプロセスやローカルホストに所属するファイルをホストオーナーは自由に制御できる。
- bootes はシステムの完全な管理権を持っている。従ってシステムのプロセスとファイルを自由に制御できる。
- ホストオーナー以外のユーザが alice のプロセスを生成したい場合には、プロセスの生成者であるホストオーナーにお願いしなくてはならない。(パスワードが必要になる)
- bootes 以外のユーザがファイルサーバに alice のファイルを生成したい場合には、認証サーバの認証が必要である。
コメント: bootes がパスワード無しで任意のユーザのファイルを生成できるのは認証サーバの
/lib/ndb/auth
でその権限が与えられているからである。
プログラムの解説
ここでは su ver.1.4 の要点を解説する。読者はソースコードを読める事が想定されている。su の以前のバージョンに対する su ver.1.4 の特徴は factotum とのインターフェースをとったことにある。従ってプログラム中での factotum の利用の仕方が解説の中心になる。factotum の解説は本来は作成者である Russ Cox が行ってくれるのが一番良いが、彼は忙しすぎる。筆者の解説はいわゆるハッキングによるもので、今だに分からないところを含み、また誤りの可能性を残している。気がついたことがあれば筆者にメールで知らせて頂きたい。
まずは ver.1.4 を作成する中で筆者が気がついた要点を纏めておく。
/mnt/factotum
かそれとも /mnt/term/mnt/factotum
か?
factotum は /mnt/factotum
あるいは (cpu コマンドでログインした場合には) /mnt/term/mnt/factotum
に置かれているが、認証に関する場面では Plan 9 のライブラリはどれも /mnt/factotum
を使っている。(従って su
もそのスタイルを守っている)
誰の /mnt/factotum
か?
認証のプロセスの中で /mnt/factotum
は場合によっては su を実行するユーザのもの、場合によってはホストオーナーのものでなくてはならない。このことがプログラミングでは混乱の原因になる。例えば bob がsu aliceを実行するとしよう。この時 bob が alice のキーを知っている事を bob の factotum の中に alice のキーを持つ事によって示す事ができる。この場面では
/mnt/factotum
は bob のものでなくてはならない。他方 bob はホストオーナーに対して alice のプロセスの生成者となるようにパスワードを添えてお願いしなくてはならない。この場面では /mnt/factotum
はホストオーナーのものでなくてはならない。誰の名前空間を構成するか?
標準ライブラリnewns(char *user, char *nsfile)
は問題を抱えている。引数 user が実際上働いていないのである(環境変数の設定にしか使われていない)。これは factotum を導入したことに伴う問題点(バグ)である。(Plan 9 にとって本質的なものではなく、ライブラリの修正によって克服可能な問題点である。)現状の
newns
では最初の factotum キーが参照される。例えば bob のキーがkey proto=p9sk1 dom=aichi-u.ac.jp user=alice !password? key proto=p9sk1 dom=aichi-u.ac.jp user=bob !password? key proto=p9sk1 dom=aichi-u.ac.jp user=carol !password?の場合には
newns("bob", nil)
や newns("carol", nil)
が実行されても、生成される名前空間は alice のもの、即ち bob はファイルシステムに対しては alice として認証される。この事は newns()
を利用したアプリケーションを作成するときにセキュリティ上の落とし穴になる。克服の方向は2つ考えられる。1つは引数
user
を名前空間の構築の中で生かす事、もう1つは newns
の引数から user
を捨てる事。後者の場合には user は /dev/user を参照して決定する事になる。筆者は /dev/user
によって決定される名前空間が好ましいと考えるが、これまでの newns() との互換性と将来の柔軟性を重視すれば前者の方が選択されるであろう。su ver.1.4 の中には修正した newns.c
が含まれている。(su
の構成に必要な分だけ含まれており、そのため addns()
は捨てられている。)
コメント: 不必要な柔軟性は管理を困難にしセキュリティ上の落とし穴を作る。他方硬直したシステム設計はニーズに的確に対応できず、現在の UNIX のようにつぎはぎの無理を重ねることになり、やはり管理を困難にしセキュリティ上の落とし穴を作って行くことになる。将来にわたるニーズを見定め、柔軟性のレベルを確定する事はシステム設計の中で最も難しい問題であろう。
cap を手にするには?
ホストオーナーでない bob が alice のプロセスの生成者となるにはホストオーナーから cap を貰わなくてはならない。この場合にはライブラリ関数AuthInfo* auth_userpasswd(char *user, char *passwd)によって、ユーザ名とパスワードを与えて cap が手に入る。(この時には
/mnt/factotum
はホストオーナーのものを使う。) パスワードはコマンド引数などによって明示的に与えてもよいが、factotum から読み取らせてもよい。factotum から読み取らせる場合にはUserPasswd* auth_getuserpasswd(AuthGetkey *getkey, char* fmt, ...)を使う。この時の factotum は
su
を実行するユーザ bob のものである。factotum からパスワードを貰えるためにはキーの形式は proto=pass
である。(この場合には factotum は生のパスワードを記憶しており、それを渡す事ができる。)
注目: cpu コマンドはユーザが factotum 中に
proto=pass
のキーを持たなくても、リモートホストの中にユーザのプロセスを生成する。このメカニズムは筆者は今のところ分かっていない。
getkey とは?
factotum は認証に必要な情報が欠落している場合に会話的にユーザにそれらの情報の入力を求める機能を持っている。そのインターフェースになっているのがgetkey
である。Plan 9 はそのための標準ライブラリ関数 auth_getkey()
を持っている。auth_getkey
は /dev/cons
を使用する。パスワードの入力の際にエコーバックを止めたいからである。しかし /dev/cons
はホストオーナーの所有であり、ホストオーナーだけが使用できる。ホストオーナーでない bob が su を実行し、factotum が auth_getkey
を呼び出したら、ここで致命的なエラーが発生するとこになる。従って su は auth_getkey()
を使わない。su はエコーバックの問題を犠牲にして標準入出力を使用する。その関数 getkey()
が su.c
に含まれている。さて bob が
su aliceを実行すると、su の
getkey()
は bob から受け取った alice の認証情報を、bob の factotum に格納する。それは bob が所有する /mnt/factotum/ctl
に書き出す事によって実現される。このファイルはプロセス factotum による仮想ファイルであり、そのオーナーは factotum の生成者である。従って su は、もしも /mnt/factotum/ctl
が bob のものでないなら、factotum を生成しなくてはならない。bob が
su aliceを実行し、su はホストオーナーから cap を貰って首尾よくプロセス空間としての alice になったとしよう。この時点では su はファイルの名前空間としてはまだ alice にはなっていない。su が alice としてルートファイルシステムをマウントする際に factotum は認証情報が不足しているのを発見したら入力を bob に促す。su は bob が入力した alice の認証情報を bob の
/mnt/factotum/ctl
に書き出そうとすると(既に su のプロセスは alice のものだから)書き込みを拒否される。この問題を回避するために su の
getkey()
ではもう1つの工夫がされている。getkey()
で得られた認証情報を確実に bob の factotum に送り込むために、bob の /mnt/factotum/ctl
を最初に開いてしまい、その fd (ファイルディスクリプタ) を使い続けるのである。
分からない事
ホストオーナー bootes がsu aliceを実行した場合 bootes は alice にパスワード無しに変身できる。即ち
getkey()
を呼び出さない。そのために su の中では次の連続した手順が踏まれている。/srv/factotum
を/mnt
にマウントし
anewns("alice", nil)
を実行する
anewns()
は newns()
の修正版である。もしも 1. を省けば su は現在の /mnt/factotum の中に alice の認証データを探し、存在しなければ
getkey()
を呼び出す。1. が実行される前には既に bootes の
/mnt/factotum
が存在する。1. は新たに bootes の /mnt/factotum
を作成する。既に存在するものと、新たに作成されるものはどこが違うのか? その違いが今の筆者にはよく分からないのである。
su のオプション
su は次のオプシヨンを持っている。多くは実用的と言うよりも教育的なものである。- -D
-
多くの情報を表示してくれる。認証がつまずいた場合のディバッグに使える。
- -n
-
名前空間を変更しない
- -u
-
ユーザ(/dev/user)を変更しない
- -p password
-
パスワードをコマンド引数で与える。コマンド引数はホストオーナーは見えるので、この形式はホストオーナーにだけ許されている。
- -p.
-
パスワードをコマンド引数からではなく実行時に入力する。
- -w
-
su -w user cmd arg ...
の形式で指定し、cmd の実行完了を待たずに su を終える
- -f
-
su を実行するユーザがホストオーナーであり、かつ factotum の認証ドメインにマッチする最初のキーのユーザが {/lib/ndb/auth} に hostid で指定されている場合に[注1]、このオプションによってパスワード無しに任意のユーザに変身できる。su を実行するユーザ名が bootes の場合には su の内部で自動的にこのオプションが設定される。
注1: 次の「信頼できるユーザ」を見よ
信頼できるユーザ
認証サーバの /lib/ndb/auth
認証サーバの /lib/ndb/auth
には「信頼できるユーザ」が定義されている。この内容は標準設定ではhostid=bootes uid=!sys uid=!adm uid=*となっている。これは bootes のキーによって、adm と sys を除く他のユーザを認証することを意味している。もしも
hostid=bootes uid=!sys uid=!adm uid=* hostid=bob uid=aliceとなっていれば、その他に bob は alice に対してのみパスワード無しでファイルサーバに認証されることになる。
注意:
/lib/ndb/auth
の hostid
は行の先頭から書き始めなくてはならない。他方 uid
は先頭から書いてはいけない。
factotum キーの順序
bob がパスワード無しで alice に変身できるためには bob の factotum の最初の行が信頼できるユーザのキーでなくてはならない。例えば bob が su を実行するとして、bob の factotum が
term% fact --rw-r--r-- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/ctl key proto=p9sk1 dom=aichi-u.ac.jp user=bootes !password? key proto=p9sk1 dom=aichi-u.ac.jp user=bob !password? term%の場合には bob は bootes のキーを知っていることになる。そして bootes は
/lib/ndb/auth
の中で hostid で指定されている。従って su の -f
オプションは有効である。 普通は bob のキーは factotum の先頭に置かれる[注2]。term% fact --rw-r--r-- M 11 arisawa arisawa 0 Dec 7 21:30 /mnt/factotum/ctl key proto=p9sk1 dom=aichi-u.ac.jp user=bob !password? key proto=p9sk1 dom=aichi-u.ac.jp user=bootes !password? term%その場合には bob も hostid で指定されていない限り
-f
オプションは有効ではない。
注2: ライブラリ関数
newns()
の抱えている問題のためにホストオーナーのキーは factotum の先頭に置く必要がある。
su によるコマンド実行
su でコマンドを実行する場合のシンタックスはsu [-fnuwD] [- p password] user cmd [arg ... ]
user
は必ず必要である。ユーザ none の場合には user
には none
を指定する。cmd
は実行すべきコマンド名であり、arg はそれに与える引数である。コマンド名には絶対パス、相対パス、あるいは /bin
からの相対パスが指定できる。su ver.1.5 では: 絶対パスは
/
で始まる。相対パスは ./
あるいは ../
で始まる。いずれでもないものは /bin
からの相対パスであると見なされる。例
su none ps su alice me su alice ./foo最後の例では実行ファイル
foo
はカレントディレクトリにあるとしている。
su ver.1.6
2012/09/09
最近になって、
auth/asコマンドが Plan9 の公式配布に含まれているのを発見した。2011 年にリリースされたらしい。これは su と良く似ている。
auth/login + auth/as + auth/noneの組で、su と非常に近いことが出来る。それでも、su は、これらの組よりも多くの事が可能である。
数年前に Plan9 からの派生OSが生まれた。9front と言う。これに関しては別の機会に触れることとする。Plan9 と 9front の表面的な違いであるが、管理者 id が Plan9 の bootes から glenda に変更されている。ver.1.5 までの su は、管理者 id が bootes である事が使われている。そこで ver.1.6 では、glenda でも構わないように書き換えた。また -w オプションを廃止し、さらに、詳しいヘルプメッセージを出すようにした。