有时,我们需要在程序执行过程中修改程序运行权限。
一、源码
修改程序权限主要分三步。
1. 调用 setgid() 修改组ID。
2. 调用 initgroups() 修改附加组ID(一个用户可以属于多个组)。
3. 调用 setuid() 修改用户ID。
#include <stdio.h>
#include <unistd.h>
#include <shadow.h>
#include <pwd.h>
#include <grp.h>
void get_groups()
{
const int gidsetsize = 1024;
int grouplist[gidsetsize];
// 获取附加组ID
int n = getgroups(gidsetsize, grouplist);
fprintf(stderr, "grouplist:");
for (int i = 0; i < n; i++) {
fprintf(stderr, "%d ", grouplist[i]);
}
fprintf(stderr, "\n");
}
void get_ids()
{
fprintf(stderr, "uid = %d, euid = %d, gid = %d, egid = %d\n",
getuid(), geteuid(), getgid(), getegid());
}
int main(int argc, char **argv)
{
char username[] = "likui";
char groupname[] = "likui";
// 根据用户名获取用户ID
struct passwd *pwd = getpwnam(username);
if (pwd == NULL) {
fprintf(stderr, "getopwnam error\n");
}
fprintf(stderr, "uid = %d\n", pwd->pw_uid);
// 根据组名获取组ID
struct group *grp;
grp = getgrnam(groupname);
if (grp == NULL) {
fprintf(stderr, "getgrnam error\n");
}
fprintf(stderr, "gid = %d\n", grp->gr_gid);
fprintf(stderr, "*** before ***\n");
get_ids();
get_groups();
// 检查有效用户ID是否为 root,只有 root 能切换
if (geteuid() == 0) {
// 更改组ID
if (setgid(grp->gr_gid) == -1) {
perror("setgid");
}
// 更改附加组ID
if (initgroups("likui", grp->gr_gid) == -1) {
perror("initgroups");
}
// 更改用户ID
if (setuid(pwd->pw_uid) == -1) {
perror("setuid");
}
fprintf(stderr, "*** after ***\n");
get_ids();
get_groups();
}
return 0;
}
二、运行
普通权限运行
$ ./main
uid = 1000
gid = 1000
*** before ***
uid = 1000, euid = 1000, gid = 1000, egid = 1000
grouplist:4 24 27 30 44 46 113 128 129 1000 1001
root 权限执行
$ sudo ./main
uid = 1000
gid = 1000
*** before ***
uid = 0, euid = 0, gid = 0, egid = 0
grouplist:0
*** after ***
uid = 1000, euid = 1000, gid = 1000, egid = 1000
grouplist:4 24 27 30 44 46 113 128 129 1000 1001
三、关于 initgroups
尝试注释
// 更改附加组ID
//if (initgroups("likui", grp->gr_gid) == -1) {
// perror("initgroups");
//}
root 权限运行
$ sudo ./main
uid = 1000
gid = 1000
*** before ***
uid = 0, euid = 0, gid = 0, egid = 0
grouplist:0
*** after ***
uid = 1000, euid = 1000, gid = 1000, egid = 1000
grouplist:0
grouplist 附加组ID未发生变化。