2001/4/26 djbtools勉強会

back


新山の発表内容


tcpserver/daemontools にはどれくらいのデーモンが対応しているか?

SMTP, DNS
これらのアプリケーションについては sendmail, bind はそもそも最初から眼中にないので無視。
WWW/FTP
Apache はログをとるのに multilog が使える。
後日追加: ほかにも WN は ok だった (前野さん)。
あと thttpd も ok。ただしパッチつくるのが結構大変。
proftpd, wu-ftpd は inetd 経由だから tcpserver 可は簡単。
https は知らない。
後日追加: IP 監視ツール、パケットリピータ
ippl は ok だ (加藤さん)。
Stone も ok だ (彦坂さん)。
iplog-2.2.3 (河野さん)
       set no_fork
       set stdout
       

snort-1.7 (塚本さん)
NTP
ntpd 4.0.99k23 は -d をつければ foreground で動く (加藤さん、森下さん)。
xntpd ならパッチあり。
Alpha のマシンでは clockspeed がない。
SSH
OpenSSH ならパッチあり。商用 SSH を改造するのはまずい。
後日追加: RealServer (としさん)
realsvr ./Bin/rmserver rmserver.cfg -m 32 > rmboot.log
LPR
LPRngはフォアグラウンドで動かせる。
SOCKS
socks5 --foreground --stderr
Squid
squid -N
DHCPサーバ
isc-dhcp なら dhcpd -d -f
NFS
linux nfsd, mountd なら ok
でも最近は knfsd か。
syslog/klog
logkit, gluelog, syslogread
Samba
Postgres
rlogind
identd

基本的には、あるツールを daemontools-aware にするのは さほどむずかしくない。


supervise, svc のソースを読む

新山の註釈つきソースを使用:

djb 特有の関数:


psuexec のこころみ

研究室の学生に好き勝手に CGI をつかわせたい。 でも publicfile/shttpd がいい。shttpd はいつも決めうちで 同じ cgi しか実行してくれないという欠点がある。

しかし shttpd が環境変数 PATH_INFO をセットするので、これを見て apache の suexec のようなことをやってみた。psuexec という setuid root されたプログラムを実行させ、各ユーザの cgi に分岐させるのだ。

けれどもこれは注意する必要がある。 それにリソースを使われすぎないようリミットをかけねばならない。

(一般ユーザ向けに書いた説明)

  1. 実行できるのは /export/cgi/home/あなたの名前/ 以下にある cgi スクリプトだけです。これ以外のディレクトリに あるスクリプトは実行できません。
  2. /export/cgi/home/あなたの名前/ 以下のディレクトリで 外から見えるのは実行する cgi スクリプトだけです。html ファイルを このディレクトリに置いても見えません。
  3. 実行する CGI スクリプトが置いてあるディレクトリの パーミッションは 0700 である必要があります。
  4. CGI スクリプトの名前は「.cgi」で終わっている必要があります。
  5. CGI スクリプトの所有者と所有グループはあなたと 一致している必要があります。
  6. 以上のような規則に合致せず CGI の実行に失敗したときも、 web サーバは「file does not exist (n)」という つれないメッセージしか返しません。これは外から見た人に ヒントを与えないようにするためです。この数値 n の 意味は、下の「CGI エラー番号表」を見てください。
  7. CGI スクリプトは、このディレクトリ以外にあるサーバ上の ファイル (www ページ含む) にアクセスすることはできません。
  8. 環境変数に入る値は Apache の場合とすこし違うので注意してください。 以下の「CGI プロトコル」の節を参照。
  9. 同一ユーザの CGI スクリプトは同時に 10プロセスまでしか走りません。
  10. 同一ユーザの CGI スクリプトが一度に開けるファイルは合計 20個までです。
  11. ひとつの CGI スクリプトが使えるメモリサイズは最大 6MBytes までです。 (これは様子を見て、必要なようなら増やします。)
  12. ひとつの CGI スクリプトが扱えるファイルの大きさは 1ファイルにつき 最大 1MBytes までです。
  13. perl, jperl では、モジュールおよびネットワーク機能は使えません。
  14. perl, jperl を使うときは、スクリプトの最初の1行目を
           #!/bin/perl -T
           #!/bin/jperl -T
           
    にしてください (taint check)。
  15. すでに出まわっている CGI スクリプトを使っているからといって 安心はできないことをよく覚えておいてください。そういうスクリプトは あるときセキュリティホールが見つかると一斉に攻撃されます。
  16. CGI の動作はすべて記録されます。

