/mnt/factotum
かそれとも /mnt/term/mnt/factotum
か?
/mnt/factotum
か?
/lib/ndb/auth
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 は同じとは限らない。
#!/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 の内容
である。/usr/none/tmp
に生成する。このディレクトリは Plan 9 の標準設定ではユーザ none 以外の書き込めないのでchmod 777 /usr/none/tmpを実行しておく必要がある。
/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
を用意しました。次のように使います。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%
注:
send
」で送り、ctl-D で削除されます。複数のキーを選択できます。send
」で送り、ctl-D で追加されます。複数のキーを選択できます。/mnt/factotum/ctl
への書き込みによってキーの削除や追加を行いますが、場合によっては /mnt/term/mnt/factotum/ctl
にアクセスする必要があり、オプションの -d
や -a
に続く文字(1または2)によってどちらであるかを選択できます。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
は 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 が仮定される。
/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 や 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 |
/lib/ndb/auth
でその権限が与えられているからである。
/mnt/factotum
かそれとも /mnt/term/mnt/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()
を利用したアプリケーションを作成するときにセキュリティ上の落とし穴になる。user
を名前空間の構築の中で生かす事、もう1つは newns
の引数から user
を捨てる事。後者の場合には user は /dev/user を参照して決定する事になる。筆者は /dev/user
によって決定される名前空間が好ましいと考えるが、これまでの newns() との互換性と将来の柔軟性を重視すれば前者の方が選択されるであろう。su ver.1.4 の中には修正した newns.c
が含まれている。(su
の構成に必要な分だけ含まれており、そのため addns()
は捨てられている。)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 は生のパスワードを記憶しており、それを渡す事ができる。)proto=pass
のキーを持たなくても、リモートホストの中にユーザのプロセスを生成する。このメカニズムは筆者は今のところ分かっていない。
getkey
である。Plan 9 はそのための標準ライブラリ関数 auth_getkey()
を持っている。auth_getkey
は /dev/cons
を使用する。パスワードの入力の際にエコーバックを止めたいからである。しかし /dev/cons
はホストオーナーの所有であり、ホストオーナーだけが使用できる。ホストオーナーでない bob が su を実行し、factotum が auth_getkey
を呼び出したら、ここで致命的なエラーが発生するとこになる。従って su は auth_getkey()
を使わない。su はエコーバックの問題を犠牲にして標準入出力を使用する。その関数 getkey()
が su.c
に含まれている。su aliceを実行すると、su の
getkey()
は bob から受け取った alice の認証情報を、bob の factotum に格納する。それは bob が所有する /mnt/factotum/ctl
に書き出す事によって実現される。このファイルはプロセス factotum による仮想ファイルであり、そのオーナーは factotum の生成者である。従って su は、もしも /mnt/factotum/ctl
が bob のものでないなら、factotum を生成しなくてはならない。su aliceを実行し、su はホストオーナーから cap を貰って首尾よくプロセス空間としての alice になったとしよう。この時点では su はファイルの名前空間としてはまだ alice にはなっていない。su が alice としてルートファイルシステムをマウントする際に factotum は認証情報が不足しているのを発見したら入力を bob に促す。su は bob が入力した alice の認証情報を bob の
/mnt/factotum/ctl
に書き出そうとすると(既に su のプロセスは alice のものだから)書き込みを拒否される。getkey()
ではもう1つの工夫がされている。getkey()
で得られた認証情報を確実に bob の factotum に送り込むために、bob の /mnt/factotum/ctl
を最初に開いてしまい、その fd (ファイルディスクリプタ) を使い続けるのである。
su aliceを実行した場合 bootes は alice にパスワード無しに変身できる。即ち
getkey()
を呼び出さない。そのために su の中では次の連続した手順が踏まれている。/srv/factotum
を /mnt
にマウントしanewns("alice", nil)
を実行するanewns()
は newns()
の修正版である。getkey()
を呼び出す。/mnt/factotum
が存在する。1. は新たに bootes の /mnt/factotum
を作成する。既に存在するものと、新たに作成されるものはどこが違うのか? その違いが今の筆者にはよく分からないのである。
/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
は先頭から書いてはいけない。
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
オプションは有効ではない。
newns()
の抱えている問題のためにホストオーナーのキーは factotum の先頭に置く必要がある。
su [-fnuwD] [- p password] user cmd [arg ... ]
user
は必ず必要である。ユーザ none の場合には user
には none
を指定する。cmd
は実行すべきコマンド名であり、arg はそれに与える引数である。コマンド名には絶対パス、相対パス、あるいは /bin
からの相対パスが指定できる。/
で始まる。相対パスは ./
あるいは ../
で始まる。いずれでもないものは /bin
からの相対パスであると見なされる。su none ps su alice me su alice ./foo最後の例では実行ファイル
foo
はカレントディレクトリにあるとしている。
最近になって、
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 オプションを廃止し、さらに、詳しいヘルプメッセージを出すようにした。