[ruby-dev:15372] new methods to treat uid/gid
From:
nagai@...
Date:
2001-12-06 06:35:18 UTC
List:
ruby-dev #15372
永井@知能.九工大です.
色々と忙しかったり風邪でダウンしてたりで遅くなりました.
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 <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#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