进程中的三种用户ID

 

1)进程中三种用户ID的含义

表12-2列出了进程执行时,与进程相关联的三种用户ID,这三种ID在Linux书刊中经常提及,但也是易混淆不好理解的地方。

                     表12-2 三种用户ID意义表

 与每个进程相关联的用户ID和组ID

实际用户ID

我们实际上是谁,ID号保存的是启动进程用户ID和组ID

实际组ID

有效用户ID

用于文件存取许可权检查。当执行码设置了设置-用-ID (set-user-ID)位时,此时进程的有效用户为该文件所属用户,同时就获取了所属用户的用户权限。有效组同理

有效组ID

保存的设置-用户-ID

用来保存有效用户ID和有效组ID的副本

保存的设置-组-ID

     实际用户ID和实际组ID标识我们究竟是谁,这两个字段是用户登录时取自口令文件中的登录项。通常,在一个登录会话期间这些值并不改变,但是超级用户进程可以对这两个ID值随便改。

    有效用户ID、有效组ID决定了文件访问权限。有效用户ID、有效组ID主要用来校验文件权限时使用,比如打开文件、创建文件、修改文件、kill别的进程等。

     保存的设置-用户-ID和设置-组-ID在执行一个程序时保存了有效用户ID和有效组ID的副本。

     通常,当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID通常是实际组ID。

     每个文件有一个所有者(属主)和组所有者(属组),所有者由stat结构(文件属性结构)中的st_uid表示,组所有者则由st_gid成员表示。当在文件方式字 (st_mode)中设置一个特殊标志时(其含义是“当执行此文件时,将进程的有效用户ID设置为文件的所有者 (st_uid)”),此时有效用户ID就不一定等于实际用户ID。与此相类似,在文件方式字中可以设置另一位,它使得执行此文件进程的有效组ID设置为文件的组所有者 (st_gid)。在文件方式字中的这两位被称之为设置-用户-ID(set-user-ID)位和设置-组-ID(set-group-ID)位。注意设置-用户-ID位和保存的设置-用户-ID是两个不同的字段,前一个是一个特殊标志,后一个是用来保存有效用户ID的副本。

    例如假设Y用户有一执行码test,此时test的设置-用户-ID(set-user-ID)位没有设置。X用户执行Y用户的执行码test时,此时test实际用户ID等于X用户ID,有效用户ID等于X用户ID,保存的设置用户ID等于X用户ID,三类组ID同理。由于,有效用户ID决定了执行码的用户权限,所以test执行码是X用户权限,有权限读取和修改X用户的文件,而对Y用户的文件则不一定有权限。

    当test的设置-用户-ID(set-user-ID)位进行了设置时,X用户执行Y用户的执行码test,此时test实际用户ID等于X用户ID,有效用户ID等于Y用户ID,保存的设置-用户-ID等于Y用户ID,三类组ID同理。此时test执行码为Y用户权限,有权限读取和修改Y用户的文件,而对X用户的文件不一定有权限。如果要让test某一段时间内有X用户的权限,则可用seteuid(getuid())方法把有效用户ID修改为实际用户ID(即X用户ID);随后test又想恢复Y用户权限,则可把有效用户ID重置,因为设置-用户-ID是以前有效用户ID的副本,在非特权用户下系统会根据设置-用户-ID的值判断此有效用户ID设置是否允许。在非特权用户下,有效用户ID重新设置时只能等于实际用户ID或保存的设置-用户-ID。

 

(2)setuid函数和setgid函数原型

        setuid(设置真实的用户识别码)

所需头文件       

#include <unistd.h>

函数说明

setuid()用来重新设置执行目前进程的用户识别码。不过,要让此函数有作用,其有效的用户识别码必须为0(root)。在Linux下,当root使用setuid()来变换成其他用户识别码时,root权限会被抛弃,完全转换成该用户身份,也就是说,该进程往后将不再具有可setuid()的权利,如果只是向暂时抛弃root 权限,稍后想重新取回权限,则必须使用seteuid()

函数原型

int setuid(uid_t uid)

函数传入值

uid

设置实际用户ID号

函数返回值

成功

0

出错

-1,失败原因存于errno中

附加说明

一般在编写具有setuid root的程序时,为减少此类程序带来的系统安全风险,在使用完root权限后建议马上执行setuid(getuid());来抛弃root权限

          

             setgid(设置真实的组识别码)

所需头文件

#include <unistd.h>

函数说明

setgid()用来将目前进程的真实组识别码(real gid)设成参数gid值。如果是以超级用户身份执行此调用,则real、effective与saved  gid都会设成参数gid

函数原型

int setgid(gid_t gid)

函数传入值

gid

设置实际组ID号

函数返回值

成功

0

出错

-1,失败原因存于errno中

错误代码

EPERM:并非以超级用户身份调用,而且参数gid 并非进程的effective gid或saved gid值之一

 

(3)setuid和setgid函数使用说明

可以用setuid函数设置实际用户ID和有效用户ID。与此类似,可以用setgid函数设置实际组ID和有效组ID。

 

使用setuid改变用户ID的规则:

