首页 > 代码库 > 进程篇(4: 基本进程控制:其他相关控制)--请参照本博客“操作系统”专栏

进程篇(4: 基本进程控制:其他相关控制)--请参照本博客“操作系统”专栏

1. 更改进程的用户ID和组ID:
为什么我们要更改用户ID和组ID的呢?

在UNIX系统中,特权是基于用户和组ID的。当用户需要增加特权,或要访问某个当前没有能力访问的文件时,我们需要更改自己的权限,以让新的ID具有合适的特权或访问权限。与此类似,当程序需要降低其特权或阻止对某些资源的访问时,也需要跟换用户ID或组ID;一般而言,在设计应用程序时,我们总是试图使用"最小特权"模型。依照此模型,我们的程序应当值具有为完成特定的任务所需要的最小特权

NAME
       getuid, geteuid - get user identity
SYNOPSIS
       #include <unistd.h>
       #include <sys/types.h>

uid_t getuid(void); uid_t geteuid(void); DESCRIPTION getuid() returns the real user ID of the calling process. [返回调用进程的实际用户id] geteuid() returns the effective user ID of the calling process. [返回调用进程的有效用户id] ERRORS These functions are always successful.

下面我们编写一段代码返回当前进程的实际用户id和有效用户id:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 
 6 int 
 7 main(void)
 8 {
 9     printf("the real user id of this process: %d\n",getuid());
10     printf("the effective user id of this process: %d\n",geteuid());
11     exit(0);
12 }

在以普通用户模式(用户名: jiangheng 用户id: )运行下的结果是:

the real user id of this process: 1000
the effective user id of this process: 1000

下面是在普通用户模式下用id命令得到的用户信息:

uid=1000(jiangheng) gid=1000(jiangheng) 组=1000(jiangheng),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),112(lpadmin),118(sambashare)

在root用户下执行程序:

the real user id of this process: 0
the effective user id of this process: 0

 

可以用setuid来设置实际用户id和有效用户id。与此类似的是,可以使用setgid来设置实际组id和有效组id。下面是linux manpage中对setuid函数的描述:

NAME
       setuid - set user identity  [设置用户身份]

SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>

       int setuid(uid_t uid);

DESCRIPTION
       setuid() sets the effective user ID of the calling process[setuid() 设置调用进程的有效用户id].  If the effective UID of the
       caller is root, the real UID and saved set-user-ID are also set.[如果调用进程的有效用户id是root的话,实际用户id和保存的set-user-ID位也要被设置]

       Under Linux, setuid() is implemented like the POSIX version  with  the  _POSIX_SAVED_IDS
       feature.   This  allows  a set-user-ID (other than root) program to drop all of its user
       privileges, do some un-privileged work, and then reengage the original effective user ID
       in a secure manner.[这个函数的主要用法是: 将用户的所有特权取消,然后做一些非特权化操作,最将用户的权限恢复]

       If the user is root or the program is set-user-ID-root, special care must be taken.  The
       setuid() function checks the effective user ID of the caller and if it is the superuser,
       all process-related user IDs are set to uid.  After this has occurred, it is impossible
       for the program to regain root privileges.[将具有root权限的进程权限修改之后再也不能恢复它的用户权限]

       Thus, a set-user-ID-root program wishing to temporarily drop root privileges, assume the
       identity  of  an unprivileged user, and then regain root privileges afterward cannot use
       setuid().  You can accomplish this with seteuid(2).

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

 tips: 进程实际用户ID,进程有效用户ID,进程保存的设置用户ID详解:

  • 实际用户id和实际组id : 标示"我是谁",也就是登陆用户id和gid。真实用户ID用于标识由谁为正在运行的进程负责
  • 有效用户id和有效组id : 进程用来决定我们对资源的访问权限,一般情况下有效用户id等于实际用户id,有效用户组id等于实际用户组id; 有效用户ID用于为新创建的文件分配所有权、检查文件访问许可,还用于通过kill系统调用向其它进程发送信号时的许可检查
  • 当保存的设置用户ID位被设置时,那么有效用户id等于文件所有者的uid,而不是实际用户id。

更改ID的若干规则:

  1). 如果进程具有超级用户特权,那么setuid函数将实际用户id,有效用户id,以及保存设置用户id设置为uid;

  2). 若进程没有超级用户权限,但是uid等于实际用户ID或保存的设置用户ID,那么setuid只将有效用户ID设置为uid。不改变实际用户id和保存的设置用户id;

      3). 如果上述两个条件都不满足,那么将errno设置为EPERM,并返回-1;

关于内核所维护的三个用户id:

  (1). 只有超级用户进程可以更改实际用户id。

  (2). 当且仅当对程序文件设置了设置用户ID位时,exec函数才会设置有效用户id。如果设置用户ID位没有设置,那么exec函数不会改变有效用户ID,而将其维持为原值。

 

2. 解释器文件:
  让我们观察一个实例:当执行的文件是解释器文件时,内核是如何处理exec函数的参数以及该解释器文件第一行可选参数的。