# module Process::GID

The `Process::GID` module contains a collection of module functions which can be used to portably get, set, and switch the current process’s real, effective, and saved group IDs.

### Public Class Methods

Process::GID.change_privilege(group) → integer click to toggle source

Change the current process’s real and effective group ID to that specified by group. Returns the new group ID. Not available on all platforms.

    [Process.gid, Process.egid]          #=> [0, 0]
    Process::GID.change_privilege(33)    #=> 33
    [Process.gid, Process.egid]          #=> [33, 33]

    static VALUE
    p_gid_change_privilege(VALUE obj, VALUE id)
    {
        rb_gid_t gid;

        check_gid_switch();

        gid = OBJ2GID(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) && !defined(OBSOLETE_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)? (rb_gid_t)-1: gid,
                          (getegid() == gid)? (rb_gid_t)-1: gid,
                          (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
            SAVED_GROUP_ID = gid;
    #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
            if (SAVED_GROUP_ID == gid) {
                if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
                             (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
                    rb_sys_fail(0);
            }
            else if (getgid() != gid) {
                if (setregid(gid, (getegid() == gid)? (rb_uid_t)-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 {
                rb_syserr_fail(EPERM, 0);
            }
    #elif defined HAVE_44BSD_SETGID
            if (getgid() == gid) {
                /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
                if (setgid(gid) < 0) rb_sys_fail(0);
                SAVED_GROUP_ID = gid;
            }
            else {
                rb_syserr_fail(EPERM, 0);
            }
    #elif defined HAVE_SETEGID
            if (getgid() == gid && SAVED_GROUP_ID == gid) {
                if (setegid(gid) < 0) rb_sys_fail(0);
            }
            else {
                rb_syserr_fail(EPERM, 0);
            }
    #elif defined HAVE_SETGID
            if (getgid() == gid && SAVED_GROUP_ID == gid) {
                if (setgid(gid) < 0) rb_sys_fail(0);
            }
            else {
                rb_syserr_fail(EPERM, 0);
            }
    #else
            (void)gid;
            rb_notimplement();
    #endif
        }
        return id;
    }

egid → integer click to toggle source
Process::GID.eid → integer
Process::Sys.geteid → integer

Returns the effective group ID for the current process:

    Process.egid # => 500

Not available on all platforms.

    static VALUE
    proc_getegid(VALUE obj)
    {
        rb_gid_t egid = getegid();

        return GIDT2NUM(egid);
    }

Process::GID.from_name(name) → gid click to toggle source

Get the group ID by the name. If the group is not found, `ArgumentError` will be raised.

    Process::GID.from_name("wheel") #=> 0
    Process::GID.from_name("nosuchgroup") #=> can't find group for nosuchgroup (ArgumentError)

    static VALUE
    p_gid_from_name(VALUE self, VALUE id)
    {
        return GIDT2NUM(OBJ2GID(id));
    }

Process::GID.grant_privilege(group) → integer click to toggle source
Process::GID.eid = group → integer

`Set` the effective group ID, and if possible, the saved group ID of the process to the given group. Returns the new effective group ID. Not available on all platforms.

    [Process.gid, Process.egid]          #=> [0, 0]
    Process::GID.grant_privilege(31)     #=> 33
    [Process.gid, Process.egid]          #=> [0, 33]

    static VALUE
    p_gid_grant_privilege(VALUE obj, VALUE id)
    {
        rb_setegid_core(OBJ2GID(id));
        return id;
    }

Process::GID.re_exchange → integer click to toggle source

Exchange real and effective group IDs and return the new effective group ID. Not available on all platforms.

    [Process.gid, Process.egid]   #=> [0, 33]
    Process::GID.re_exchange      #=> 0
    [Process.gid, Process.egid]   #=> [33, 0]

    static VALUE
    p_gid_exchange(VALUE obj)
    {
        rb_gid_t gid;
    #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
        rb_gid_t egid;
    #endif

        check_gid_switch();

        gid = getgid();
    #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
        egid = getegid();
    #endif

    #if defined(HAVE_SETRESGID)
        if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
        SAVED_GROUP_ID = gid;
    #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
        if (setregid(egid,gid) < 0) rb_sys_fail(0);
        SAVED_GROUP_ID = gid;
    #else
        rb_notimplement();
    #endif
        return GIDT2NUM(gid);
    }

Process::GID.re_exchangeable? → true or false click to toggle source

Returns `true` if the real and effective group IDs of a process may be exchanged on the current platform.

    static VALUE
    p_gid_exchangeable(VALUE _)
    {
    #if defined(HAVE_SETRESGID)
        return Qtrue;
    #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
        return Qtrue;
    #else
        return Qfalse;
    #endif
    }

gid → integer click to toggle source
Process::GID.rid → integer
Process::Sys.getgid → integer

Returns the (real) group ID for the current process:

    Process.gid # => 1000

    static VALUE
    proc_getgid(VALUE obj)
    {
        rb_gid_t gid = getgid();
        return GIDT2NUM(gid);
    }

Process::GID.sid_available? → true or false click to toggle source

Returns `true` if the current platform has saved group ID functionality.

    static VALUE
    p_gid_have_saved_id(VALUE _)
    {
    #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
        return Qtrue;
    #else
        return Qfalse;
    #endif
    }

Process::GID.switch → integer click to toggle source
Process::GID.switch {|| block} → object

Switch the effective and real group IDs of the current process. If a block is given, the group IDs will be switched back after the block is executed. Returns the new effective group ID if called without a block, and the return value of the block if one is given.

    static VALUE
    p_gid_switch(VALUE obj)
    {
        rb_gid_t gid, egid;

        check_gid_switch();

        gid = getgid();
        egid = getegid();

        if (gid != egid) {
            proc_setegid(obj, GIDT2NUM(gid));
            if (rb_block_given_p()) {
                under_gid_switch = 1;
                return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
            }
            else {
                return GIDT2NUM(egid);
            }
        }
        else if (egid != SAVED_GROUP_ID) {
            proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
            if (rb_block_given_p()) {
                under_gid_switch = 1;
                return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
            }
            else {
                return GIDT2NUM(gid);
            }
        }
        else {
            rb_syserr_fail(EPERM, 0);
        }

        UNREACHABLE_RETURN(Qnil);
    }