①    若进程具有超级用户特权,则setuid(uid)执行时将实际用户ID、有效用户 ID,以及保存的设置-用户-ID设置为uid。

②    若进程没有超级用户特权,但是uid等于实际用户ID或保存的设置-用户-ID,则setuid(uid)执行时只将有效用户ID设置为uid,不改变实际用户ID和保存的设置-用户-ID。

③    如果上面两个条件都不满足,则errno设置为EPERM,并返回出错。

 

关于内核所维护的三个用户ID的说明:

①    只有超级用户进程可以更改实际用户ID。通常,实际用户ID是在用户登录时,由login程序设置的,而且决不会改变它。因为login是一个超级用户进程,当它调用setuid时,设置所有三个用户ID。

②    仅当对程序文件设置了设置-用户-ID位时,exec函数会设置有效用户ID。如果设置-用户-ID位没有设置,则exec函数不会改变有效用户ID,而将其维持为原先值。任何时候都可以调用setuid,将有效用户ID设置为实际用户ID或保存的设置-用户-ID。

③    “保存的设置-用户-ID是进程exec时从有效用户ID复制而来,复制后并将此副本保存起来。

 

       表12-3列出了改变三种用户ID的不同方法表。从表中可以看出,有效用户ID是主角,因为有效用户ID决定了进程对文件的访问权限,非特权用户下有效用户ID的值重新设置时只能等于实际用户ID或保存的设置-用户-ID。

         表12-3 改变三种用户ID的不同方法表

  ID

        exec

          setuid(uid)

设置-用户-ID位关闭

设置-用户-ID位打开

超级用户

非特权用户

实际用户ID

不变

不变

设为uid

不变

有效用户ID

不变

设置为程序文件的用户ID

设为uid

设为uid

保存的设置-用户-ID

从有效用户ID复制

从有效用户ID复制

设为uid

不变

 

(4)seteuid和setegid函数原型

         seteuid(设置有效的用户识别码)

所需头文件

#include <unistd.h>

函数说明

seteuid()用来重新设置执行目前进程的有效用户识别码。在Linux下,seteuid(euid)相当于setreuid(-1,euid)

函数原型

int seteuid(uid_t euid)

函数传入值

euid

设置有效用户的ID号

函数返回值

成功

0

出错

-1,失败原因存于errno中

 setegid(设置有效的组识别码)

所需头文件

#include <unistd.h>

函数说明

设置执行目前进程的有效组识别号

函数原型

int setegid(gid_t egid)

函数传入值

egid

设置有效组ID号

函数返回值

成功

0

出错

-1,失败原因存于errno中

 

(5)seteuid和setegid函数说明

seteuid和setegid它们只更改有效用户ID和有效组ID。

执行seteuid(uid)时,对于一个非特权用户只有uid等于实际用户ID或其保存的设置-用户-ID时才能设置。对于一个超级特权用户则可将有效用户ID可设置为uid(这区别于setuid函数,特权用户下它更改的是三个用户ID)。

 

(6)函数举例说明几种ID的作用

在X用户下编写setid.c源文件,内容如下。

#include <unistd.h>

#include <pwd.h>

#include <sys/types.h>

#include <stdio.h>

int main(int argc,char **argv)

{

    pid_t my_pid,parent_pid;

    uid_t my_uid,my_euid;

    gid_t my_gid,my_egid;

    my_uid=getuid();

    my_euid=geteuid();

    my_gid=getgid();

    my_egid=getegid();

    printf("User ID%ld\n",my_uid);

    printf("Effective User ID%ld\n",my_euid);

    printf("Group ID%ld\n",my_gid);

    printf("Effective Group ID%ld\n",my_egid)  ;

    system("wc -l xx") ;

 

    seteuid(getuid()) ;

    setegid(getgid()) ;

    my_uid=getuid();

    my_euid=geteuid();

    my_gid=getgid();

    my_egid=getegid();

 

    printf("after seteuid(getuid())\n");

    printf("User ID%ld\n",my_uid);

    printf("Effective User ID%ld\n",my_euid);

    printf("Group ID%ld\n",my_gid);

    printf("Effective Group ID%ld\n",my_egid)  ;

    system("wc -l xx") ;

 

    return 0 ;

}

①    编译 gcc setid.c –o setid。

②    设置执行码设置-用户-ID(set-user-ID)位和设置-组-ID(set-group-ID)位。

$chmod u+s setid

$chmod g+s setid

③    用vim xx文件输入几行内容,用chmod 700设置xx文件的权限。

④    用id命令查看X用户的用户ID和组ID,结果如下:

uid=1008(X) gid=1003(XX)

⑤    到Y用户下,用id命令查看Y用户的用户ID和组ID,结果如下:

uid=1016(Y) gid=1001(YY)

⑥    在Y用户到相应目录执行./setid,执行结果如下:

User ID1016

Effective User ID1008

Group ID1001

Effective Group ID1003

3 xx

after seteuid(getuid())

User ID1016

Effective User ID1016

Group ID1001

Effective Group ID1001

wc: xx: Permission denied

 

        摘录自《深入浅出Linux工具与编程》

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值