第9章
這章主要講了一堆關於進程的ID。實際用戶(組)ID、有效用戶(組)ID、保存設置用戶(組)ID、文件系統用戶(組)ID。和輔助組ID。
實際用戶ID決定執行者是誰。
有效用戶ID決定該進程執行時獲取的文件權限。PS:有效用戶ID為0的進程擁有超級用戶的所有權限。
認識保存設置用戶ID(saved set-user-ID)的時候先來看看設置用戶ID(set-user-ID)(對於文件的)。
如果可執行文件設置了設置用戶ID,當該文件執行的時候會將該進程的有效用戶ID設置為執行文件的用戶ID。
例如當某個執行文件的用戶ID為root,而且設置了設置用戶ID,那么如果某用戶(非root)運行該文件的時候,該進程的有效用戶ID就會變成root,也就是0,從而獲取超級進程用戶權限。例如passwd,ping。這兩個文件的所屬都屬於root,但是這兩個文件可以不以root來執行。通過ls -l可以看到它們設置了set-user-ID位。
lancelot@debian:~$ ls -l /bin/ping -rwsr-xr-x 1 root root 36136 4月 13 2011 /bin/ping lancelot@debian:~$ ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 51096 5月 26 2012 /usr/bin/passwd
然后我們來看一個詳細的例子:
一個可執行文件check_password要根據/etc/shadow來檢查密碼是否正確,但是訪問/etc/shadow需要權限。
lancelot@debian:~/Code/tlpi$ ls -l check_password -rwxr-xr-x 1 lancelot lancelot 16031 4月 25 22:50 check_password lancelot@debian:~/Code/tlpi$ ./check_password Username: lancelot ERROR: no permissong to read shadow password file
然后我們先修改它的用戶ID,再設置設置用戶ID權限位。然后來看看運行結果。
lancelot@debian:~/Code/tlpi$ sudo chown root check_password lancelot@debian:~/Code/tlpi$ sudo chmod u+s check_password lancelot@debian:~/Code/tlpi$ ls -l check_password -rwsr-xr-x 1 root lancelot 16031 4月 25 22:50 check_password lancelot@debian:~/Code/tlpi$ ./check_password Username: lancelot Password: Successfully authenticated: UID=1000
好了,現在來看看保存設置用戶ID了,其實就是進程的有效用戶ID的副本。
文件系統用戶ID決定文件系統操作的權限。其值通常與有效用戶ID相同。PS:當有效用戶ID發生改變,文件系統用戶ID也會緊接着發生改變(變成相同的值)。
獲取實際用戶和有效用戶ID
1 #include <unistd.h> 2 3 uid_t getuid(void); //返回調用進程的實際用戶ID 4 5 uid_t geteuid(void); //返回調用進程的有效用戶ID 6 7 gid_t getgid(void); //返回調用進程的實際組ID 8 9 gid_t getegid(void); //返回調用進程的有效組ID
修改有效ID:
1 #include <unistd.h> 2 3 int setuid(uid_t uid); 4 5 int setgid(gid_t gid);
成功修改返回0,失敗返回-1。
PS:非特權進程(有效ID為0)調用修改有效ID時,只能修改進程的有效用戶ID(將其值設置為實際用戶ID和保存設置用戶ID)。當特權進程調用修改有效ID時,實際用戶ID、有效用戶ID和保存設置用戶ID均會設置為uid的值。
1 #include <unistd.h> 2 3 int seteuid(uid_t euid); 4 5 int setegid(gid_t egid);
成功修改返回0,失敗返回-1。
PS:非特權進程僅能將有效用戶ID設置為實際用戶ID或者保存設置用戶ID。特權進程可以將有效用戶ID設置為任意值。
修改實際ID和有效ID
#include <unistd.h> int setreuid(uid_t ruid, uid_t euid); int seregid(gid_t rgid, gid_t egid);
成功修改返回0, 失敗返回-1。
第一個參數為新的實際ID,第二個參數為新的有效ID。如果只修改其中一個,可以將另一個的值設置為-1。
獲取實際、有效和保存設置ID:
1 #define _GNU_SOURCE 2 #include <unistd.h> 3 4 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); 5 6 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
成功獲取返回0,失敗返回-1。
修改實際、有效和保存設置ID:
1 #define _GNU_SOURCE 2 #include <unistd.h> 3 4 int setresuid(uid_t ruid, uid_t euid, uid_t suid); 5 6 int getresgid(gid_t rgid, gid_t egid, gid_t sgid);
成功修改返回0, 失敗返回-1。
如果不想修改的ID,可以設置為-1。
獲取和修改文件系統ID:
1 #inlcude <sys/fsuid.h> 2 3 int setfsuid(uid_t fsuid); 4 5 int setfsgid(gid_t fsgid);
--------------------------------------------------------省略輔助組ID----------------------------------------------
第10章
這章主要講了時間的概念。時間分為兩種類型:1、真實時間;2、進程時間。
真實時間:
一、日歷時間,用於對記錄或文件打上時間戳。
二、流逝時間或掛鍾時間,用於需要周期性操作或定期從外部輸入設備進行度量的程序。
日歷時間:
UNIX系統內部對時間的表示方式是自1970年1月1日早晨零點以來的秒數。
1 #include <time.h> 2 3 time_t time(time_t *timep);
返回自1970年1月1日早晨零點以來的秒數,出現錯誤返回-1。
如果timep為NULL,直接返回自1970年1月1日早晨零點以來的秒數,如果不為NULL,還會講秒數置於timep所指向的位置。
獲取到秒數后就要通過一些函數將秒數轉成人類可讀的格式。
通過ctime:
1 #include <time.h> 2 3 char *ctime(const time_t *timep);
返回指向靜態分配的字符串的指針,出現錯誤返回NULL
1 #include <stdio.h> 2 #include <time.h> 3 4 int main(int argc, char *argv[]){ 5 time_t t = time(NULL); 6 printf("%s\n", ctime(&t)); 7 return 0; 8 }
結果:
1 lancelot@debian:~/Code/tlpi$ ./a.out 2 Sat Apr 26 09:33:27 2014
有時候我們不僅需要將時間轉成可打印的格式,還需要將時間分解成很多獨立字段。這個時候就需要用到gmtime()或者localtime()。
1 #include <time.h> 2 3 struct tm *gmtime(const time_t *timep); 4 5 struct tm* localtime(const time_t *timep);
返回指向靜態分配的字符串的指針,出現錯誤返回NULL。gmtime返回的是對UTC的分解時間,localtime返回的是對系統本地時間的分解時間。
如果現在存在一個分解時間,可以通過mktime來輸出其對應的秒數。
1 #include <time.h> 2 3 time_t mktime(struct tm *timeptr);
返回自1970年1月1日早晨零點以來到分解時間的秒數,出現錯誤返回-1。
我們還可以對分解時間進行轉換,轉換成可打印時間。
1 #include <time.h> 2 3 char *asctime(const struct tm *timeptr);
返回指向靜態分配的字符串的指針,錯誤返回NULL。
------昨晚睡覺前開始寫的。。。。感覺好像搞懂了那一對關於進程的ID。。。。。還是挺開心的
------在看到別人的收獲的時候,還要看到別人付出的血汗。正因為你不夠別人勤奮,所以你才落后別人
------好好努力,為了9月份的校招!!!!!!!!還有時間!!!!!!!