2014-01-22 33 views
1

在POSIX中,有衆所周知的函數getuid()geteuid()用於獲取進程的真實有效uid。但是,檢查保存的uid也是很有用的(在支持POSIX保存的uid的平臺上,這是每個當前的操作系統)。如何檢索我的進程的已保存的用戶ID?

例如,在經典指南"Setuid Demystified" (Chen, Dean, Wagner 2002)中,作者建議在任何調用setuid()函數後立即檢查真實的,有效的和保存的uid是否都是預期的。然而,在他們的實施指南中,他們沒有解釋如何檢查所有平臺上保存的uid。

如何檢索我的進程的已保存的用戶ID?

回答

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 
相關問題