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