sudo
执行需要 root 权限的程序时, 输入的是当前用户的口令而不是 root 的?看一下
sudo
的 manpage, 描述是 "execute a command as another user". 注意并不一定是以 root
身份跑程序, 而是可以用任何其他身份. 这做好事不留名干坏事不怕差评利器真是太方便了. 比如, 偷偷输出某个用户的 SSH RSA 私钥之类的. 在桌面机上很少有人会建多个用户, 那么现在创建一个 (建议接下来的试验都新建用户进行, 避免遗留安全隐患; 另外, 当前用户必须已经被添加到 sudo
白名单中)$ sudo useradd -m furude
$ sudo passwd furude # 这一步最好设置一个与当前用户不同的口令
$ su - furude
furude $
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/furude/.ssh/id_rsa): Created directory '/home/furude/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/furude/.ssh/id_rsa.
Your public key has been saved in /home/furude/.ssh/id_rsa.pub.
The key fingerprint is:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
The keys randomart image is:
+--[ RSA 2048]----+
| ............... |
+-----------------+
$ ls .ssh
id_rsa id_rsa.pub
$ ls /home/furude/.ssh
下面就轮到
sudo
登场了. 还是当前用户身份登入, 执行$ sudo ls /home/furude/.ssh
id_rsa id_rsa.pub
$ sudo -u furude ls /home/furude/.ssh
id_rsa id_rsa.pub
$ sudo -u `whoami` ls /home/furude/.ssh
ls: cannot open directory /home/furude/.ssh/: Permission denied
-u furude
参数则是指定以 furude 这个用户身份执行, 自己当然可以看自己的东西了; 最后一个则仍然是以当前用户身份执行, 所以被驳回了.在上面试验中, 即使以 furude 的身份使用
sudo
, 要求输入的口令仍然是当前用户的口令而不是 furude 用户的 (最好新开一个终端试试, 连续使用 sudo
时口令会被缓存下来). 那么, 开头的问题应该是这样的- 为何用
sudo
临时以另一用户身份执行程序时, 要求输入的是当前用户的口令, 而不是被指定的那个用户?
sudo
的源代码中, 而在于文件系统对文件权限设置的一个不常见设置. 一般在谈到文件权限设置时, 都会说到如 751 或者 644 这样的选项, 对应的权限分别是 rwxr-x--x
与 rw-r--r--
, 详细的含义和构成这里就不讲了, 很多地方都有参考. 下面看看 sudo
$ ls -l `which sudo`
-rwsr-xr-x 2 root root /usr/bin/sudo*
x
如果被标记为 s
(含义是 "用户设置"), 则这个程序在启动时, 无论由谁启动, 将该进程对应的用户设置为该可执行文件的所有者.比如, 下面再来做个试验, 创建下面的 C 源代码文件 print_private_key.c
/* print_private_key.c */
#include <stdio.h>
int main(void)
{
FILE* f = fopen("/home/furude/.ssh/id_rsa", "r");
if (NULL == f) {
fprintf(stderr, "Unable to open the file\n");
return 1;
}
char buffer[81];
while(fgets(buffer, 80, f) != NULL) {
printf("%s", buffer);
}
return 0;
}
$ gcc print_private_key.c -o p.out
以 furude 的身份的话, 当然运行这个程序是没问题的. 但是, 如果以一般其它用户运行, 在打开文件那一步就会出错, 输出 "Unable to open the file" 然后灰溜溜地退出. 这一点当然毫不令人惊讶. 下面在编译生成的可执行程序上施加一点魔法 (以文件所有者 furude 的身份)
$ chmod 4751 p.out
-rwsr-x--x
. 这时再随便找个用户运行 p.out (不会提示输入 furude 的口令) 都能看到 furude 用户的密钥.因此这是一件非常非常危险的事情!
那么之前那个问题一般到此解答了, 为什么运行
sudo
不用输入假身份的口令, 但还没解决的是为何要输入真身的口令.实际上, 任何普通用户在都能执行
sudo
, 启动 sudo
进程后, 其身份已然是 root 用户, root 想看谁想删谁想引爆电脑都可以. 只是在这之前, 要核实一下当前用户是否在白名单里, 并且要求用户输入一次口令. 这个检查的操作要借助一个系统调用 getuid
来完成; 而说到这个 API 又不得不说另一个与之类似的 geteuid
(这俩好基友在 manpage 里面都是占一个坑的). 保存下面的源代码#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
int main(void)
{
uid_t uid = geteuid();
struct passwd* pw = getpwuid(uid);
printf("Efficient user: %s\n", pw->pw_name);
uid = getuid();
pw = getpwuid(uid);
printf("Real user: %s\n", pw->pw_name);
return 0;
}