在POSIX中,有众所周知的函数getuid()
和geteuid()
用于获取进程的真实有效uid。但是,检查保存的uid通常也很有用(在支持POSIX保存的uid的平台上,这是每个当前的操作系统)。
例如,在经典指南"Setuid Demystified" (Chen, Dean, Wagner 2002)中,作者建议在调用setuid()
函数后立即检查真实,有效和保存的uid是否符合预期。但是,在他们的实施指南中,他们没有解释如何在所有平台上检查已保存的uid。
如何检索我的进程已保存的uid?
答案 0 :(得分:1)
以下代码段实现了getsuid()
功能。经测试适用于Linux 2.6 +,FreeBSD 8 +,Solaris 8 +,AIX 5.3 +,HP-UX 11.00+,MacOS 10.6+。也可能适用于旧版本。
#include <unistd.h>
#include <stdio.h>
#ifdef _AIX
#include <sys/id.h>
#elif defined(__sun)
#include <fcntl.h>
#include <procfs.h>
#elif defined(__hpux)
#include <dlfcn.h>
#include <sys/pstat.h>
#elif defined(__APPLE__)
#include <sys/sysctl.h>
#endif
#if defined(__linux) || defined(__FreeBSD__)
static int getsuid(uid_t* suid) {
uid_t ruid, euid;
return getresuid(&ruid, &euid, suid);
}
#elif defined(_AIX)
static int getsuid(uid_t* suid) {
*suid = getuidx(ID_SAVED);
return *suid == (uid_t)-1 ? -1 : 0;
}
#elif defined(__sun)
static int getsuid(uid_t* suid) {
int fd = open("/proc/self/cred", O_RDONLY);
if (fd < 0) return -1;
prcred_t prcred;
int n = read(fd, &prcred, sizeof(prcred));
close(fd);
if (n != sizeof(prcred)) return -1;
*suid = prcred.pr_suid;
return 0;
}
#elif defined(__hpux)
static int getsuid(uid_t* suid)
{
// HP-UX does have getresuid, but only on 11.11 onwards.
void* handle;
int (*getresuid_)(uid_t*,uid_t*,uid_t*);
struct pst_status pst;
int i;
if ((handle = dlopen("libc.sl", RTLD_LAZY | RTLD_GLOBAL)) &&
(getresuid_ = dlsym(handle, "getresuid")))
{
uid_t dummy1, dummy2, result;
if ((*getresuid_)(&dummy1, &dummy2, &result))
return -1;
*suid = result;
dlclose(handle);
return 0;
}
if (handle) dlclose(handle);
for (i = 0; pstat_getproc(&pst, sizeof(pst), 1, i); ++i) {
if (pst.pst_pid != getpid())
continue;
*suid = pst.pst_suid;
return 0;
}
return -1;
}
#elif defined(__APPLE__)
static int getsuid(uid_t* suid)
{
int ctl[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
struct kinfo_proc kip;
size_t len = sizeof(kip);
if (sysctl(ctl, 4, &kip, &len, 0, 0) < 0)
return -1;
*suid = kip.kp_eproc.e_pcred.p_svuid;
return 0;
}
#else
#error getsuid() not implemented for this platform
#endif
#ifdef TEST_CODE
int main() {
uid_t ruid, euid, suid;
ruid = getuid();
euid = geteuid();
if (getsuid(&suid) < 0) {
perror("getsuid failure");
return -1;
}
printf("uid: %ld, euid: %ld, suid: %ld\n",
(long)ruid, (long)euid, (long)suid);
}
#endif