程序管理2
1、使用者群組:
程序是和使用者群組關聯的,使用者id群組id分别是C語言的uid_t和gid_t類型表示。數字表示和可讀字元串之間的映射關系
是通過使用者空間的/etc/passwd和/etc/group兩個檔案完成的,核心隻處理數字表示形式。
在Unix系統中,一個程序的使用者ID群組ID代表這個程序可以執行哪些檔案操作以及向其他程序發送信号的能力。程序必須以
合适的使用者群組運作,最好的方式是遵循“最小權限”的原則。這個要求是變化的:如果程序在前期需要以root使用者的權限
運作,那麼後面不需要root權限了,那麼就應該在後面盡可能采用權限更小的使用者權限運作。
1)一個程序的 real user ID 是指運作此程序的使用者角色的 ID。
2)一個程序的 effective user ID 是指此程序目前實際有效的使用者 ID(也就是權限的大小),effective user ID 主要用來
校驗權限時使用,比如打開檔案、建立檔案、修改檔案、向别的程序發信号,等等。
如果一個程序是以 root 身份來運作的,那麼上面這兩個 ID 可以用 setuid/seteuid 随便修改,但是如果一個程序是以普通
使用者身份來運作的,那麼上面這兩個 ID 一般來說是相同的,并且也不能随便修改。隻有一種情況例外:
此程序的可執行檔案的權限标記中,設定了“設定使用者 ID”位!
3)設定使用者id是檔案權限的一個标記,可以通過
chmod +s /path/to/file
來設定使用者id位。一旦用了這個指令之後,再執行這個檔案,那麼生成的程序的 effective user ID 就變成了這個可執行檔案
的 owner user ID(屬主使用者 ID)。
4)儲存的設定使用者id,是程式在執行exec一個setuid程式(設定了設定使用者id标記位的檔案)之前的有效使用者id,這樣可以儲存
通過儲存的設定使用者id來恢複之前的有效使用者的id
當一個使用者登入的時候,login程式會把真實的使用者ID和有效的使用者ID設定成/etc/passwd檔案中指定的UID,當一個程序fork的
時候,子程序會從父程序那繼承它。真實UID和真實GID辨別程序的真實所有者,會影響到發送信号的權限。
2、改變實際使用者(組)ID 和儲存設定的使用者(組)ID
Cpp代碼
- #include <sys/types.h>
- #include <unistd.h>
- int setuid(uid_t uid);
- int setgid(gid_t gid);
#include <sys/types.h>
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
setuid是用來設定目前程序的有效id。如果目前使用者的有效id是root,那麼實際使用者id和儲存設定的使用者id也會被同時設定為uid,
root使用者可以為uid提供任何值,進而将所有三種使用者id都設定成uid了。非root使用者隻允許将實際使用者id和儲存設定的使用者id最為
uid的實際參數傳遞,也就是有效使用者id隻能是這兩種的一個值。
成功傳回0,錯誤傳回-1,并設定errno:
EAGAIN: uid的值和實際使用者id的值不同,把uid設定為real user id會讓使用者超過他的NRPOC限制(它指定了一個使用者可以擁有的
程序數)。
EPERM:使用者不是root,uid既不是有效也不是儲存使用者ID。
上面的讨論也适合setgid。
3、改變有效使用者或者組id:
Linux提供了兩個POSIX所定義的函數來改變目前程序的有效使用者id群組id的值:
- int seteuid(uid_t euid);
- int setegid(gid_t egid);
#include <sys/types.h>
#include <unistd.h>
int seteuid(uid_t euid);
int setegid(gid_t egid);
seteuid是将有效使用者ID的值設定為euid。root使用者可以為euid提供任何值,而非root使用者隻能将有效使用者ID設定設定為實際使用者
ID或者儲存設施的使用者ID。成功傳回0,失敗傳回-1,并且把errno設定為EPERM,它代表目前程序的所有者不是root使用者,并且euid
既不等于使用者ID也不同于實際使用者id也不等于儲存使用者id。
非root使用者,seteuid和setuid的行為一樣。始終使用seteuid()是一個标準實踐和好的方法,除非你的程序傾向于以root身份運作,
這樣setuid會變得更有意義。
4、獲得使用者群組ID:
以下兩個系統調用傳回真實使用者群組的ID:
- #include <sys/type.h>
- uid_t getuid(void);
- gid_t getgid(void);
#include <unistd.h>
#include <sys/type.h>
uid_t getuid(void);
gid_t getgid(void);
相應的以下兩個系統調用傳回有效使用者群組的ID:
- uid_t geteuid(void);
- gid_t getegid(void);
#include <unistd.h>
#include <sys/type.h>
uid_t geteuid(void);
gid_t getegid(void);
這兩組系統調用不會失敗。
5、會話和程序組:
每個程序都屬于某個程序組,程序組是由一個或者多個互相間有關聯的程序組成,它的目的是為了作業控制。
程序組的主要特征是信号可以給程序組中的所有的程序:這個信号使同一個程序組中的所有程序終止、停止
或者繼續運作。
每一個程序組都由程序組ID(pgid)唯一來辨別,并且有一個組長程序(process goup leader),程序組的ID
就是組長程序的pid。隻要在某個程序組中還有一個程序存在,則該程序組就存在,即使組長程序終止了,該程序
仍然存在。
當新的使用者登入計算機時,登入程序就會為這個使用者建立一個新的會話。這個會話中隻有使用者登入shell這一個程序。
登入shell作為會話首程序(session leader)。會話囊括了登入使用者的所有活動,并且配置設定給使用者一個控制終端。
1)與會話相關的系統調用:
在登入時,shell會建立新的會話。這是通過以下系統調用完成的:
- pid_t setsid(void);
#include <unistd.h>
pid_t setsid(void);
setsid建立的新會話,并在其中建立一個新的程序組,而且調用程序稱為新會話的首程序和程序組的組長程序。
成功傳回,新會話的會話ID,錯誤時,傳回-1,并把errno設定成EPERM,表示調用程序是目前程序組的組長程序。
有一個簡單的方法可以使得任何程序都不成為組長程序:建立一個新程序,終止父程序,讓子程序來調用setsid。
例如:
- pid_t pid;
- pid = fork();
- if(pid == -1){
- perror("fork");
- return -1;
- }else if(pid != 0){
- exit(EXIT_SUCESS);
- }
- if(setsid() == -1){
- perror("setsid");
pid_t pid;
pid = fork();
if(pid == -1){
perror("fork");
return -1;
}else if(pid != 0){
exit(EXIT_SUCESS);
}
if(setsid() == -1){
perror("setsid");
return -1;
}
獲得目前程序的會話id,雖然不怎麼常用:
- pid_t getsid(pid_t pid);
#include <unistd.h>
pid_t getsid(pid_t pid);
調用成功傳回程序會話ID。如果參數是0,則傳回調用程序的會話id。
錯誤傳回-1,并設定errno為ESRCH,表示pid不代表任何程序。
其他的UNIX系統可能設定errno為EPERM,它表示pid訓示的程序和調用程序不屬于同一個會話。Linux
傾向于傳回任何程序的會話id。
- pid_t sid;
- sid = getsid(0);
- if(sid == -1)
- perror("getsid");
- else
- printf("My session id=%d\n",sid);
pid_t sid;
sid = getsid(0);
if(sid == -1)
perror("getsid");
else
printf("My session id=%d\n",sid);
2)與程序組相關的系統調用:
setpgid将程序pid的程序的程序組ID設定為pgid:
- int setpgid(pid_t pid, pid_t pgid);
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
如果pid是0,則使用調用者的程序id。如果pgid是0,則将pid程序的id設定為程序組的ID。
成功傳回0。
a)pid代表的程序必須是調用者或者是其子程序,而且子程序沒有調用過exec函數,并且pid程序和
調用者在同一個會話中。
b)pid程序不能使會話首程序。
c)如果pgid已經存在,那麼必須與調用者在同一個會話中。
d)pgid非負。
錯誤傳回-1,并且把errno設定成:
EACCESS pid程序是迪歐用程序的子程序,并且子程序調用了exec函數。
EINVAL pgid < 0
EPERM pid程序是會話的首程序,或者與調用者不在同一個會話中的另一個程序。也可能試圖把程序放置
到一個不同在一個會話的程序組中。
ESRCH pid不是目前程序或者目前程序的子程序。
可以通過會話獲得程序的程序組ID:
- pid_t getpgid(pid_t pid);
#include <unistd.h>
pid_t getpgid(pid_t pid);
- pid_t pgid;
- pgid = getpgid(0);
- if(pgid == -1)
- perror("getpgid");
- printf("My process group id=%d\n",pgid);
pid_t pgid;
pgid = getpgid(0);
if(pgid == -1)
perror("getpgid");
else
printf("My process group id=%d\n",pgid);