From: nagai@... Date: 2001-12-06T15:35:18+09:00 Subject: [ruby-dev:15372] new methods to treat uid/gid 永井@知能.九工大です. 色々と忙しかったり風邪でダウンしてたりで遅くなりました. Process モジュールにおけるユーザ ID / グループ ID の操作関連の 新しいメソッド群の試験実装です. よかったら,試して意見をください. まず,実装しているメソッドは次の通りです. ============================================================ uid/gid 操作のために実装するメソッド Process.uid Process.euid Process.uid= Process.euid= Process.swap_uid Process.switch_uauth() { ... } ------------------- Process.gid Process.egid Process.gid= Process.egid= Process.swap_gid Process.switch_gauth() { ... } ============================================================ で,各メソッドの仕様は以下のようになっています. ============================================================ Process.uid=(id) [Process.gid=(id)] 仕様 : 実/実効/保存ユーザ ID のすべてを変更して, 他のユーザとしての権限を放棄する. 成功時は id を返す. 完全放棄できない場合(一部ユーザ ID の変更ができない場合)は 例外を発生する. 例外の発生時に,このメソッドを呼び出す前の各ユーザ ID の値が 保存されているかどうかは保証されない. 注意 : 以前の Process.uid= とは互換性がないことに注意. setreuid(id,-1) によって実装されていたものを用いていたケースは, 例えば次のように書き換える必要があるだろう. Process.swap_uid ;# (r,e,s) == (u1,u2,??) ==> (u2,u1,??) Process.euid = id ;# (u2,u1,??) ==> (u2,id,??) Process.swap_uid ;# (u2,id,??) ==> (id,u2,??) ------------------------------------------------------------ Process.euid=(id) [Process.egid=(id)] 仕様 : 実効ユーザ ID を変更する. 成功時は id を返す. 保存ユーザ ID の変化は,Process.swap_uid が定義されているかで決まる. 定義されない環境では,保存ユーザ ID は変化しない. 定義されている環境では,id が実ユーザ ID と異なる値に設定された場合, 保存ユーザ ID は新しい実効ユーザ ID の値に設定される. 設定できない場合は例外を発生する. ------------------------------------------------------------ Process.swap_uid() [Process.swap_gid()] 仕様 : 実ユーザ ID と実効ユーザ ID とを入れ換える. 保存ユーザ ID は新しい実効ユーザ ID と同じになる. 設定できない場合は例外を発生する. 戻り値としては,新しい実効ユーザ ID を返す. 注意 : setresuid か setreuid を持たない環境には設定されない. ------------------------------------------------------------ Process.switch_uauth() { ... } [Process.switch_gauth() { ... }] 仕様 : ユーザ権限を(一時的に)変更する. その際に実ユーザ ID が変化するかは,環境依存のため,保証されない. 実/実効/保存ユーザ ID が二つのユーザ権限を移行できる状態でなければ 例外を発生する. ブロックが与えられたならば,権限を移行してそのブロックを実行した後, 元の権限に復帰する. ブロック内でユーザ ID が変更されるなどの理由で, 元の権限に復帰できない場合,例外を発生する. ブロックが与えられない場合の戻り値は元に戻せる(変更できる) ID 値, ブロックが与えられた場合の戻り値はブロックの値を返す. ============================================================ ただ,環境に対して個別対応せざるをえない問題が少しあります. 上記仕様とするためには,保存ユーザ ID が存在し, かつ,setreuid が存在する環境では, その setreuid は保存ユーザ ID を変化させるものでなければなりません. もし,変化させないものであった場合には その setreuid の使用を無効化する必要があります. とりあえず今のところ,OpenBSD 環境だけがそうらしいということで, その場合のみは setreuid を使わないようにしています. # 手元には OpenBSD 環境はありません. また,保存ユーザ ID が存在するかどうかは, setresuid が存在するか,seteuid が存在するか, _POSIX_SAVED_IDS が真であるかのいずれかで判断しています. そのため,これらに該当しないにも関わらず 保存ユーザ ID を持つ環境に対しては個別対応が必要です. といっても,上の setreuid の問題よりは軽微で, Process.switch_uauth において, 保存ユーザ ID を使った権限変更が選択されず, 実/実効ユーザ ID の交換による方法が選択されてしまうという点です. 保存ユーザ ID に影響しない setreuid の環境かどうかは 次のソースをコンパイルして,root 権限で実行してみてください. もし FAIL を出さずに最後まで行くようなら, 保存ユーザ ID に影響しない setreuid の環境ではないかと思われます. ============================================================ #include #ifdef HAVE_UNISTD_H #include #endif int main() { int uid, euid, suid; uid = getuid(); euid = geteuid(); suid = euid; printf("initial status : (%d, %d, %d)\n", uid, euid, suid); printf(" --> (%d, 5) ; ", uid); if (setreuid(-1,5) < 0) { printf("FAIL!!\n"); exit (0); } uid = getuid(); euid = geteuid(); printf("(%d, %d, ?)\n", uid, euid); printf(" --> (%d, %d) ; ", euid, uid); if (setreuid(euid,uid) < 0) { printf("FAIL!!\n"); exit (0); } uid = getuid(); euid = geteuid(); suid = euid; printf("(%d, %d, %d)\n", uid, euid, suid); printf(" --> (%d, 7) ; ", uid); if (setreuid(-1,7) < 0) { printf("FAIL!!\n"); exit (0); } uid = getuid(); euid = geteuid(); printf("(%d, %d, ?)\n", uid, euid); printf(" --> (%d, %d) ; ", euid, uid); if (setreuid(euid,uid) < 0) { printf("FAIL!!\n"); exit (0); } uid = getuid(); euid = geteuid(); suid = euid; printf("(%d, %d, %d)\n", uid, euid, suid); printf(" --> (%d, %d) ; ", uid, uid); if (setreuid(-1,uid) < 0) { printf("FAIL!!\n"); exit (0); } uid = getuid(); euid = geteuid(); printf("(%d, %d, %d)\n", uid, euid, suid); printf(" --> (%d, %d) ; ", uid, suid); if (setreuid(-1,suid) < 0) { printf("FAIL!!\n"); } uid = getuid(); euid = geteuid(); printf("(%d, %d, %d)\n", uid, euid, suid); return 0; } ============================================================ # これに限らず,テストプログラムで条件確認をしようとすると # root 権限が必要になる点が頭のいたいところです. で,以下がパッチです. ============================================================ Index: configure.in =================================================================== RCS file: /src/ruby/configure.in,v retrieving revision 1.103 diff -u -r1.103 configure.in --- configure.in 2001/12/03 09:38:35 1.103 +++ configure.in 2001/12/06 06:30:23 @@ -297,8 +297,8 @@ isinf isnan finite hypot) AC_CHECK_FUNCS(fmod killpg drand48 random wait4 waitpid syscall chroot\ truncate chsize times utimes fcntl lockf lstat symlink readlink\ - setitimer setruid seteuid setreuid setresuid setproctitle\ - setrgid setegid setregid setresgid pause lchown lchmod\ + setitimer setuid setruid seteuid setreuid setresuid setproctitle\ + setgid setrgid setegid setregid setresgid pause lchown lchmod\ getpgrp setpgrp getpgid setpgid getgroups getpriority getrlimit\ dlopen sigprocmask sigaction _setjmp setsid telldir seekdir fchmod) AC_STRUCT_TIMEZONE Index: process.c =================================================================== RCS file: /src/ruby/process.c,v retrieving revision 1.43 diff -u -r1.43 process.c --- process.c 2001/11/21 15:41:26 1.43 +++ process.c 2001/12/06 06:30:24 @@ -1111,29 +1111,134 @@ return INT2FIX(uid); } +static int SAVED_USER_ID; + static VALUE proc_setuid(obj, id) VALUE obj, id; { + extern int errno; int uid; uid = NUM2INT(id); -#if defined(HAVE_SETRESUID) && !defined(__CHECKER__) - if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0); + + 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 (setreuid(uid, -1) < 0) rb_sys_fail(0); -#elif defined HAVE_SETRUID - if (setruid(uid) < 0) rb_sys_fail(0); -#else - { - if (geteuid() == uid) { - if (setuid(uid) < 0) rb_sys_fail(0); + 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 { - rb_notimplement(); + } 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); } @@ -1145,29 +1250,134 @@ return INT2FIX(gid); } +static int SAVED_GROUP_ID; + static VALUE proc_setgid(obj, id) VALUE obj, id; { + extern int errno; int gid; gid = NUM2INT(id); -#if defined(HAVE_SETRESGID) && !defined(__CHECKER__) - if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0); + + if (getegid() == 0) { /* root-group */ +#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 (setregid(gid, -1) < 0) rb_sys_fail(0); -#elif defined HAS_SETRGID - if (setrgid((GIDTYPE)gid) < 0) rb_sys_fail(0); -#else - { - if (getegid() == gid) { - if (setgid(gid) < 0) rb_sys_fail(0); + 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, root, 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 { + if (setregid(0, -1) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = 0; + if (setregid(gid, gid) < 0) rb_sys_fail(0); + SAVED_GROUP_ID = gid; + } } - else { - rb_notimplement(); + } 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 (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 group */ +#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); } @@ -1180,25 +1390,43 @@ } static VALUE -proc_seteuid(obj, euid) - VALUE obj, euid; +rb_seteuid_core(euid) + int euid; { + int uid; + + uid = getuid(); + #if defined(HAVE_SETRESUID) && !defined(__CHECKER__) - if (setresuid(-1, NUM2INT(euid), -1) < 0) rb_sys_fail(0); -#elif defined HAVE_SETREUID - if (setreuid(-1, NUM2INT(euid)) < 0) rb_sys_fail(0); -#elif defined HAVE_SETEUID - if (seteuid(NUM2INT(euid)) < 0) rb_sys_fail(0); -#else - euid = NUM2INT(euid); - if (euid == getuid()) { - if (setuid(euid) < 0) rb_sys_fail(0); + 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); } - else { - rb_notimplement(); +#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 euid; + return INT2FIX(euid); +} + +static VALUE +proc_seteuid(obj, id) + VALUE obj, id; +{ + return rb_seteuid_core(NUM2INT(id)); } static VALUE @@ -1210,26 +1438,171 @@ } static VALUE -proc_setegid(obj, egid) - VALUE obj, egid; +rb_setegid_core(egid) + int egid; { - rb_secure(2); + int gid; + + gid = getgid(); + #if defined(HAVE_SETRESGID) && !defined(__CHECKER__) - if (setresgid(-1, NUM2INT(egid), -1) < 0) rb_sys_fail(0); -#elif defined HAVE_SETREGID - if (setregid(-1, NUM2INT(egid)) < 0) rb_sys_fail(0); + 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(NUM2INT(egid)) < 0) rb_sys_fail(0); + 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 - egid = NUM2INT(egid); - if (egid == getgid()) { - if (setgid(egid) < 0) rb_sys_fail(0); + rb_notimplement(); +#endif + return INT2FIX(egid); +} + +static VALUE +proc_setegid(obj, id) + VALUE obj, id; +{ + return rb_setegid_core(NUM2INT(id)); +} + +static VALUE +proc_swap_uid(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 +proc_swap_gid(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 +proc_switch_uauth(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 +proc_switch_gauth(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); } - else { - rb_notimplement(); + proc_swap_gid(obj); + if (rb_block_given_p()) { + return rb_ensure(rb_yield, Qnil, proc_swap_gid, obj); + } else { + return INT2FIX(egid); } #endif - return egid; } VALUE @@ -1333,6 +1706,8 @@ rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER)); #endif + SAVED_USER_ID = geteuid(); + SAVED_GROUP_ID = getegid(); rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0); rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1); rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0); @@ -1341,6 +1716,14 @@ 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); +#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(__OpenBSD__)) + rb_define_module_function(rb_mProcess, "swap_uid", proc_swap_uid, 0); +#endif +#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(__OpenBSD__)) + rb_define_module_function(rb_mProcess, "swap_gid", proc_swap_gid, 0); +#endif + rb_define_module_function(rb_mProcess, "switch_uauth", proc_switch_uauth, 0); + rb_define_module_function(rb_mProcess, "switch_gauth", proc_switch_gauth, 0); rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0); ============================================================ -- 永井 秀利 (九工大 知能情報) nagai@ai.kyutech.ac.jp