Linux在伪代码中有效,真实,保存,文件系统UID操作

时间:2011-07-22 11:57:01

标签: linux unix setuid

我花了一些时间在Groovy中的一些代码来使Linux UID操作对我自己有点不那么困惑,因为手册页很乱。结果是一个TestCase,用于显示在setuid,seteuid,setfsuid,setreuid和setresuid调用的引擎下发生的事情。不考虑有关返回的错误代码(或不包含)的详细信息。

问题基本上是:我错过了什么吗?

/**
 * This is some Groovy code to explain Linux privilege handling
 * The manipulable data structure is "PermVector", and it is manipulated through a
 * TestCase.
 */

class PermissionTestCase extends GroovyTestCase {

  class PermVector {

    int ruid  // real UID; affects the permissions for sending signals 
    int euid  // effective UID; affects file creation and access
    int suid  // saved UID
    int fsuid // filesystem UID; access control to the file system for NFS in Linux

    /**
     * The permission vector of a process that is created from a parent process
     * having the given parent_euid, with its executable file having the given
     * exe_suid_bit and being owned by the given exe_uid  
     */

    PermVector(Map params) {
        ruid  = params.parent_euid // is this right??
        euid  = params.parent_euid
        suid  = params.exe_suid_bit ? params.exe_uid : params.parent_euid
        fsuid = params.parent_euid // is this right??
    }

    /**
     * What does it mean for a process to be "privileged"?
     */

    def isPrivileged() {
        return euid == 0
    }

    /**
     * Helper
     */

    private def euid_part(int new_euid) {
        if (isPrivileged() || 
            (new_euid == ruid || new_euid == euid || new_euid == suid)) {
            return new_euid
        }
        else {
            throw new IllegalStateException("Nixed euid ${euid} to ${new_euid}")
        }
    }

    /**
     * Helper
     */

    private def ruid_part(int new_ruid) {
        if (isPrivileged() || (new_ruid == ruid || new_ruid == euid)) {
            return new_ruid
        }
        else {
            throw new IllegalStateException("Nixed ruid ${ruid} to ${new_ruid}")
        }
    }

    /**
     * Helper
     */

    private def suid_part(int new_suid) {
        if (isPrivileged() || 
            (new_suid == ruid || new_suid == euid || new_suid == suid)) {
            return new_suid
        }
        else {
            throw new IllegalStateException("Nixed suid ${suid} to ${new_suid}")
        }
    }

    /**
     * Helper
     */

    private def ruid_part_for_setresuid(int new_ruid) {
        if (isPrivileged() || 
            (new_ruid == ruid || new_ruid == euid || new_ruid == suid)) {
            return new_ruid
        }
        else {
            throw new IllegalStateException("Nixed ruid ${ruid} to ${new_ruid}")
        }
    }

    /**
     * Behaviour of SETREUID(2)
     */

    def setreuid(int new_ruid, int new_euid) {
        int next_euid = euid_part(new_euid)
        int next_ruid = ruid_part(new_ruid)
        if (next_euid != euid || next_ruid != ruid) {
            suid = next_euid
        }
        euid = next_euid
        ruid = next_ruid
        fsuid = next_euid
    }

    /**
     * Behaviour of SETEUID(2)
     */

    def seteuid(int new_euid) {
        if (isPrivileged()) {
            euid = new_euid
            fsuid = new_euid
        }
        else {
            if (new_euid == ruid || new_euid == euid || new_euid == suid) {
                euid = new_euid
                fsuid = new_euid
                // glibc 2.1  and  later do not change the suid!
            }
            else {
                throw new IllegalStateException("Nixed euid ${euid} to ${new_euid}")
            }
        }
    }

    /**
     * Behaviour of SETUID(2)
     */

    def setuid(int new_euid) {
        if (isPrivileged()) {
            euid = new_euid
            ruid = new_euid
            suid = new_euid
            fsuid = new_euid
        }
        else {
            if (new_euid == ruid || new_euid == suid) {
                euid = new_euid
                fsuid = new_euid
            }
            else {
                throw new IllegalStateException("Nixed euid ${euid} to ${new_euid}")
            }
        }
    }

