![]() |
portable(?) user/group ID control
Hi,
About 2 years ago, there was a small thread of discussion on ruby-dev ML. It was about the portablity of user/group ID control. Process.uid= and Process.euid= are not enough for adequate control of privileges. Systemcalls (such as setuid or setreuid) have only low portability because of dependency on OS. The discussion was about the set of methods and specification of each method which has higher portability for privileges control than the current method set of Ruby. Here is a sample of specification. A patch for CVS head (1.8.0) is attached to this mail. In a lot of cases, the purpose of user/group ID control is (1) to exchange a user privilege to another privilege temporarily, or (2) to drop to a user privilege permanently. If based on this patch, Process::UserID.eid = new_id and Process::UserID.swith will work for case (1), and Process::UserID.to(new_id) will work for case (2). Which systemcalls must be used for the purpose on the current environment is determined by Ruby. Your comments and suggestions (include better names of methods) are welcome. # As you know, I can write only a little English. # So, I'm very sorry but I may not be able to give you answers # enough to satisfy your question. =*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==* ==*==*= module Process::ID_Syscall * Simple implementation of systemcalls. * These methods have low portability. getuid geteuid getgid getegid setuid setgid setruid setrgid seteuid setegid setreuid setregid setresuid setresgid module Process::UserID * manipulate user IDs of the process module Process::GroupID * manipulate group IDs of the process ================================================== ========== Process::UserID.rid [Process::GroupID.rid] SPEC : gets the real user ID of the current process. ================================================== ========== Process::UserID.eid [Process::GroupID.eid] SPEC : gets the effective user ID of the current process. ================================================== ========== Process::UserID.to(id) [Process::GroupID.to(id)] SPEC : sets the real/effective/saved user ID to id. If succeed, returns id. If fail to change some of IDs, raise a exception. After the exception, it is unknown whether each of IDs keeps the old value. Attention : There is no compatibility with Process.uid=. If you use the method implemented by setreuid(id,-1), for example, please rewrite the script to the following. 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)] SPEC : sets the effecttive user ID to id. If succeeed, returns id. It depends on the value of Process::UserID.ex_reid? whether the saved user ID is changed or not at the same time. If Process::UserID.ex_reid? returns false, the saved user ID is not changed. If Process::UserID.ex_reid? returns true and succeed to change the effective user ID to the different value from the real user ID, the saved user ID is changed to the new effective user ID. If fail to change, raise a exception. ================================================== ========== Process::UserID.ex_reid [Process::GroupID.ex_reid] SPEC : exchanges the real user ID and the effective user ID. the saved user ID is set to the same value as the new effective user ID. If not implemented (depends on specification of systemcalls of your OS), raise a exception. If succeed, returns the new effective user ID. ================================================== ========== Process::UserID.ex_reid? [Process::GroupID.ex_reid?] SPEC : returns whether can exchange or not the real user ID and the effective user ID (whether Process::UserID.ex_reid is implemented or not) on your environment. If implemented, returns true. ================================================== ========== Process::UserID.has_sid? [Process::GroupID.has_sid?] SPEC : returns whether your OS supports the saved user ID or not. If supports, returns true. Attention : On the current version, if one of the following rules is satisfied, this method gesses the environment supports the saved user ID. (1) has setresuid() systemcall. (2) has seteuid() systemcall. (3) define _POSIX_SAVED_IDS as true ================================================== ========== Process::UserID.switch [Process::GroupID.switch] Process::UserID.switch { ... } [Process::GroupID.switch { ... }] SPEC : changes the user privilege temporarily. If a block is given, evaluate the block under the switched user privilege and back to the original privilege. Without a block, it works to switch the two privileges. As far as the real/effective/saved user ID are not changed by other methods, this method toggles the two privileges. Without a block, this method returns a user ID which is restorable. With a block, returns a value of the block. If the status of current real/effective/saved user ID cannot support switching privileges, raise a exception. If with a block and cannot change back to original privilege after evaluating the block (e.g. calls Process::UserID.to(id) in the block), raise a exception. The privilage to be changed to is the current real user ID's privilege or the current saved ID's privilege. If your enviromnet doesn't have the saved user ID, the real user ID is changed by this method. ================================================== ========== =*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==* ==*==*= 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); } -- Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) |
| All times are GMT. The time now is 06:52 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.