Godbach注:
转载过来一篇介绍setuid相关函数的文章,用于了解当程序需要setuid root时候的情形。原标题为《编程 setuid, setruid函数
》,本文对标题进行了修改。
【原文】
[linux]编程 getuid,setuid函数(转载自http://sunny-day.blogbus.com/logs/1)
在linux中每个进程有三个[实际上有第4个]用户标识符.
real uid : 真实用户ID.
saved uid : 已保存用户ID
effective uid : 有效用户ID
真实用户ID(real uid)是login时的用户.而在运行过程中,
用于所有的安全检查的是有效用户ID(effective uid).
一般情况下:
real uid = saved uid = effective uid
在某些场合下,使用用setuid,setruid函数可以改变effective uid,从而
使得程序运行时具有特殊的权限.常见的例子是linux系统中的passwd命令,
由于所有的用户信息包括用户密码都保存在/etc/passwd文件中,而/etc/passwd
文件只有root权限可以读写,若想让每个用户都只可以修改自己的密码,就必须
让普通用户暂时获得有限的读写/etc/passwd的权限.用setuid就可以解决这个
问题.
Linux setuid(uid)函数:
(1)如果由普通用户调用,将当前进程的有效ID设置为uid.
(2)如果由有效用户ID符为0的进程调用,则将真实,有效和已保存用户ID都设
置为uid.
Linux的setuid函数和Unix中的setuid函数的行为是不同的.
Unix中.setuid(uid)函数的行为:
(1)如果进程没有超级用户特权,且uid等于实际用户ID或已保存用户ID,则只
将有效的用户ID设置为uid.否则返回错误.
(2)如果进程是有超级用户特权,则将真实,有效和
已保存用户表示符都设置为uid.
这里主要的区别在于普通用户调用时的行为.产生这个问题的原因是POSIX和
BSD的实现差异,而linux却同时支持这两者.BSD中使用
setreuid(uid_t ruid, uid_t euid)
来设定真实用户ID(real uid)和有效用户ID(effective uid).这个函数在由有效
用户ID符为0的进程调用时,不会改变已保存用户ID.函数seteuid(uid_t uid)等价
于setreuid(-1,uid),只改变有效用户ID(effective uid).
例子:
使用setuid或是setruid,让非root用户也可以读取只有root用户有读写权限的
文件.
#假设此程序名为:setuid_ex
#要读取的文件为:root_only.txt
我修改改写了一个c语言版本:
1. /*
2. * linux setuid example
3. * */
4. #include<unistd.h>
5. #include<fcntl.h>
6. #include<stdio.h>
7. void test_read_file(const char *name)
8. {
9. int fd = -1;
10. fd = open(name, O_RDWR);
11. if(fd < 0)
12. {
13. printf("=[ERROR]:read failed.\n");
14. }
15. else
16. {
17. printf("=[OK]: read fuccessful\n");
18. close(fd);
19. }
20.
21. }
22. //打印uid和euid.
23. void p_states(void)
24. {
25. int uid = 0;
26. int euid = 0;
27. printf("-----Current states--------------------------\n");
28. printf("real uid\t %d\n",getuid());
29. printf("effective uid\t %d\n",geteuid());
30. printf("---------------------------------------------\n");
31. }
32. //调用setuid
33. void run_setuid_fun(int uid)
34. {
35. if(setuid(uid) == -1)
36. {
37. printf("=[ERROR]:setuid(%d) error\n", uid);
38. }
39. p_states();
40. }
41. //调用seteuid
42. void run_seteuid_fun(int uid)
43. {
44. if(seteuid(uid)== -1)
45. {
46. printf("=[ERROR]:seteuid(%d) error\n", uid);
47. }
48. p_states();
49. }
50. int main()
51. {
52. int t_re = 0;
53. const char *file = "root_only.txt";
54. printf("\nTEST 1:\n");
55. p_states();
56. //此时real uid = login user id
57. //effective uid = root
58. //saved uid = root
59. test_read_file(file);
60. printf("\nTEST 2:seteuid(getuid())\n");
61. run_seteuid_fun(getuid());
62. //[2]此时 real uid= login user id
63. // effective uid = login user id
64. // saved uid = root
65. test_read_file(file);
66. printf("\nTEST 3:seteuid(0)\n");
67. run_seteuid_fun(0);
68. //read uid = lonin user id
69. //effective uid = root
70. //saved uid = root
71. test_read_file(file);
72. printf("\nTEST 4:setuid(0)\n");
73. run_setuid_fun(0);
74. //real uid = root
75. //effective uid = root
76. //saved uid= root
77. test_read_file(file);
78.
79. printf("\nTEST 5 setuid(503)\n");
80. run_setuid_fun(503);
81. //real uid = login user id
82. //effective id = login user id
83. //saved uid = login user id
84. test_read_file(file);
85. printf("\nTEST 6:seruid(0)\n");
86. //read uid = login user id
87. //effective uid = login user id
88. //saved uid = login user id
89. run_setuid_fun(0);
90. test_read_file(file);
91. return 0;
92. }
|
makefile 需要在root权限下编译,在用户权限进行执行。
src=setuid_ex.c
exe=setuid_ex
cc=gcc
flags=-g
all:
${cc} ${flags} $(src) -o ${exe}
chown root:root ${exe}
### 实际上chmod 4111改变了effective id 和saved uid的值.
### 这也是setuid setruid函数在不同权限间正常切换的前提.
chmod 4111 ${exe}
|
>>>省略原文中的C++代码部分
$ sudo make #使用root进行Make.
$ ls -l setuid_ex
---s--x--x 1 root root 58579 Jan 15 11:27 setuid_ex
$ ./setuid_ex
TEST 1:
-----Current states--------------------------
real uid 503
effective uid 0
---------------------------------------------
=[OK]: read successful.
TEST 2: seteuid(getuid())
-----Current states--------------------------
real uid 503
effective uid 503
---------------------------------------------
=[ERROR]: read failed.
TEST 3: seteuid(0)
-----Current states--------------------------
real uid 503
effective uid 0
---------------------------------------------
=[OK]: read successful.
TEST 4: setuid(0)
-----Current states--------------------------
real uid 0
effective uid 0
---------------------------------------------
=[OK]: read successful.
TEST 5: setuid(503)
-----Current states--------------------------
real uid 503
effective uid 503
---------------------------------------------
=[ERROR]: read failed.
TEST 6: setuid(0)
=[ERROR]: setuid(0) error
-----Current states--------------------------
real uid 503
effective uid 503
---------------------------------------------
=[ERROR]: read failed.
阅读(3112) | 评论(0) | 转发(0) |