永井@知能.九工大です. From: matz / ruby-lang.org (Yukihiro Matsumoto) Subject: [ruby-dev:20681] Re: frozen ThreadGroup Date: Tue, 15 Jul 2003 16:46:40 +0900 Message-ID: <1058255237.819358.15871.nullmailer / picachu.netlab.jp> > |う゛... > |これって,もしかして例の portable な user id / group id の > |コントロールメソッドを目指そうという件でしょうか? > |だとしたらごめんなさい. > |周囲からの要望もないし,なんだか一人で騒いでいるだけという気がして > |完全に放置してました. > |確か,メソッド名がまつもとさんの好みに合わないということと > |本当にあのメソッドセットで OK なのかということとが問題で > |そのままになっていたと思います. > です。私はuser id/gruop idを操作する欲求も経験もありませんか > ら、機能の善し悪しについては判断できませんでした。が、名前の > 善し悪しについては判断するという。 とりあえず,メソッド名変更と CVS head への適用を行ってみました. メソッド名はあくまでも案ですので,修正提案歓迎です. まずは,仕様のメモ書きを示して,末尾にパッチを添えます. お試しいただけると幸いです. # 本当はサンプルまで用意しておくといいのでしょうけど... =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= [ruby-dev:16609] の定義に基づく [ruby-dev:16883] の patch を CVS head に適用したもの (メソッド名は短く変更). getgroups/setgroups は Process.group/group= で実装済なのでそのまま. initgroups を Process.initgroups として追加 module Process::ID_Syscall 単なるシステムコールの直接実装 単純な操作がどうしても欲しい人のためのサービス提供 ポータビリティは期待できない getuid geteuid getgid getegid setuid setgid setruid setrgid seteuid setegid setreuid setregid setresuid setresgid module Process::UserID ユーザ ID 操作 [patch] [別名候補] [簡易説明] rid real 実 ID の獲得 eid eid, effective 実効 ID の獲得 to id=, set 指定 ID への完全移行 eid= effective= 実効 ID の設定 ex_reid ex_re, re_exchange, exchange, exchange_re 実/実効 ID の交換 ex_reid? ex_re?, re_exchangeable?, exchangable? 実/実効 ID の交換可否 has_sid? has_saved? 保存 ID の有無 switch toggle 権限の一時的な変更 module Process::GroupID グループ ID 操作 メソッド集合は module Process::UserID と同じ ============================================================ Process::UserID.rid [Process::GroupID.rid] 仕様 : 現在の実ユーザ ID を得る ============================================================ Process::UserID.eid [Process::GroupID.eid] 仕様 : 現在の実効ユーザ ID を得る ============================================================ Process::UserID.to(id) [Process::GroupID.to(id)] 仕様 : 実/実効/保存ユーザ ID のすべてを変更して, 他のユーザとしての権限を放棄する. 成功時は id を返す. 完全放棄できない場合(一部ユーザ ID の変更ができない場合)は 例外を発生する. 例外の発生時に,このメソッドを呼び出す前の各ユーザ ID の値が 保存されているかどうかは保証されない. 注意 : 以前の Process.uid= とは互換性がないことに注意. setreuid(id,-1) によって実装されていたものを用いていたケースは, 例えば次のように書き換える必要があるだろう. Process::UserID.ex_reid # (r,e,s)==(u1,u2,??) ==> (u2,u1,??) Process::UserID.eid = id # (u2,u1,??) ==> (u2,id,??) Process::UserID.ex_reid # (u2,id,??) ==> (id,u2,??) ============================================================ Process::UserID.eid=(id) [Process::GroupID.eid=(id)] 仕様 : 実効ユーザ ID を変更する. 成功時は id を返す. 保存ユーザ ID の変化は,Process::UserID.ex_reid? が true かどうかで決まる. 定義されない環境では,保存ユーザ ID は変化しない. 定義されている環境では,id が実ユーザ ID と異なる値に設定された場合, 保存ユーザ ID は新しい実効ユーザ ID の値に設定される. 設定できない場合は例外を発生する. ============================================================ Process::UserID.ex_reid [Process::GroupID.ex_reid] 仕様 : 実ユーザ ID と実効ユーザ ID とを入れ換える. 保存ユーザ ID は新しい実効ユーザ ID と同じになる. 環境依存により実装されていない場合は例外を発生する. 戻り値としては,新しい実効ユーザ ID を返す. ============================================================ Process::UserID.ex_reid? [Process::GroupID.ex_reid?] 仕様 : 実ユーザ ID と実効ユーザ ID との入れ換えが可能な環境かどうか (Process::UserID.ex_reid が実装されているか) を真偽値で返す. 入れ換え可能なら true を返す. ============================================================ Process::UserID.has_sid? [Process::GroupID.has_sid?] 仕様 : 保存ユーザ ID を持つ環境かどうかを真偽値で返す. 保存ユーザ ID を持つなら true を返す. ただし,保存ユーザ ID の有無を明確に判定できない環境では, この値は推定値である (誤りの可能性もある) ことに注意が必要. 現在は,次の条件のいずれかが満足される場合に 保存ユーザ ID を持つものと判定する. ・setresuid を持つ ・seteuid を持つ ・_POSIX_SAVED_IDS が真として定義されている ============================================================ Process::UserID.switch [Process::GroupID.switch] Process::UserID.switch { ... } [Process::GroupID.switch { ... }] 仕様 : ユーザ権限を(一時的に)変更する. ブロックが与えられたならば,権限を移行してそのブロックを実行した後, 元の権限に復帰する. 途中で実/実効/保存ユーザ ID を変更しなければ, ブロックを与えない呼び出しを二度実行することで, 権限の一時的変更と元の権限への復帰とが可能となる. ブロックが与えられない場合の戻り値は元に戻せる(変更できる) ID 値, ブロックが与えられた場合の戻り値はブロックの値を返す. 実/実効/保存ユーザ ID が二つのユーザ権限を移行できる状態でなければ 例外を発生する (変更できるのは実ユーザ ID の権限へか, 保存ユーザ ID の権限へかのいずれかである). ブロックを与えた際に,ブロック内でユーザ ID が変更されたなどの理由で 元の権限に復帰できない場合も例外を発生する. 保存ユーザ ID を持たない環境では,このメソッドの実行によって 実ユーザ ID が変化する (ブロックを与えた場合はブロック実行中のみ). ============================================================ =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Index: configure.in =================================================================== RCS file: /src/ruby/configure.in,v retrieving revision 1.179 diff -u -r1.179 configure.in --- configure.in 11 Jul 2003 13:37:22 -0000 1.179 +++ configure.in 16 Jul 2003 03:45:50 -0000 @@ -371,9 +371,9 @@ truncate chsize times utimes fcntl lockf lstat symlink readlink\ setitimer setruid seteuid setreuid setresuid setproctitle\ setrgid setegid setregid setresgid pause lchown lchmod\ - getpgrp setpgrp getpgid setpgid getgroups setgroups getpriority getrlimit\ - dlopen sigprocmask sigaction _setjmp setsid telldir seekdir fchmod\ - mktime timegm cosh sinh tanh) + getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\ + getpriority getrlimit dlopen sigprocmask sigaction _setjmp\ + setsid telldir seekdir fchmod mktime timegm cosh sinh tanh) AC_STRUCT_TIMEZONE AC_CACHE_CHECK(for struct tm.tm_gmtoff, rb_cv_member_struct_tm_tm_gmtoff, [AC_TRY_COMPILE([#include <time.h>], Index: process.c =================================================================== RCS file: /src/ruby/process.c,v retrieving revision 1.73 diff -u -r1.73 process.c --- process.c 15 Jul 2003 07:35:10 -0000 1.73 +++ process.c 16 Jul 2003 03:45:52 -0000 @@ -1158,6 +1158,66 @@ } static VALUE +p_sys_setuid(obj, id) + VALUE obj, id; +{ +#if defined HAVE_SETUID + if (setuid(NUM2INT(id)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE +p_sys_setruid(obj, id) + VALUE obj, id; +{ +#if defined HAVE_SETRUID + if (setruid(NUM2INT(id)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE +p_sys_seteuid(obj, id) + VALUE obj, id; +{ +#if defined HAVE_SETEUID + if (seteuid(NUM2INT(id)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE +p_sys_setreuid(obj, rid, eid) + VALUE obj, rid, eid; +{ +#if defined HAVE_SETREUID + if (setreuid(NUM2INT(rid),NUM2INT(eid)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE +p_sys_setresuid(obj, rid, eid, sid) + VALUE obj, rid, eid, sid; +{ +#if defined HAVE_SETRESUID + if (setresuid(NUM2INT(rid),NUM2INT(eid),NUM2INT(sid)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE proc_getuid(obj) VALUE obj; { @@ -1177,7 +1237,7 @@ if (setreuid(uid, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETRUID if (setruid(uid) < 0) rb_sys_fail(0); -#else +#elif defined HAVE_SETUID { if (geteuid() == uid) { if (setuid(uid) < 0) rb_sys_fail(0); @@ -1186,10 +1246,203 @@ rb_notimplement(); } } +#else + rb_notimplement(); #endif return INT2FIX(uid); } +static int SAVED_USER_ID; + +static VALUE +p_uid_set_to(obj, id) + VALUE obj, id; +{ + extern int errno; + int uid; + + uid = NUM2INT(id); + + if (geteuid() == 0) { /* root-user */ +#if defined(HAVE_SETRESUID) + if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; +#elif defined HAVE_SETUID + if (setuid(uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; +#elif defined HAVE_SETREUID + if (getuid() == uid) { + if (SAVED_USER_ID == uid) { + if (setreuid(-1, uid) < 0) rb_sys_fail(0); + } else { + if (uid == 0) { /* (r,e,s) == (root, root, x) */ + if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0); + if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0); + SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */ + if (setreuid(uid, uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + } else { + if (setreuid(0, -1) < 0) rb_sys_fail(0); + SAVED_USER_ID = 0; + if (setreuid(uid, uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + } + } + } else { + if (setreuid(uid, uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + } +#elif defined HAVE_SETRUID && defined HAVE_SETEUID + if (getuid() == uid) { + if (SAVED_USER_ID == uid) { + if (seteuid(uid) < 0) rb_sys_fail(0); + } else { + if (uid == 0) { + if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0); + SAVED_USER_ID = 0; + if (setruid(0) < 0) rb_sys_fail(0); + } else { + if (setruid(0) < 0) rb_sys_fail(0); + SAVED_USER_ID = 0; + if (seteuid(uid) < 0) rb_sys_fail(0); + if (setruid(uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + } + } + } else { + if (seteuid(uid) < 0) rb_sys_fail(0); + if (setruid(uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + } +#else + rb_notimplement(); +#endif + } else { /* unprivileged user */ +#if defined(HAVE_SETRESUID) + if (setresuid((getuid() == uid)? -1: uid, + (geteuid() == uid)? -1: uid, + (SAVED_USER_ID == uid)? -1: uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; +#elif defined HAVE_SETREUID + if (SAVED_USER_ID == uid) { + if (setreuid((getuid() == uid)? -1: uid, + (geteuid() == uid)? -1: uid) < 0) rb_sys_fail(0); + } else if (getuid() != uid) { + if (setreuid(uid, (geteuid() == uid)? -1: uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + } else if (/* getuid() == uid && */ geteuid() != uid) { + if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + if (setreuid(uid, -1) < 0) rb_sys_fail(0); + } else { /* getuid() == uid && geteuid() == uid */ + if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0); + if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + if (setreuid(uid, -1) < 0) rb_sys_fail(0); + } +#elif defined HAVE_SETRUID && defined HAVE_SETEUID + if (SAVED_USER_ID == uid) { + if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0); + if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0); + } else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) { + if (getuid() != uid) { + if (setruid(uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + } else { + if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + if (setruid(uid) < 0) rb_sys_fail(0); + } + } else if (/* geteuid() != uid && */ getuid() == uid) { + if (seteuid(uid) < 0) rb_sys_fail(0); + if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; + if (setruid(uid) < 0) rb_sys_fail(0); + } else { + errno = EPERM; + rb_sys_fail(0); + } +#elif defined HAVE_SETEUID + if (getuid() == uid && SAVED_USER_ID == uid) { + if (seteuid(uid) < 0) rb_sys_fail(0); + } else { + errno = EPERM; + rb_sys_fail(0); + } +#elif defined HAVE_SETUID + if (getuid() == uid && SAVED_USER_ID == uid) { + if (setuid(uid) < 0) rb_sys_fail(0); + } else { + errno = EPERM; + rb_sys_fail(0); + } +#else + rb_notimplement(); +#endif + } + return INT2FIX(uid); +} + +static VALUE +p_sys_setgid(obj, id) + VALUE obj, id; +{ +#if defined HAVE_SETGID + if (setgid(NUM2INT(id)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE +p_sys_setrgid(obj, id) + VALUE obj, id; +{ +#if defined HAVE_SETRGID + if (setrgid(NUM2INT(id)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE +p_sys_setegid(obj, id) + VALUE obj, id; +{ +#if defined HAVE_SETEGID + if (setegid(NUM2INT(id)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE +p_sys_setregid(obj, rid, eid) + VALUE obj, rid, eid; +{ +#if defined HAVE_SETREGID + if (setregid(NUM2INT(rid),NUM2INT(eid)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + +static VALUE +p_sys_setresgid(obj, rid, eid, sid) + VALUE obj, rid, eid, sid; +{ +#if defined HAVE_SETRESGID + if (setresgid(NUM2INT(rid),NUM2INT(eid),NUM2INT(sid)) != 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return Qnil; +} + static VALUE proc_getgid(obj) VALUE obj; @@ -1208,9 +1461,9 @@ if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETREGID if (setregid(gid, -1) < 0) rb_sys_fail(0); -#elif defined HAS_SETRGID +#elif defined HAVE_SETRGID if (setrgid((GIDTYPE)gid) < 0) rb_sys_fail(0); -#else +#elif defined HAVE_SETGID { if (getegid() == gid) { if (setgid(gid) < 0) rb_sys_fail(0); @@ -1219,6 +1472,8 @@ rb_notimplement(); } } +#else + rb_notimplement(); #endif return INT2FIX(gid); } @@ -1302,6 +1557,21 @@ } static VALUE +proc_initgroups(obj, uname, base_grp) + VALUE obj, uname, base_grp; +{ +#ifdef HAVE_INITGROUPS + if (initgroups(StringValuePtr(uname), (gid_t)NUM2INT(base_grp)) != 0) { + rb_sys_fail(0); + } + return proc_getgroups(obj); +#else + rb_notimplement(); + return Qnil; +#endif +} + +static VALUE proc_getmaxgroups(obj) VALUE obj; { @@ -1322,6 +1592,138 @@ return INT2FIX(maxgroups); } +static int SAVED_GROUP_ID; + +static VALUE +p_gid_set_to(obj, id) + VALUE obj, id; +{ + extern int errno; + int gid; + + gid = NUM2INT(id); + + if (geteuid() == 0) { /* root-user */ +#if defined(HAVE_SETRESGID) + if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; +#elif defined HAVE_SETGID + if (setgid(gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; +#elif defined HAVE_SETREGID + if (getgid() == gid) { + if (SAVED_GROUP_ID == gid) { + if (setregid(-1, gid) < 0) rb_sys_fail(0); + } else { + if (gid == 0) { /* (r,e,s) == (root, y, x) */ + if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0); + if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */ + if (setregid(gid, gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + } else { /* (r,e,s) == (z, y, x) */ + if (setregid(0, 0) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = 0; + if (setregid(gid, gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + } + } + } else { + if (setregid(gid, gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + } +#elif defined HAVE_SETRGID && defined HAVE_SETEGID + if (getgid() == gid) { + if (SAVED_GROUP_ID == gid) { + if (setegid(gid) < 0) rb_sys_fail(0); + } else { + if (gid == 0) { + if (setegid(gid) < 0) rb_sys_fail(0); + if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = 0; + if (setrgid(0) < 0) rb_sys_fail(0); + } else { + if (setrgid(0) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = 0; + if (setegid(gid) < 0) rb_sys_fail(0); + if (setrgid(gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + } + } + } else { + if (setegid(gid) < 0) rb_sys_fail(0); + if (setrgid(gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + } +#else + rb_notimplement(); +#endif + } else { /* unprivileged user */ +#if defined(HAVE_SETRESGID) + if (setresgid((getgid() == gid)? -1: gid, + (getegid() == gid)? -1: gid, + (SAVED_GROUP_ID == gid)? -1: gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; +#elif defined HAVE_SETREGID + if (SAVED_GROUP_ID == gid) { + if (setregid((getgid() == gid)? -1: gid, + (getegid() == gid)? -1: gid) < 0) rb_sys_fail(0); + } else if (getgid() != gid) { + if (setregid(gid, (getegid() == gid)? -1: gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + } else if (/* getgid() == gid && */ getegid() != gid) { + if (setregid(getegid(), gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + if (setregid(gid, -1) < 0) rb_sys_fail(0); + } else { /* getgid() == gid && getegid() == gid */ + if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0); + if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + if (setregid(gid, -1) < 0) rb_sys_fail(0); + } +#elif defined HAVE_SETRGID && defined HAVE_SETEGID + if (SAVED_GROUP_ID == gid) { + if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0); + if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0); + } else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) { + if (getgid() != gid) { + if (setrgid(gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + } else { + if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + if (setrgid(gid) < 0) rb_sys_fail(0); + } + } else if (/* getegid() != gid && */ getgid() == gid) { + if (setegid(gid) < 0) rb_sys_fail(0); + if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + if (setrgid(gid) < 0) rb_sys_fail(0); + } else { + errno = EPERM; + rb_sys_fail(0); + } +#elif defined HAVE_SETEGID + if (getgid() == gid && SAVED_GROUP_ID == gid) { + if (setegid(gid) < 0) rb_sys_fail(0); + } else { + errno = EPERM; + rb_sys_fail(0); + } +#elif defined HAVE_SETGID + if (getgid() == gid && SAVED_GROUP_ID == gid) { + if (setgid(gid) < 0) rb_sys_fail(0); + } else { + errno = EPERM; + rb_sys_fail(0); + } +#else + rb_notimplement(); +#endif + } + return INT2FIX(gid); +} + static VALUE proc_geteuid(obj) VALUE obj; @@ -1340,7 +1742,7 @@ if (setreuid(-1, NUM2INT(euid)) < 0) rb_sys_fail(0); #elif defined HAVE_SETEUID if (seteuid(NUM2INT(euid)) < 0) rb_sys_fail(0); -#else +#elif defined HAVE_SETUID euid = NUM2INT(euid); if (euid == getuid()) { if (setuid(euid) < 0) rb_sys_fail(0); @@ -1348,11 +1750,53 @@ else { rb_notimplement(); } +#else + rb_notimplement(); #endif return euid; } static VALUE +rb_seteuid_core(euid) + int euid; +{ + int uid; + + uid = getuid(); + +#if defined(HAVE_SETRESUID) && !defined(__CHECKER__) + if (uid != euid) { + if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0); + SAVED_USER_ID = euid; + } else { + if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0); + } +#elif defined HAVE_SETREUID && !defined(__OpenBSD__) + if (setreuid(-1, euid) < 0) rb_sys_fail(0); + if (uid != euid) { + if (setreuid(euid,uid) < 0) rb_sys_fail(0); + if (setreuid(uid,euid) < 0) rb_sys_fail(0); + SAVED_USER_ID = euid; + } +#elif defined HAVE_SETEUID + if (seteuid(euid) < 0) rb_sys_fail(0); +#elif defined HAVE_SETUID + if (geteuid() == 0) rb_sys_fail(0); + if (setuid(euid) < 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return INT2FIX(euid); +} + +static VALUE +p_uid_set_eid(obj, id) + VALUE obj, id; +{ + return rb_seteuid_core(NUM2INT(id)); +} + +static VALUE proc_getegid(obj) VALUE obj; { @@ -1372,7 +1816,7 @@ if (setregid(-1, NUM2INT(egid)) < 0) rb_sys_fail(0); #elif defined HAVE_SETEGID if (setegid(NUM2INT(egid)) < 0) rb_sys_fail(0); -#else +#elif defined HAVE_SETGID egid = NUM2INT(egid); if (egid == getgid()) { if (setgid(egid) < 0) rb_sys_fail(0); @@ -1380,10 +1824,224 @@ else { rb_notimplement(); } +#else + rb_notimplement(); #endif return egid; } +static VALUE +rb_setegid_core(egid) + int egid; +{ + int gid; + + gid = getgid(); + +#if defined(HAVE_SETRESGID) && !defined(__CHECKER__) + if (gid != egid) { + if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = egid; + } else { + if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0); + } +#elif defined HAVE_SETREGID && !defined(__OpenBSD__) + if (setregid(-1, egid) < 0) rb_sys_fail(0); + if (gid != egid) { + if (setregid(egid,gid) < 0) rb_sys_fail(0); + if (setregid(gid,egid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = egid; + } +#elif defined HAVE_SETEGID + if (setegid(egid) < 0) rb_sys_fail(0); +#elif defined HAVE_SETGID + if (getegid() == 0) rb_sys_fail(0); + if (setgid(egid) < 0) rb_sys_fail(0); +#else + rb_notimplement(); +#endif + return INT2FIX(egid); +} + +static VALUE +p_gid_set_eid(obj, id) + VALUE obj, id; +{ + return rb_setegid_core(NUM2INT(id)); +} + +static VALUE +p_uid_exchangeable() +{ +#if defined(HAVE_SETRESUID) && !defined(__CHECKER__) + return Qtrue; +#elif defined HAVE_SETREUID && !defined(__OpenBSD__) + return Qtrue; +#else + return Qfalse; +#endif +} + +static VALUE +p_uid_exchange(obj) + VALUE obj; +{ + int uid, euid; + + uid = getuid(); + euid = geteuid(); + +#if defined(HAVE_SETRESUID) && !defined(__CHECKER__) + if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; +#elif defined HAVE_SETREUID && !defined(__OpenBSD__) + if (setreuid(euid,uid) < 0) rb_sys_fail(0); + SAVED_USER_ID = uid; +#else + rb_notimplement(); +#endif + return INT2FIX(uid); +} + +static VALUE +p_gid_exchangeable() +{ +#if defined(HAVE_SETRESGID) && !defined(__CHECKER__) + return Qtrue; +#elif defined HAVE_SETREGID && !defined(__OpenBSD__) + return Qtrue; +#else + return Qfalse; +#endif +} + +static VALUE +p_gid_exchange(obj) + VALUE obj; +{ + int gid, egid; + + gid = getgid(); + egid = getegid(); + +#if defined(HAVE_SETRESGID) && !defined(__CHECKER__) + if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; +#elif defined HAVE_SETREGID && !defined(__OpenBSD__) + if (setregid(egid,gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; +#else + rb_notimplement(); +#endif + return INT2FIX(gid); +} + +static VALUE +p_uid_has_saved_id() +{ +#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || _POSIX_SAVED_IDS + return Qtrue; +#else + return Qfalse; +#endif +} + +static VALUE +p_uid_switch_auth(obj) + VALUE obj; +{ + extern int errno; + int uid, euid; + + uid = getuid(); + euid = geteuid(); + +#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || _POSIX_SAVED_IDS + if (uid != euid) { + proc_seteuid(obj, INT2FIX(uid)); + if (rb_block_given_p()) { + return rb_ensure(rb_yield, Qnil, rb_seteuid_core, SAVED_USER_ID); + } else { + return INT2FIX(euid); + } + } else if (euid != SAVED_USER_ID) { + proc_seteuid(obj, INT2FIX(SAVED_USER_ID)); + if (rb_block_given_p()) { + return rb_ensure(rb_yield, Qnil, rb_seteuid_core, euid); + } else { + return INT2FIX(uid); + } + } else { + errno = EPERM; + rb_sys_fail(0); + } +#else + if (uid == euid) { + errno = EPERM; + rb_sys_fail(0); + } + proc_swap_uid(obj); + if (rb_block_given_p()) { + return rb_ensure(rb_yield, Qnil, proc_swap_uid, obj); + } else { + return INT2FIX(euid); + } +#endif +} + +static VALUE +p_gid_has_saved_id() +{ +#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || _POSIX_SAVED_IDS + return Qtrue; +#else + return Qfalse; +#endif +} + +static VALUE +p_gid_switch_auth(obj) + VALUE obj; +{ + extern int errno; + int gid, egid; + + gid = getgid(); + egid = getegid(); + +#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || _POSIX_SAVED_IDS + if (gid != egid) { + proc_setegid(obj, INT2FIX(gid)); + if (rb_block_given_p()) { + return rb_ensure(rb_yield, Qnil, proc_setegid, INT2FIX(SAVED_GROUP_ID)); + } else { + return INT2FIX(egid); + } + } else if (egid != SAVED_GROUP_ID) { + proc_setegid(obj, INT2FIX(SAVED_GROUP_ID)); + if (rb_block_given_p()) { + return rb_ensure(rb_yield, Qnil, proc_setegid, INT2FIX(egid)); + } else { + return INT2FIX(gid); + } + } else { + errno = EPERM; + rb_sys_fail(0); + } +#else + if (gid == egid) { + errno = EPERM; + rb_sys_fail(0); + } + proc_swap_gid(obj); + if (rb_block_given_p()) { + return rb_ensure(rb_yield, Qnil, proc_swap_gid, obj); + } else { + return INT2FIX(egid); + } +#endif +} + VALUE rb_proc_times(obj) VALUE obj; @@ -1411,6 +2069,9 @@ } VALUE rb_mProcess; +VALUE rb_mProcUID; +VALUE rb_mProcGID; +VALUE rb_mProcID_Syscall; void Init_process() @@ -1499,6 +2160,7 @@ rb_define_module_function(rb_mProcess, "euid=", proc_seteuid, 1); rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0); rb_define_module_function(rb_mProcess, "egid=", proc_setegid, 1); + rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2); rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0); rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1); rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0); @@ -1509,4 +2171,53 @@ #if defined(HAVE_TIMES) || defined(_WIN32) S_Tms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", 0); #endif + + SAVED_USER_ID = geteuid(); + SAVED_GROUP_ID = getegid(); + + rb_mProcUID = rb_define_module_under(rb_mProcess, "UserID"); + rb_mProcGID = rb_define_module_under(rb_mProcess, "GroupID"); + + rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0); + rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0); + rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0); + rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0); + rb_define_module_function(rb_mProcUID, "to", p_uid_set_to, 1); + rb_define_module_function(rb_mProcGID, "to", p_gid_set_to, 1); + rb_define_module_function(rb_mProcUID, "eid=", p_uid_set_eid, 1); + rb_define_module_function(rb_mProcGID, "eid=", p_gid_set_eid, 1); + rb_define_module_function(rb_mProcUID, "ex_reid", p_uid_exchange, 0); + rb_define_module_function(rb_mProcGID, "ex_reid", p_gid_exchange, 0); + rb_define_module_function(rb_mProcUID, "ex_reid?", p_uid_exchangeable, 0); + rb_define_module_function(rb_mProcGID, "ex_reid?", p_gid_exchangeable, 0); + rb_define_module_function(rb_mProcUID, "has_sid?", p_uid_has_saved_id, 0); + rb_define_module_function(rb_mProcGID, "has_sid?", p_gid_has_saved_id, 0); + rb_define_module_function(rb_mProcUID, "switch", p_uid_switch_auth, 0); + rb_define_module_function(rb_mProcGID, "switch", p_uid_switch_auth, 0); + + rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "ID_Syscall"); + + rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0); + rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0); + rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0); + rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0); + + rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1); + rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1); + + rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1); + rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1); + + rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1); + rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1); + + rb_define_module_function(rb_mProcID_Syscall, "setreuid", + p_sys_setreuid, 2); + rb_define_module_function(rb_mProcID_Syscall, "setregid", + p_sys_setregid, 2); + + rb_define_module_function(rb_mProcID_Syscall, "setresuid", + p_sys_setresuid, 3); + rb_define_module_function(rb_mProcID_Syscall, "setresgid", + p_sys_setresgid, 3); } -- 永井 秀利 (九工大 知能情報) nagai / ai.kyutech.ac.jp