与进程相关的ID有如下几个:
1.实际用户ID、实际组ID
2.有效用户ID、有效组ID、附属组ID
3.保存的用户ID、保存的组ID
第一组标识我们实际的ID,比如登录shell使用的ID;第二组是进程运行时用于判断文件访问权限的ID,这个是跟访问权限息息相关的;第三组是当我们的ID发生变化时保存的值,方便我们找回。
正常情况下实际ID和有效ID是相等的,但是如果我们配置了设置用户ID和设置组ID标志位,那么会在exec执行后,改变对应的有效ID为文件所有者ID和文件所属组ID,并且把新ID保存起来。
Linux提供了对应的修改ID的API:
int setuid(uid_t uid); //设置实际用户ID
int setgid(gid_t gid); //设置实际组ID
int seteuid(uid_t uid); //设置有效用户ID
int setegid(gid_T gid); //设置有效组ID
当我们具有root权限时,上述ID设置可以是任意的ID,如果非root权限执行,那么只能设置为(实际ID/保存的ID)两者之一,否则会设置失败。
文件的st_mode有两个位用来表示设置用户ID和设置组ID:
S_ISUID 执行时设置用户ID
S_ISGID 执行时设置组ID
这两个位的关键作用是可以用来设置可执行文件,当该可执行文件被exec执行时,会以文件所属用户ID或者文件所属组ID来运行该文件,而不是当前的实际用户ID和实际组ID。
比如一个可执行程序daemon,它属于root用户所有,我们直接运行该程序是以当前实际用户ID来运行,如果把该文的设置用户ID标志位配置上,那么就会以root权限去运行该程序。
~/work/qemu/sdk/test$ ls -l daemon
-rwxrwxr-x 1 root xiehaocheng 14090 3月 20 16:29 daemon
~/work/qemu/sdk/test$ sudo chmod +s daemon
~/work/qemu/sdk/test$ ls -l daemon
-rwsrwsr-x 1 root xiehaocheng 14090 3月 20 16:29 daemon
可以直接使用chmod命令设置对应的st_mode:
chmod +s daemon #设置用户ID位
chmod +ss daemon #设置用户ID位和设置组ID位
如果在代码中修改,可以参考如下示例:
struct stat statbuf;
stat("daemon", &statbuf);
chmod("daemon", statbuf.st_mode | (S_ISUID | S_ISGID));