国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 操作系統 > 正文

setuid函數解析

2024-06-28 13:22:29
字體:
來源:轉載
供稿:網友
setuid函數解析

  在討論這個setuid函數之前,我們首先要了解的一個東西就是內核為每個進程維護的三個UID值。這三個UID分別是實際用戶ID(real uid)、有效用戶ID(effective uid)、保存的設置用戶ID(saved set-user-ID)。

  首先說這個實際用戶ID,就是我們當前以哪個用戶登錄了,我們運行的程序的實際用戶ID就是這個用戶的ID。有效用戶ID就是當前進程是以哪個用戶ID來運行的,一般情況下是實際用戶ID,如果可執行文件具有了SUID權限,那么它的有效用戶ID就是可執行文件的擁有者。保存的設置用戶ID就是有效用戶ID的一個副本,與SUID權限有關。

  關于那個SUID,最經典的例子莫過于passwd命令。passwd這個可執行文件的所有者是root,但是其他用戶對于它也有執行權限,并且它自身具有SUID權限。那么當其他用戶來執行passwd這個可執行文件的時候,產生的進程的就是以root用戶的ID來運行的。如下圖所示:

  

  這個passwd的所有者是root,并且在權限那一欄中s代表的是SUID權限。我以普通用戶michael來運行這個命令,產生的進程如下:

  

  大家可以看到,倒數第二行這個進程其命令是passwd,但是其USER卻是root。這就是SUID權限。

  接下來,我們開始扯正題,setuid函數。這是setuid函數的聲明和返回值:

  

  

  如果成功返回0,如果失敗返回-1,并將errno設置為合適的值。

  關于這個函數的功能,APUE(《UNIX環境高級編程》,下面的APUE為相同的意思,不再贅述)上面是這樣寫的:

  

  這樣光講概念可能有點干巴巴了,下面我來舉幾個分別說明一下:

  開始講之前,我先驗證一下我的電腦是支持"保存的設置用戶ID"這個功能的,在電腦上運行以下代碼:

 1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<stdarg.h> 5 #include<errno.h> 6 #include<unistd.h> 7 #define BUFSIZE 512 8 void err_exit(char *fmt,...); 9 int main(int argc,char *argv[])10 {11     if(sysconf(_SC_SAVED_IDS) > 0)12     PRintf("_POSIX_SAVED_IDS effective!/n");13 14     return 0;15 }

  程序的運行結果如下:

  

  首先說一下我用到的用戶,一共使用了三個用戶,root(UID=0),michael(UID=500),xiaojie(UID=501)如下圖所示:

  

  先講第一點,如果進程具有超級用戶特權,那么這三個UID都被設置成了uid(setuid函數的參數)的值。比如下面這段代碼:

 1 #include<sys/types.h> 2 #include<unistd.h> 3 #include<stdio.h> 4 int main(int argc,char *argv[]) 5 { 6     uid_t ruid,euid,suid; 7     //這三個uid分別是實際用戶ID,有效用戶ID,保存的設置用戶ID 8  9     setuid(500);10     getresuid(&ruid,&euid,&suid);11     printf("real:%d/teffective:%d/tset-user-id:%d/n",ruid,euid,suid);12 13     return 0;14 }

  我用root用戶來運行這個程序,那么剛開始這個進程的有效用戶ID為0,然后這個進程中調用setuid(500),這三個UID的值都會被設置成500(在程序中通過getresuid函數來獲取進程的三個UID的值),運行結果如下圖:

  

  接下來我們再來討論第二種情況,如果函數的參數uid等于進程的實際用戶ID或者保存的設置用戶ID,那么就將有效用戶ID設置為uid,其他的兩個(實際用戶ID和保存的設置用戶ID)保持不變。比如下面這個程序:

 1 #include<sys/types.h> 2 #include<unistd.h> 3 #include<stdio.h> 4 void err_exit(char *fmt,...); 5 int main(int argc,char *argv[]) 6 { 7     uid_t ruid,euid,suid; 8  9     printf("Before:/n");10     if(-1 == getresuid(&ruid,&euid,&suid))11     err_exit("[getresuid]: ");12     printf("real:%d/teffective:%d/tset-user:%d/n",ruid,euid,suid);13     setuid(500);14     printf("After:/n");15     if(-1 == getresuid(&ruid,&euid,&suid))16     err_exit("[getresuid]: ");17     printf("real:%d/teffective:%d/tset-user:%d/n",ruid,euid,suid);18 19     return 0;20 }

  關于這段代碼生成的可執行文件,我讓它的擁有者變成了xiaojie(UID=501),并且給它加上了SUID權限,如下圖所示:

  

  然后我用michael用戶(UID=500)來運行這個程序,那么這個程序的實際用戶ID=500,而有效用戶ID和保存的設置用戶ID都為501。接著,在這個程序中調用setuid函數,傳入的參數為500,大家可以猜想到,最終應該只有有效用戶ID受到影響,而保存的設置用戶ID保持不變。運行結果如下圖所示:

  

  這就符合了我們的預期,僅僅只有有效用戶ID受到了影響,而實際用戶ID和保存的設置用戶ID并沒有改變。(這里我僅僅是驗證了保存的設置用戶ID不受影響,大家也可以自己寫一個程序,來驗證實際用戶ID并不受影響。)

  最后一點,如果setuid函數的參數的uid的值即不等于實際用戶ID,也不等于保存的設置用戶ID,而且這個進程的有效用戶ID也不是0(非特權進程)。那么這個程序就會出錯,并將errno設置為EPERM。比如下面這個程序:

 1 #include<sys/types.h> 2 #include<unistd.h> 3 #include<stdio.h> 4 #include<string.h> 5 #include<errno.h> 6 int main(int argc,char *argv[]) 7 { 8     uid_t ruid,euid,suid; 9 10     getresuid(&ruid,&euid,&suid);11     printf("real:%d/teffective:%d/tset-user:%d/n",ruid,euid,suid);12 13     if(-1 == setuid(500))14     {15     printf("%s/n",strerror(errno));16     if(errno == EPERM)17     {18         printf("Error number is EPERM!/n");19     }20     }21     else22     {23     getresuid(&ruid,&euid,&suid);24         printf("real:%d/teffective:%d/tset-user:%d/n",ruid,euid,suid);25     }26 27     return 0;28 }

  我以xiaojie用戶(UID=501)來運行這個程序,那么這個程序的三個用戶ID都為501,然后在這個程序中,調用setuid(500)。于是程序就會報錯,并將errno設置為EPERM,如下圖所示:

  

  

  OK,這就是APUE上關于setuid函數的解釋,講了這么多,綜合成一句話就是,root是神,想怎么干就怎么干,沒人管得了。而普通用戶呢,只能管自己分內的事(把進程的有效ID改成自己的ID),不能胡亂來。

  OK,that‘s all。希望這篇文章對大家能夠有幫助。

  


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 察隅县| 汉沽区| 九龙坡区| 英吉沙县| 吐鲁番市| 普宁市| 玛纳斯县| 白沙| 华亭县| 安新县| 新野县| 永登县| 高邮市| 桐梓县| 定安县| 福清市| 上高县| 临夏市| 精河县| 岗巴县| 微博| 城步| 河北区| 葵青区| 乳山市| 巢湖市| 璧山县| 同江市| 黄龙县| 汤原县| 绵竹市| 芜湖市| 大洼县| 佛山市| 石台县| 太谷县| 万安县| 阿合奇县| 鲁甸县| 旌德县| 筠连县|