UNIX环境高级编程-第4章-4.4-4.7

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:~/桌面$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值