一個進(jìn)程的 real user ID 是指運(yùn)行此進(jìn)程的用戶角色的 ID。
一個進(jìn)程的 effective user ID 是指此進(jìn)程目前實(shí)際有效的用戶 ID(也就是權(quán)限的大小),effective user ID 主要用來校驗(yàn)權(quán)限時使用,比如打開文件、創(chuàng)建文件、修改文件、kill 別的進(jìn)程,等等。
如果一個進(jìn)程是以 root 身份來運(yùn)行的,那么上面這兩個 ID 可以用 setuid/seteuid 隨便修改,想怎么改就怎么改,改來改去都可以。
但是如果一個進(jìn)程是以普通用戶身份來運(yùn)行的,那么上面這兩個 ID 一般來說是相同的,并且也不能隨便修改。只有一種情況例外:此進(jìn)程的可執(zhí)行文件的權(quán)限標(biāo)記中,設(shè)置了“設(shè)置用戶 ID”位!
在命令行中,設(shè)置一個可執(zhí)行文件的“設(shè)置用戶 ID”位的最簡單的方法,就是用
chmod +s /path/to/file
這個命令。
一旦用了這個命令之后,再執(zhí)行這個文件,
那么生成的進(jìn)程的 effective user ID 就變成了這個可執(zhí)行文件的 owner user ID(屬主用戶 ID),
而 real user ID 仍然是啟動這個程序時所用的用戶的 ID。
打個比方來說,如果有這樣的一個文件:
引用:
-rw[color=red]s[/color]r-[color=red]s[/color]r-x 1 susesuse susesuse 7902 2006-08-31 13:22 tuid注意這個文件已經(jīng)用 chmod +s 命令設(shè)置過“設(shè)置用戶 ID”位了。
然后我用 flw 這個用戶來執(zhí)行它,那么生成的進(jìn)程它的 real user ID 就是 flw(因?yàn)槲沂怯?nbsp;flw 運(yùn)行的),但是 effective user ID 就變成了 susesuse(因?yàn)檫@個可執(zhí)行文件被設(shè)置了“設(shè)置用戶 ID”位,并且它的 owner user ID 是 susesuse)。
這時,這個進(jìn)程實(shí)際上就有兩個用戶權(quán)限了。只不過目前生效的是 susesuse,因此它目前能夠且只能夠操作 susesuse 用戶的文件,如果現(xiàn)在我又想要操作 flw 用戶的文件怎么辦?
很簡單,只需要 seteuid( getuid() ) 就可以了。執(zhí)行完這句之后,effective user ID 就變成和 real user ID 一樣了,都變成 flw 了。
可是如果過了一會兒我又想要變回來怎么辦?因?yàn)?nbsp;effective user ID 和 real user ID 此時都變成了 flw 了,所以操作系統(tǒng)必須得有一個地方保存住原來的“設(shè)置用戶 ID”(也就是可執(zhí)行文件的 owner user ID),不然等你再想要 seteuid 的時候,操作系統(tǒng)就不知道你有沒有那個權(quán)利了。(總不能再去訪問一次文件系統(tǒng)吧?那樣也太沒有效率了)
操作系統(tǒng)為了能夠在設(shè)置了 seteuid 之后,再次設(shè)置回來,所以特地將原來的“設(shè)置用戶 ID”保存下來了,這個保存下來的設(shè)置用戶 ID 自然就叫做“保存的設(shè)置用戶 ID”。
下面看一段寫的例子程序:
flw@Sleeper:~$ whoami
flw
flw@Sleeper:~$ cat tuid.c
# include <stdio.h>
# include <sys/types.h>
# include <pwd.h>
int main( void )
{
struct passwd *pwd;
pwd = getpwuid( geteuid() );
printf( "effective UID: [%s]\n", pwd->pw_name );
system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
printf( "\nset EUID to `flw'..\n" );
pwd = getpwnam( "flw" );
seteuid(pwd->pw_uid);
pwd = getpwuid( geteuid() );
printf( "effective UID: [%s]\n", pwd->pw_name );
system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
printf( "\nset EUID to `root'..\n" );
seteuid(0);
pwd = getpwuid( geteuid() );
printf( "effective UID: [%s]\n", pwd->pw_name );
system( "touch /tmp/foo.txt; ls -l /tmp/foo.txt; rm -rf /tmp/foo.txt" );
return 0;
}
flw@Sleeper:~$ su root -c "cc -o tuid tuid.c; chmod +s tuid; ls -al tuid"
Password:
-rwsr-sr-x 1 root root 7902 2006-08-31 13:55 tuid
flw@Sleeper:~$ ./tuid
effective UID: [root]
-rw-r--r-- 1 root root 0 2006-08-31 13:55 /tmp/foo.txt
set EUID to `flw'..
effective UID: [flw]
-rw-r--r-- 1 flw root 0 2006-08-31 13:55 /tmp/foo.txt
set EUID to `root'..
effective UID: [root]
-rw-r--r-- 1 root root 0 2006-08-31 13:55 /tmp/foo.txt
flw@Sleeper:~$