在Linux系统中,为了系统安全,通常程序不会直接以root用户运行,而是以它所需要的最小权限的用户运行。但是程序中有部分代码,却必须要root权限运行,此时,就必须在程序中进行提权操作,暂时将权限提升至root权限。执行完对应代码后,降回原来权限。这样,既能保证程序功能正常,也能保证系统安全。
此文介绍通过sudo的方式来提升程序权限。
sudo
sudo是Linux系统管理指令,是允许系统管理员让普通用户执行一些或者全部的root命令的一个工具。简单来说,就是普通用户可以通过sudo执行root用户才能执行的操作(前提是root用户在sudo配置文件中,配置了对应Alias)。
sudo配置
Linux系统中,将需要切换到root身份下的用户及其能执行的操作等相关信息,存储在/etc/sudoers中。需要注意,配置sudo需要在root用户下进行。一般将/etc/sudoers的语句称为Alias。Alias主要分为4种:
1)Host_Alias:即允许的主机名列表,如:Host_Alias HOST_FLAG=hostname1,hostname2,hostname3,表示只能在运行的主机上进行sudo操作。
2)Cmnd_Alias:即允许执行的命令列表,命令前加!表示不允许执行此命令。如:Cmnd_Alias COMMAND_FLAG=command1,command2,!command3,表示可以通过sudo执行command1,command2,不可以执行command3。
3) User_Alias:即拥有sudo权限的用户列表。如:User_Alias USER_FLAG=user1,user2,user3。
4)Runas_Alias:即用户已什么身份执行的列表。如:Runas_Alias RUNAS_FLAG=operator1,operator2,operator3。
配置格式为:
USER_FLAG HOST_FLAG=(RUNAS_FLAG) COMMAND_FLAG
如下图,则表示 operator用户可以通过sudo指令,以root身份,执行reboot和cat指令。
root ALL=(ALL) ALL
Cmnd_Alias COMMAND_FLAG=/sbin/reboot,/bin/cat
operator ALL=(root)NOPASSWD:COMMAND_FLAG
场景应用
如下,我们在root用户中,创建文件helloWorld.txt,并将其文件权限设置为400,即只有root用户才能查看文件内容。
root@tz:/tmp# echo "hello world !" > helloWorld.txt
root@tz:/tmp# chmod 0400 helloWorld.txt
root@tz:/tmp# cat helloWorld.txt
hello world !
root@tz:/tmp#
其他用户(以operator为例)尝试查看文件内容,提示权限不允许。
@tz:/tmp$ ls -l helloWorld.txt
-r-------- 1 0 0 14 Dec 26 15:54 helloWorld.txt
@tz:/tmp$ echo ${USER}
operator
@tz:/tmp$ cat helloWorld.txt
cat: can't open 'helloWorld.txt': Permission denied
@tz:/tmp$
此时,我们在/etc/sudoers下配置如下Alias,使operator能通过sudo执行cat指令。
root ALL=(ALL) ALL
Cmnd_Alias COMMAND_FLAG=/bin/cat
operator ALL=(root) NOPASSWD:COMMAND_FLAG
再切换到operator用户,执行sudo cat helloWorld.txt,执行结果为
@tz:/tmp$ ls -l helloWorld.txt
-r-------- 1 0 0 14 Dec 26 16:04 helloWorld.txt
@tz:/tmp$ sudo cat helloWorld.txt
hello world !
@tz:/tmp$
说明配置生效了。将Cmnd_Alias添加 !/bin/chmod,让operator不能执行/bin/chmod指令。再分别执行如下shell脚本。
#!/bin/sh
name=$(echo ${USER})
echo "I am $name"
ls -l /tmp/helloWorld.txt
sudo cat /tmp/helloWorld.txt
sudo chmod 777 /tmp/helloWorld.txt
ls -l /tmp/helloWorld.txt
root用户下的执行结果如下图,可以看到,cat执行成功,chmod也执行成功,文件的权限被改成了777。
root@tz:/tmp# /tmp/test.sh
I am root
-r-------- 1 root root 14 Dec 26 16:04 /tmp/helloWorld.txt
hello world !
-rwxrwxrwx 1 root root 14 Dec 26 16:04 /tmp/helloWorld.txt
root@tz:/tmp#
operator用户的执行结果如下,cat执行成功,chmod执行时报错,提示不被允许执行chmod,文件权限仍为400。
@tz:/tmp$ /tmp/test.sh
I am operator
-r-------- 1 0 0 14 Dec 26 16:04 /tmp/helloWorld.txt
hello world !
Sorry, user operator is not allowed to execute '/bin/chmod 777 /tmp/helloWorld.txt' as root on tz.
-r-------- 1 0 0 14 Dec 26 16:04 /tmp/helloWorld.txt
@tz:/tmp$
除了shell脚本中,C语言程序中,也可通过sudo暂时提升权限。如下程序,通过execve执行cat /tmp/helloWorld.txt。
int main(void)
{
char *argv[] = {"/bin/cat", "/tmp/helloWorld.txt", NULL};
char *envp[] = {0, NULL};
execve("/bin/cat", argv, envp);
return 0;
}
root用户的执行结果如下,能正常获取helloWorld.txt文件内容。
root@tz:/tmp# ls -l helloWorld.txt
-r-------- 1 root root 14 Dec 26 16:04 helloWorld.txt
root@tz:/tmp# /tmp/cwmpd
hello world !
root@tz:/tmp#
operator用户下,执行结果表明用户权限不允许。
@tz:/tmp$ ls -l helloWorld.txt
-r-------- 1 0 0 14 Dec 26 16:04 helloWorld.txt
@tz:/tmp$ /tmp/cwmpd
cat: can't open '/tmp/helloWorld.txt': Permission denied
@tz:/tmp$
更改程序,使用sudo执行cat /tmp/helloWorld.txt,代码如下:
int main(void)
{
char *argv[] = {"sudo", "/bin/cat", "/tmp/helloWorld.txt", NULL};
char *envp[] = {0, NULL};
execve("/usr/bin/sudo", argv, envp);
return 0;
}
operator用户执行结果如下,能正常获取文件内容。
@tz:/tmp$ ls -l helloWorld.txt
-r-------- 1 0 0 14 Dec 26 16:04 helloWorld.txt
@tz:/tmp$ /tmp/cwmpd
hello world !
@tz:/tmp$
作为对比,使用sudo执行chmod的执行结果如下。
int main(void)
{
char *argv[] = {"sudo", "/bin/chmod", "777", "/tmp/helloWorld.txt", NULL};
char *envp[] = {0, NULL};
execve("/usr/bin/sudo", argv, envp);
return 0;
}
@tz:/tmp$ ls -l helloWorld.txt
-r-------- 1 0 0 14 Dec 26 16:04 helloWorld.txt
@tz:/tmp$ /tmp/cwmpd
Sorry, user operator is not allowed to execute '/bin/chmod 777 /tmp/helloWorld.txt' as root on tz.
@tz:/tmp$
执行结果与shell脚本一致,表明sudo配置生效。并且能在shell脚本中和C程序中,通过sudo提升执行权限。