portable(?) user/group ID control

Discussion in 'Ruby' started by Hidetoshi NAGAI, Jul 17, 2003.

  1. 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 ()
    Hidetoshi NAGAI, Jul 17, 2003
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eli Bendersky
    Replies:
    1
    Views:
    1,151
    Mike Treseler
    Mar 1, 2006
  2. Mad Scientist Jr
    Replies:
    0
    Views:
    622
    Mad Scientist Jr
    Mar 22, 2006
  3. Replies:
    7
    Views:
    900
  4. Sinan Alkan
    Replies:
    0
    Views:
    410
    Sinan Alkan
    Oct 3, 2008
  5. Jonathan Wood

    User Control to Control Other User Control

    Jonathan Wood, Jan 24, 2010, in forum: ASP .Net
    Replies:
    4
    Views:
    525
    Jonathan Wood
    Feb 2, 2010
Loading...

Share This Page