因为某种原因 感觉心里一直有想把Unix有关文件权限编程这部份弄懂的想法, 所以第三遍看Unix高级编程第四章, 以前都是一眼带过, 根本没看吃透, 再次看感觉懂了蛮多的, 写下了以后复习用!
一: 一个进程相关的ID主要有:
实际用户ID 实际组ID : 标识空间我们是谁, 登录时取自口令文件登录项,登录会话期间一直不变,超级用户可改变
有效用户ID 有效组ID : 决定了我们的文件访问权限,也就是用来测试本进程对某些文件的访问权限
保存的设置用户ID,设置组ID: 执行一个程序时包含了有效用户ID 和有效组ID的副本
ps: 通常 有效用户ID等于实际用户ID,有效组ID等于实际组ID ,当执行一个文件时, 如果文件设置了设置用户ID位或设置用户组ID位 即SUID SGID 则情况不同
二: 进程每次打开一个文件时, 内核进行访问权限测试:
涉及到用户所有者(st_uid st_gid), 进程有效ID(有效用户ID和有效组ID)以及附加组ID(若支持的话)
所有者ID是文件的性质, 两个有效ID和附加组ID则是进程的性质。
内核进行的测试步骤:
1. 如果进程的有效用户ID是0(超级用户), 则允许访问
2. 若进程有效用户ID等于文件所有者ID, 则根据文件所有者所设置的权限访问
点击(此处)折叠或打开
- -rwxr-xr-x 1 201 202 1891 7月 16 10:24 test.sh
如上, 如果进程的有效用户ID 等于201, 则进程对文件的权限为 -rwxr-xr-x 紫色所表示的权限
3. 如进程的有效组ID或进程的附加组ID之一等于文件的组ID(即文件的实际组ID) , 那么进程对文件的权限为文件所有组所设置的权限 .
还是上面这个例子, 如果进程的有效组ID或附加组ID之一为202的话, 那么进程对文件的权限 为 -rwxr-xr-x 紫色所表示的权限
4. 若其他用户适当权限被设置 则进程此文件的权限为文件的其他访问权限
就是上面例子的最后三位权限了!
注意: 这四步是依次执行的, 如果不是超级用户, 但是进程拥有此文件( 也就是有效用户ID等于文件的实际用户ID) 那么就按文件所有者权限来确认进程对此文件的权限, 后面的步骤不再执行!
对于进程访问文件权限测试的总结
从上面可以看出, 内核对进程文件的权限测试 主要是针对 进程的有效用户ID来进行测试的, 也就是说, 如果有效用户ID 等于文件所有者ID 那么我(打开文件的进程) 就是文件的所有者 拥有文件所有者所拥有的权限, 如果不是文件的所有者 就再测试进程有效组ID...
三:文件模式中的设置用户ID位和设置组ID位
关于具体的描述网上很多文章都说了, 简单说下书上说的:
文件 设置用户ID位: 当执行此文件时, 将进程的有效用户ID设置成文件的所有者用户ID
设置组ID位: 当执行此文件时, 将进程的有效组ID设置成文件的组所有者ID
- -rwsr-sr-x 1 200 201 1891 7月 16 10:24 test.sh
如上 -rwsr-sr-x 紫色表示文件设置了 设置用户ID位; -rwsr-sr-x 紫色表示设置了 设置组ID位 , 如果这里的S位为大写, 表示执行位没有设置,连文件执行位都没设置, 那么设置了 设置用户或设置组ID位 也没有用。
最经常看到的例子:
passwd程序就是一个设置用户ID程序, 允许任何用户修改其口令, 因为命令可以将新口令写入口令文件/etc/passwd, 但只有超级用户才有该文件的写权限, 所以设置了该passwd设置用户ID位, 当执行passwd时, 进程有效用户ID设置成程序passwd的所有者ID, 即root, 所以可以写入新命令到口令文件中了!
四: 新文件和新目录的所有权
1. 新文件的用户ID设置成进程的有效用户ID
2. 新文件的组ID两种情况:
(1) 新文件的组ID是进程的有效组ID
(2) 如果新文件的组ID所在目录的设置组ID位 设置了的话, 新文件的组ID将设为目录的组ID (这设置组ID位这里的作用与权限测试的时候有点类似)
3. 其他:
(1). mkdir 函数自动的传递了目录的设置组ID位
(2) access 函数是用实际用户ID和实际组ID来进行访问权限的测试的, 如果你只想测试下实际用户所拥有的权限 ,就可以使用这个函数了。
五:编程应用
1. 在执行exec前后 进程的实际用户ID和实际组ID不变, 而有效ID 取决于所执行的程序文件 是否设置了设置用户ID位和设置组ID位, 如果设置了 设置用户ID位, 则有效用户ID变成程序文件所有者ID,否则有效用户ID不变, 对组ID处理方式与此相同,
2. 保存的设置用户ID是由exec复制有效用户ID后得来的, 所有第一点里面介绍设置用户ID时说 是有效用户ID的副本!
3. 一般设计应用程序时, 总是试图使用最小特权模型, 依照模型, 程序应当只具有为完成任务所需的最小特权.
4. 使用函数:
- #include ,unistd.h>
- int setuid(uid_t uid); //设置实际用户ID和有效用户ID,如果进程为超级用户,则会设置实际、有效、保存的设置用户ID
- int setgid(gid_t gid); //设置实际组ID和有效组ID
- int setreuid(uid_t ruid, uid_t euid); //交换实际用户ID和有效用户ID
- int setregid(gid_t rgid, gid_t egid);
- int seteuid(uid_t uid); //更改有效用户ID
- int setegid(gid_t gid);
注意:
根据书上来看, 特权用户使用这几个函数的时候, 都是直接用参数的值来设置实际用户ID或者有效用户ID,这些值都可以是任意的.
例如:setreuid(ruid, euid), 如果是特权用户,则直接设置实际用户ID为ruid,有效用户ID为euid
但非特权用户就不行了, 非特权用户用setuid(), seteuid()则只能将有效有户ID设置为实际用户ID或保存的设置用户ID,如果不是这两个数,设置失败!
对编程应用方面的总结:
非特权用户不能指定任意的有效用户ID, 结合其他几个函数来交换或设置有效用户ID, 与设置用户ID位 一起实现权限的控制
六: 以书上的例子结束
man程序文件的所有者及他属组通宵是为man自身保留的用户和组, man可能需要执行许多其他命令,以处理包含显示手册页的文件,为了防止被欺骗或重写错误文件, man在两种权限间切换: 运行man命令用户的权限, 拥有man可执行文件用户的权限
1. man程序文件由名为man的用户所拥有, 设置用户ID位已设置, exec 此程序时 , 用户ID情况:
实际用户ID = 我们的用户ID
有效用户ID = man //因为设置用户ID位,所有进程的有效用户ID成了文件的所有者ID
保存的设置用户ID = man // 保存的设置用户ID,复制有效用户ID得来
2. 程序访问需要的配置文件和手册页,这些文件由man用户拥有, 因为有效用户ID是man,所以可以访问
3. man 代表我们运行任一命令前, 调用setuid(getuid()) , 我们不是超级用户, 所以仅仅改变有效用户ID, 用户ID情况变成:
实际用户ID = 我们的用户ID (未改变)
有效用户ID = 我们的用户ID
保存的设置用户ID = man
现在man 以有效用户为我们的用户ID运行, 所以man 只能搜索我们通常可以访问的文件, 代表我们安全的执行一次过滤
4. 当过滤完成后 , 再调用setuid(euid), {euid 由用户man调用geteuid()保存下来, 这里setuid的参数为设置用户ID 所以是许可的} ,现在用户ID情况:
实际用户ID = 我们的用户ID (未改变)
有效用户ID = man
保存的设置用户ID = man (未改变)
注意: 一个进程无法直接获取他的保存的设置用户ID, 但因为exec时设置用户ID是由复制有效ID获取的, 所以开始时应该用euid=geteuid()保存这个有效ID 即后面的设置用户ID, 供这里使用.
5. 因为有效用户是man, 所以现在可以对其他文件进行操作了