    /**
     * Behaviour of SETFSUID(2)
     */

    def setfsuid(int new_fsuid) {
        if (isPrivileged()) {
            fsuid = new_fsuid
        }
        else {
            if (new_fsuid == ruid || new_fsuid == euid || 
                new_fsuid == suid || new_fsuid == fsuid) {
                fsuid = new_fsuid
            }
            else {
                throw new IllegalStateException("Nixed fsuid ${fsuid} to ${new_fsuid}")
            }
        }
    }

    /**
     * Behaviour of SETRESUID(2)
     */

    def setresuid(int new_ruid, int new_euid, int new_suid) {
        int next_ruid = new_ruid==-1 ? ruid : ruid_part_for_setresuid(new_ruid)
        int next_euid = new_euid==-1 ? euid : euid_part(new_euid)
        int next_suid = new_suid==-1 ? suid : suid_part(new_suid)
        ruid = next_ruid
        euid = next_euid
        suid = next_suid
        fsuid = next_euid
    }

    /**
     * Printing
     */

    String toString() {
        return "[ruid:${ruid}, euid:${euid}, suid:${suid}, fsuid:${fsuid}]"
    }
}


/**
 * Use case: drop privileges for good
 */

void testDropPrivilegesFromRoot() {
    PermVector pv = 
         new PermVector(parent_euid : 0, exe_suid_bit : false, exe_uid : 500)        
    System.out << "Dropping privileges from ${pv} using setuid(1000) .... "
    pv.setuid(1000)
    System.out << "now at ${pv}\n"
    assertEquals(1000, pv.ruid)
    assertEquals(1000, pv.euid)
    assertEquals(1000, pv.suid)
    assertEquals(1000, pv.fsuid)

}

/**
 * Use case: elevate privileges, do some work, then drop privileges again
 */

void testElevatePrivilegesTemporarily() {
    PermVector pv = 
       new PermVector(parent_euid : 500, exe_suid_bit : true, exe_uid : 0)
    System.out << "Elevating privileges from ${pv} using setreuid(500,0) .... "
    pv.setreuid(500,0)        
    System.out << "now at ${pv}, doing privileged work .... "
    assertEquals(500, pv.ruid)
    assertEquals(0, pv.euid)
    assertEquals(0, pv.suid)
    assertEquals(0, pv.fsuid)
    System.out << "dropping back .... "        
    pv.setuid(500)
    System.out << "now at ${pv}\n"
    assertEquals(500, pv.ruid)
    assertEquals(500, pv.euid)
    assertEquals(500, pv.suid)
    assertEquals(500, pv.fsuid)

}

/**
 * Use case: drop privileges, do some work, then elevate privileges again
 */

void testDropPrivilegesTemporarily() {
    PermVector pv = 
       new PermVector(parent_euid : 0, exe_suid_bit : false, exe_uid : 500)
    System.out << "Dropping privileges from ${pv} using setreuid(0,500) .... "
    pv.setreuid(0, 500)
    System.out << "now at ${pv} ... doing unprivileged work safely .... "
    assertEquals(0, pv.ruid)
    assertEquals(500, pv.euid)
    assertEquals(500, pv.suid)
    assertEquals(500, pv.fsuid)
    System.out << "elevating .... "
    pv.setuid(0)
    System.out << "back at ${pv}\n"
    assertEquals(0, pv.ruid)
    assertEquals(0, pv.euid)
    assertEquals(500, pv.suid)
    assertEquals(0, pv.fsuid)

  }
}

1 个答案:

答案 0 :(得分:5)

对于实际和有效UID之间的区别,请阅读例如this - 这是UNIX UID的关键概念。你可以,例如有一个设置了UID位的进程,如果普通用户运行它,他将拥有root的有效UID(例如),但真正的UID仍然是他的UID。在你理解了这个例子后,它会变得更加清晰......