新山の発表内容
set no_fork set stdout
基本的には、あるツールを daemontools-aware にするのは さほどむずかしくない。
新山の註釈つきソースを使用:
djb 特有の関数:
研究室の学生に好き勝手に CGI をつかわせたい。 でも publicfile/shttpd がいい。shttpd はいつも決めうちで 同じ cgi しか実行してくれないという欠点がある。
しかし shttpd が環境変数 PATH_INFO をセットするので、これを見て apache の suexec のようなことをやってみた。psuexec という setuid root されたプログラムを実行させ、各ユーザの cgi に分岐させるのだ。
けれどもこれは注意する必要がある。 それにリソースを使われすぎないようリミットをかけねばならない。
にしてください (taint check)。#!/bin/perl -T #!/bin/jperl -T
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); }
あるいは ディレクトリ は cdb?
djb がネットワークプロトコルを作ったら?