4.4 设置用户ID和设置组ID
与一个进程有关的ID有6个或更多:实际用户ID 实际组ID ---------------------- 有效用户ID 有效组ID 附属组ID ---------------------- 保存的设置用户ID 保存的设置组ID
实际用户ID:这个ID标志了是哪个用户启动了该进程,通常在用户登陆的时候就已经确定了执行进程时的实际用户ID,该ID取自/etc/passwd的登陆选项。实际用户ID用
uid表示。
实际组ID: 这个ID标志了该进程属于哪个组所有,该值在用户登陆的时候就已经确定了。
进程的实际组ID用gid表示。
有效用户ID:通常进程的有效用户ID被称作euid,通常该值被设置成为了实际用户ID,但是在进程文件的SUID位被设置之后,该程序被任何用户执行产生的进程的euid将会被设置成为进程文件的属主uid。有效组ID: 进程的有效组ID被称作egid,通常该值被设置成为了实际组ID,但是在进程文件的SGID,SGID为被设置之后,该程序被任何用户执行产生的进程egid将会被设置成为进程文件的属组gid。
附属组ID: 进程的附属组ID应该是登陆用户附属于其他组时所在的组ID。
保存的设置用户ID:
保存的设置组ID:进程的实际用户uid和gid用来标志当前进程的属主和属组,euid,egid用来标志资源的访问权限,
保存的设置用户ID和保存的设置组ID由exec函数保存,在执行一个程序时,包含了有效用户ID和有效
组ID的副本。
//编写一个程序,测试进程的uid,gid,euid,egid,并且设置该程序文件的suid,sgid位。
#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>
int main(int argc,char**argv){
printf("uid=%d,gid=%d,euid=%d,egid=%d\n",getuid(),getgid(),geteuid(),getegid());
return 0;
}
//验证结果如下:
xcl@xcl:~/桌面$ ll /home/oracle/桌面/main
-rwsrwsr-x 1 root root 9856 6月 9 13:54 /home/oracle/桌面/main*
xcl@xcl:~/桌面$ /home/oracle/桌面/main
uid=1000,gid=1000,euid=0,egid=0
xcl@xcl:~/桌面$ su oracle
密码:
oracle@xcl:/home/xcl/桌面$ cd ~/桌面
oracle@xcl:~/桌面$ ./main
uid=1001,gid=1001,euid=0,egid=0
oracle@xcl:~/桌面$
4.5 文件访问权限
文件权限使用的不同方式如下: 注意:第一个规则是:当我们用名字打开任何一个类型的文件时,对该名字中包含的每一个目录,包括他可能包含的当前工作目录都需要有执行权限。 这个就是为什么对于目录,其执行权限位常被称作为搜索位的原因。 注意:目录的读权限和搜索权限是不同的,读权限的意义在于,可以获取到目录下面的目录项,这些目录项包括i节点的指针,文件的名字组成的向量。 对于执行权限,是指进程可以通过该目录去搜索该目录下面的某个特定文件。 注意:为了在打开文件的时候指定O_TRUNC方式,必须要对该文件具有写权限。 注意:为了在一个目录中创建一个文件,必须对该目录具有写权限和执行权限。 注意:如果对一个目录设置了粘连位的话,如果需要删除或者重命名目录下的某一个文件,那么就必须满足下面三个条件中的一个 进程拥有该文件 进程拥有超级权限 进程拥有该目录
注意:如果7个exec函数中的任何一个需要执行某一个文件,那么必须具有对该文件的执行权限,并且该文件必须是一个普通文件。———————————
进程对文件权限进行测试的步骤: 进程每次打开,创建或者删除文件,内核就进行文件访问权限测试,这种测试可能会涉及文件的所有者(st_uid,st_gid),进程的有效ID(euid,egid) 以及进程的附属组ID。两个所有者id(st_uid,st_gid)是文件的属性,而两个有效ID以及附属组ID是进程的属性。内核进行的测试步骤如下: (1)如果进程的euid是0,则允许访问。 (2)如果进程euid等于文件的st_uid,那么进程拥有此文件,那么所有者对该文件具有什么权限,那么进程就对该文件具有什么权限。否则拒绝访问。 (3)如果进程egid或者进程的附属组ID等于文件的st_gid,那么文件属组所具有什么权限,进程就具有什么权限。否则拒绝权限。 (4)否则进程就是其他用户,按照文件对其他用户设置的权限进行访问。 (5)以上四个步骤只要通过了一个步骤就不进行后面步骤的测试。 (6)可以将内核测试进程访问资源权限的步骤为:euid于st_uid的测试先于egid于st_gid的测试,超级管理员测试先于普通用户测试,普通用户测试先于其他用户的测试。
4.6 新文件和目录的所有权
进程使用open和creat函数创建的新文件的所有权的确定规则是:
(1)新文件的属主id等于进程的有效用户ID (2)在Linux中,如果目录的粘连位没有被设置的话,那么新文件的属组id等于进程的有效组ID (3)在Linux中,如果目录的粘连位被设置过的话,那么新文件的属组id等于该目录的属组ID
注意:经过测试,Linux中的粘连位没有对该目录下新文件的属组ID产生影响
注意:设置目录粘连位的优势是,该目录下文件的组所有权可以向下传递
//新文件和目录的所有权测试 xcl@xcl:~/桌面$ stat workspace 文件:"workspace" 大小:4096 块:8 IO 块:4096 目录 设备:2ch/44d Inode:26611605 硬链接:12 权限:(0775/drwxrwxr-x) Uid:( 1000/ xcl) Gid:( 1000/ xcl) 最近访问:2016-06-09 15:45:23.691656683 +0800 最近更改:2016-06-09 15:45:26.800419261 +0800 最近改动:2016-06-09 15:45:26.800419261 +0800 创建时间:- xcl@xcl:~/桌面$ touch workspace/xcl.txt xcl@xcl:~/桌面$ ll workspace/xcl.txt -rw-rw-r-- 1 xcl xcl 0 6月 9 15:46 workspace/xcl.txt xcl@xcl:~/桌面$ chmod o+w workspace xcl@xcl:~/桌面$ su oracle 密码: oracle@xcl:/home/xcl/桌面$ touch workspace/xcl2.txt oracle@xcl:/home/xcl/桌面$ ll workspace/xcl2.txt -rw-rw-r-- 1 oracle oracle 0 6月 9 15:46 workspace/xcl2.txt oracle@xcl:/home/xcl/桌面$ exit exit xcl@xcl:~/桌面$ chmod +t workspace xcl@xcl:~/桌面$ stat workspace 文件:"workspace" 大小:4096 块:8 IO 块:4096 目录 设备:2ch/44d Inode:26611605 硬链接:12 权限:(1777/drwxrwxrwt) Uid:( 1000/ xcl) Gid:( 1000/ xcl) 最近访问:2016-06-09 15:45:23.691656683 +0800 最近更改:2016-06-09 15:46:40.034383516 +0800 最近改动:2016-06-09 15:47:02.423875648 +0800 创建时间:- xcl@xcl:~/桌面$ su oracle 密码: oracle@xcl:/home/xcl/桌面$ touch workspace/xcl3.txt oracle@xcl:/home/xcl/桌面$ ll workspace/xcl3.txt -rw-rw-r-- 1 oracle oracle 0 6月 9 15:47 workspace/xcl3.txt
4.7 函数access,函数faccessat
正如前面所有,内核在检查进程对资源的访问权限的时候,使用的是进程的有效uid和有效gid进行测试的。
有时,进程有效uid和有效gid可能和进程实际uid和实际gid不同,而且希望进程还是能够按照实际uid和实际
gid来进行资源访问。比如当可执行文件设置了SUID和SGID位之后,该文件执行产生的进程可能具有root权限,
但启动该进程的用户并不是root用户,而这时仍然想要让进程按照当前非root用户的权限来进行资源访问,
那么函数access和faccessat具有该功能。
#include<unistd.h>
int access(const char*pathname,int mode);
int faccessat(int fd,const char*pathname,int mode,int flag);
其中,mode取值如下:
F_OK 测试文件是否已经存在 R_OK 测试读权限 W_OK 测试写权限 X_OK 测试执行权限 其中,flag可以取的值是 AT_SYMBOLINK_NOFOLLOW 不跟踪符号链接,默认跟踪 AT_EACCESS 按照进程euid,egid检查访问权限 0 默认按照uid,gid,跟踪,access函数默认也是跟踪符号链接 flag参数可以改变faccessat的行为,如果flag设置为AT_EACCESS,范文检查用的是进程的有效用户ID和有效 组ID而不是实际用户ID和实际组ID。
//编写一个程序测试access是按照进程的实际用户ID来进行资源访问测试的。
#include<fcntl.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>
int main(int argc,char**argv){
printf("uid=%d,gid=%d,euid=%d,egid=%d\n",getuid(),getgid(),geteuid(),getegid());
int fd=access("pp.txt",R_OK);
if(fd<0){
printf("当用access以实际用户进行测试的时候发现文件pp.txt不能读\n");
}else{
printf("当用access以实际用户进行测试的时候发现文件pp.txt可读\n");
}
int fd2=open("pp.txt",O_RDONLY);
if(fd2<0){
printf("以O_RDONLY调用open函数默认使用进程的有效ID进行资源访问发现pp.txt不可以读\n");
}else{
printf("以O_RDONLY调用open函数默认使用进程的有效ID进行资源访问发现pp.txt可以读\n");
}
int fd3=faccessat(AT_FDCWD,"pp.txt",R_OK,AT_EACCESS);
if(fd3<0){
printf("当用faccessat以有效用户ID读pp.txt不可读\n");
}else{
printf("当用faccessat以有效用户ID读pp.txt可读\n");
}
return 0;
}
//测试结果 oracle@xcl:~/桌面$ ll pp.txt -r-------- 1 root root 0 6月 9 16:11 pp.txt oracle@xcl:~/桌面$ ll main -rwsr-sr-x 1 root root 10128 6月 9 16:22 main* oracle@xcl:~/桌面$ ./main uid=1001,gid=1001,euid=0,egid=0 当用access以实际用户进行测试的时候发现文件pp.txt不能读 以O_RDONLY调用open函数默认使用进程的有效ID进行资源访问发现pp.txt可以读 当用faccessat以有效用户ID读pp.txt可读 oracle@xcl:~/桌面$