Plan 9 第4版になっていくつかの新しい技術が Plan 9 に導入された。それらの代表的なものは
venti
fossil
secstore
cap
である。venti, fossil, secstore に関しては解説済みである。今回は cap に関して解説を加える。
cap はプロセスが他のユーザのプロセスに変身を行う事を可能にする新しい試みである[注1]。capの機能を使うとホストオーナーはプログラムの中で直接にパスワードを扱わなくても変身ができる。cap のような機能は欲しいと思う。例えば筆者がデザインした web サーバ Pegasus は ユーザ web としてサービスを行っている。ホストオーナーが web に変身するためには、Plan 9 の伝統的な方法では web をユーザ登録し、パスワードを設定し、そのパスワードを web に変身するプログラケムに与えなくてはならない。問題は web のパスワードをどこに格納しておくかである。
筆者は web のパスワートを cpu サーバのファイルに格納し、chmod によってアクセス制限をかけた。この方法は UNIX でよく見られ、たぶん UNIX ユーザはそれで満足するであろうが、筆者はパスワードファイルが cpu サーバの名前空間の中にあることが気に入らなかった。何かの管理ミスがパスワードの漏洩に繋がるからである。
当時は cap が既に使えるようになっていた。この方法は cpu サーバから見える名前空間からパスワードファイルを排除するのを可能にしているように思えたが、cap の使い方がよく分からなかったので結局 UNIX 的な方法で済ませたのである。
今回は cap を論じる事ができる。以下に見るように cap の現在の仕様は UNIX のroot 特権に近い。筆者はこのような大きな権限をホストオーナーに与える必要があるのかと疑問に思っている。まあ、時間がたてば本当に必要な権限のレベルがはっきりしてくるであろう。
注1: CAP によってプロセスを異なるオーナーとして生成できる。UNIX と異なり Plan 9 の場合には、ファイルシステムに対する権利者が変更された事を意味しない。(2004/11/02)
cap の使い方
ここでは UNIX の su に良く似た機能を果たす Plan 9 のプログラム su を紹介する。但し管理者だけに実行が許されている。cap の使い方が凝縮されているので、cap を利用したプログラムを作りたい人にとって参考になると思う。
/*
*
* usage: su user
*
* This program illustrate how to use
* /dev/caphash
* /dev/capuse
*
* This program must be run by hostowner
*
* [1] TRY in fscons: open -AW
* - hostowner can become any user without authentication
* - user need not be registered in /adm/users
* - user need not be registered in /mnt/factotum/ctl
* [2] TRY on cpu server with regular open mode of fscons (no -APW)
* - hostowner can become any real user without authentication
* - user need be registered in /adm/users
* - user need not be registered in /mnt/factotum/ctl
*
* Ref:
* - cap(3)
* - sechash(2)
* - /sys/src/cmd/cpu.c
*/
#include <u.h>
#include <libc.h>
#include <mp.h>
#include <libsec.h>
#include <auth.h>
#define ERRLEN 256
static int
waitfor(int pid, char *msg)
{
Waitmsg *w;
while((w = wait()) != nil){
if(w->pid == pid){
strncpy(msg, w->msg, ERRMAX);
free(w);
return 0;
}
free(w);
}
return -1;
}
void main(int argc, char *argv[])
{ int fd, i, n, pid, status;
char *user, *newuser, *key;
uchar hash[SHA1dlen];
AuthInfo ai;
char buf[256];
char msg[ERRLEN];
USED(argc); USED(argv);
argv++;
if(*argv == nil)
sysfatal("usage: su user");
newuser = *argv; // a user you want to be
user = getuser(); // this user must be host owner
switch(pid = rfork(RFNOTEG|RFPROC|RFFDG|RFNAMEG)) {/* assign = */
case -1:
sysfatal("fork");
case 0: /* child process */
break;
default:
close(0);
close(1);
close(2);
status = waitfor(pid, msg);
if(status<0)
sysfatal("waitfor: %r");
exits(nil);
}
/* key must be a null terminated string */
srand(truerand());
for(i = 0; i<10; i++)
sprint(buf+2*i, "%2.2ux", rand());
key = strdup(buf);
snprint(buf, sizeof buf, "%s@%s", user, newuser);
hmac_sha1((uchar*)buf, strlen(buf), (uchar*)key, strlen(key), hash, nil);
/* only hostowner can write to /dev/caphash */
fd = open("/dev/caphash", OWRITE);
if(fd<0)
sysfatal("unable to open /dev/caphash: %r\n");
n = write(fd, hash, sizeof hash);
if(n<0)
sysfatal("unable to write /dev/caphash: %r\n");
close(fd);
ai.cuid = newuser;
snprint(buf, sizeof buf, "%s@%s@%s", user, newuser, key);
ai.cap = buf;
/* - auth_chuid writes ai.cap internally to /dev/cap *
* look /sys/src/libauth/auth_chuid.c *
* - you must call auth_chuid within 1 min *
* after you write to caphash */
if(auth_chuid(&ai, nil)<0)
sysfatal("could't become the user:%r");
putenv("prompt", "su# ");
execl("/bin/rc", "rc", "-i", nil);
}
望ましい姿
su を実行してみれば分かると思うが、hostowner の権限が UNIX 並みに強い。これはこれまでに Plan 9 が守って来たシステムコンセプト「パスワードを知っているものだけがそのユーザになる事ができる」に反する。筆者はこのコンセプトを守って欲しい。Plan 9 第4版は secstore と factotum を持っており、これらの組み合わせによって、パスワードを使いながらシステムエージェントとしての仮想ユーザに安全に変身する仕組みはできるはずである。(筆者は当然そのようになっていると思っていたのだが、現在のリリースのバグであろうか?)
問題の起源
2004/10/25 追加
Plan 9 は、これまでに Plan 9 が守って来たシステムコンセプト「パスワードを知っているものだけがそのユーザになる事ができる」を捨てたのであろうか?
su が可能になったメカニズムを探っていくと、OS 自体の仕組みとしてはそうではないことが分かる。問題は factotum にあるのだ。
factotum は認証代理人である。Plan 9 のユーザは認証を受けたホストに対する認証情報を factotum に渡す。これは自動的に行われるのでユーザは意識しない。また、cpu サーバが立ち上がるときに factotum は bootes のパスワードの入力を要求し、この情報が bootes の factotum に渡される。この事は
cat /mnt/factotum/ctl
で確認できる。
従って cpu サーバが立ち上がってしまえば cpu サーバの owner である bootes はパスワードを入力しなくても factotum のお陰で認証サーバにアクセスできる。この能力が su を可能にしているのである[注意1]。これは便利ではあるが、cpu サーバで動いている bootes のプロセスがこの能力を抱えている事になる。
注意1: factotum が認証サーバのパスワードを見ていると言っているのではない。
cpu サーバの bootes の factotum から bootes のバスワードを削除すればどうなるか? su はもはや威力を失う。しかし、Plan 9 システムの現在の版ではトラブルをもたらす。例えば端末から cpu コマンドで cpu サーバにアクセスできなくなる。認証に cap を利用している cpu コマンドのようなプログラムが動作しなくなるのである。
筆者は bootes の factotum が cpu サーバに無くてもよいようにシステムが動作するようにすべきであると思うが、皆さんはどう思いますか ?
su ver.1.2
2004/11/04 訂正
2004/11/02 改訂
2004/10/29 追加
su ver.1.2
su の実用的な版が http:/netlib/cmd/ に置かれている。この su はホストオーナーでないユーザが他のユーザに変身できるように、パスワードを使えるようになっている。その場合には
adom=aichi-u.ac.jp
su -p xxxxx alice
のように使う。環境変数 adom はパスワードを使うときに必要になる環境変数で認証ドメインを与える。aichi-u.ac.jp は筆者のシステムの認証ドメインで、もちろんシステム毎に違う。xxxxx は alice のパスワード。
su を使うと Plan 9 の認証に対する考え方が良く分かる。
注意: 29 日版の su (ver.1.0) は問題点を抱えていた。パスワードを与えた時のファイルシステムに対する十分な認証能力を持つていなかった。他方 11月02版の su (ver.1.1) は cpu サーバにおける bootes の能力を低めていた。今回の su は大丈夫だと思われる。
UNIX
ユーザ alice はプロセスのオーナーでもありファイルのオーナーでもある。UNIX ではこの二つを区別する必要はなく同一のユーザ名を持っている。プロセスのオーナーである alice が作成するファイルは alice の所有物である。そしてプロセスのオーナーとなる権利が与えられれば自動的にファイルのオーナーとなる権利も与えられるのである。この考え方は一見すると当然のように思えるが、分散ファイルシステムではうまく働かない[注3]。
Plan 9 ではプロセスのオーナーとなる権利とファイルのオーナーとなる権利は別のものであると考えられている。そのために Plan 9 ではファイルシステム毎にユーザが登録されるのである。小さなシステムの中でユーザ登録されれば両方の権利が与えられる。その場合にはユーザ alice はプロセスのオーナーとしての alice であり、ファイルのオーナーとしての alice でもある。しかしこの同一性は必ず守られるわけではない。プロセスのオーナー alice がファイルのオーナー carol として活動することもありえるのである。
私は誰?
プロセスの owner
プロセスのオーナーは
ps | grep ps
を実行してみれば直ちに分かる。これはまた /dev/user の値でもある。プロセスのオーナー alice によって生成された仮想ファイルシステムは alice にファイルを提供する。例えば alice が ramfs を実行すれば ramfs に作成されるファイルは全てが alice のファイルとなる。alice が factotum を実行すれば、その factotum は alice のために仮想ファイル /mnt/factotum を提供する、と言った具合である。
ファイルの owner
ファイルの作成者を調べるには chmod 777 のディレクトリを作成し、そこに作成されたファイルのオーナーを見ればよい。(この方法はちょっと面倒だが、筆者はこれ以外の方法を知らない。)
su で遊んでみれば、alice のプロセスによって作成されたファイルが必ずしも alice のファイルを作成しないことが分かるはずである[注4]。
注4: su に実行オプション -n を与えればファイルに関してはそのままである。
認証の基本的な考え方
プロセスの認証
プロセスのオーナーを変更するにはホストオーナーにお願いする。これが cap である。従ってホストオーナーは自由にプロセスのオーナーを変更できる。ホストオーナーでないユーザが他のユーザに変身するにはそのユーザのパスワードを知っている事を認証サーバに示し、認証サーバから貰った認証(cap)を介してホストオーナーにお願いすればホストオーナーは許可してくれる。
以下の説明では Plan 9 システムのホストオーナーを bootes とする。また alice と bob は一般のユーザを代表している。alice と bob はシステムのホストオーナー bootes に一致していてもよい。
実験結果の合理性を判定する基準はセキュリティと使いやすさである。この2つの関係は一般的には一方を立てれば他方が立たなくなるのだが、Plan 9 では両方をうまくやっていることが分かるであろう。
認証のいらない Plan 9 端末
Plan 9 端末が認証なしに動作するのは自分自身のファイルシステムによって動いている場合だけである。この場合にはカーネルは 9pcdisk (kfs ベース) あるいは 9pcf (fossil ベース) が使用される。
Plan 9 にとってディスクベースの端末は個人利用あるいは完全な信頼関係のある小さなグループの利用を想定している。ここには誤操作を防止する機能はあってもセキュリティは存在しない。
筆者の家庭の fossil の設定は open -AW モード、即ち認証はいらず、chmod は誰でもどのファイルに対してもかけられると言う甘いモードで動いている。信頼できる環境ではこれが使いやすい。以下の実験は 9pcf の場合には、このモードでのものである。
bob をPlan 9 端末のホストオーナーとする。bob は Plan 9 システムのユーザの一人でもある。
su alice
結果: bob による su はパスワードなしでどのユーザにも変身を可能にする。プロセスに対してもファイルに対しても alice となる。
execl: permission denied
alice は noworld ユーザである、あるいは /lib/ndb/auth で認証が禁止されている
execl: '/bin/rc' does not exist
alice は /usr/alice/lib/profile を持たない
おわりに
筆者が su の能力とその限界に関心を持ったのは、将来における Pegasus の webdav のサポートのためである。安全に運用し、かつ認証を受けたユーザに変身したプロセスによってファイルへのアクセスを行う必要がある。安全に運用するためには Pegasus に bootes の特権を与えるわけにはいなかい。もっと弱いユーザである、例えば現在の Pegasus が行っている仮想ユーザ web の下で実行が開始され、パスワードによってそのユーザに変身するメカニズムが望ましい。これは UNIX ではなし得ないが Plan 9 の下では可能である。
筆者は su の能力とその限界を調べて来たが、その過程で多くの混乱した議論を行ってしまった。様々な su を試してみて、様々な異なった結果を得る。ある部分の改良の結果、他の部分の改悪を招いてしまったのである。目標とするのは最大の能力を発揮する su である。その意味で su ver.1.1 の能力表に問題があることを山梨さんからのメールで判明しました。感謝します。