psuexec のソース(抜粋)

int main(int argc, char* argv[], char* envp[])
{
// 変数定義は略
    http = 0;
    proto = getenv("SERVER_PROTOCOL");
    if (proto) {
	if (!strncasecmp(proto, "http/1.0", 8))
	    http = 1;
	if (!strncasecmp(proto, "http/1.1", 8))
	    http = 2;
    }
    
// パスを取得・ながすぎたらもうダメ
    p1 = getenv("PATH_INFO");
    if (!p1)
	{ fprintf(stderr, PROGNAME "PATH_INFO isn't set.\n"); ab(-1); }

    if (BUFFSIZE < strlen(p1)) {
	fprintf(stderr, PROGNAME "PATH_INFO too long: %d\n", strlen(p1));
	ab(-2);
    }
// プレフィクスが違ってらダメ
    if (strncmp(p1, PATH_PREFIX, STRLEN(PATH_PREFIX))) {
	fprintf(stderr, PROGNAME "PATH_INFO malformed.\n");
	ab(-3);
    }
    if (strlen(p1) < 4 ||
	strncmp(p1+strlen(p1)-STRLEN(CGI_SUFFIX), 
		CGI_SUFFIX, STRLEN(CGI_SUFFIX))) {
	fprintf(stderr, PROGNAME "illegal extension: %s\n", p1);
	ab(-4);
    }
    p1 += STRLEN(PATH_PREFIX);
    
    for(i = 0; i < 8 && *p1 && *p1 != '/'; i++)
	username[i] = *(p1++);
    username[i] = '\0';
    sprintf(s, HOME_DIR "/%s", username);
    
// そのユーザのディレクトリがなかったらダメ
    if (i == 0 || stat(s, &buf)) {
	fprintf(stderr, PROGNAME "not found: %s\n", s);
	ab(-5);
    }
    
// そのディレクトリがそのユーザの所有でかつ uid,gid が 1000以上
    if (buf.st_uid < UID_MIN || buf.st_gid < GID_MIN) {
	fprintf(stderr, PROGNAME "illegal uid or gid.\n");
	ab(-6);
    }
// 他人から見えてたらダメ
    if ((buf.st_mode & 0777) != (S_IRUSR | S_IWUSR | S_IXUSR)) {
	fprintf(stderr, PROGNAME "illegal directory permission: %x\n", 
		buf.st_mode);
	ab(-7);
    }

// そのディレクトリのuid,gidになる
    if (setregid(buf.st_gid, buf.st_gid) ||
	setreuid(buf.st_uid, buf.st_uid)) {
	fprintf(stderr, PROGNAME "can't change user/group.\n");
	ab(-8);
    }

(中略)
// そのディレクトリに chdir する
    if (chdir(s)) {
	fprintf(stderr, PROGNAME "can't chdir to %s\n", s);
	ab(-9);
    }

// プログラムがあって、所有者か?
    base++;
    if (stat(base, &buf)) {
	fprintf(stderr, PROGNAME "not found: %s\n", base);
	ab(-10);
    }
    if (buf.st_uid != getuid() || 
	buf.st_gid != getgid()) {
	fprintf(stderr, PROGNAME "not owner: %s\n", base);
	ab(-11);
    }
// ふつうのファイルか?
    if (! S_ISREG(buf.st_mode)) {
	fprintf(stderr, PROGNAME "illegal file type: %s\n", base);
	ab(-12);
    }
    setenv("PATH", CONST_PATH, 1);
    execv(base, argv);
    i = errno; ab(i);
}

djb が UNIX を作ったら?

djb がネットワークプロトコルを作ったら?


Last modified: Wed Sep 26 18:02:59 2001
Yusuke Shinyama