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



我花了一些时间在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)
  }
}

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

相关内容

最新更新