43 lines
2.3 KiB
C
43 lines
2.3 KiB
C
/* priv.h - 提权:经 sudo 执行单条命令
|
||
*
|
||
* 先说清楚这个模块**不做**什么,以及为什么:
|
||
*
|
||
* PAM 认证不等于获得权限。su 之所以能变 root,是因为 /usr/bin/su 这个文件
|
||
* 本身是 setuid root —— 内核先把 root 给它,它再验密码、验不过就降权。普通
|
||
* 进程调 pam_authenticate() 只能得到"密码对不对",uid 一位都不变。要让 ligent
|
||
* 内部认证后真的变 root,唯一的路是把它编译成 setuid root;而它的功能是
|
||
* "让模型执行任意命令",setuid root 的它等于把 root 远程执行做成一等功能。
|
||
* 所以不走那条路。
|
||
*
|
||
* 也不做"授权提示"。**密码本身就是授权**:模型敲不出来,你也不可能手滑敲出来。
|
||
* 再加一道 y/N 只会是多余的摩擦,还会给出一个虚假的安全模型 —— 好像把关的是
|
||
* ligent 的提示,其实真正把关的是 sudo。所以这里只做两件事:
|
||
*
|
||
* 1. 把命令包成 `sudo -u <用户> -- <argv>` 交出去(**不经 shell**,
|
||
* 所以路径/命令里的引号、换行、`;` 注入不进 root 那条命令里);
|
||
* 2. 需要密码时,**让终端留在 sudo 手上**,由它自己问、自己存 —— ligent
|
||
* 不读、不存、不转发密码。
|
||
*
|
||
* 唯一由 ligent 把守的是"别卡死":没有控制终端就**根本不去试**,直接说清楚。
|
||
* 否则就会起一个在后台等一个没人能看见的密码提示的进程。
|
||
*/
|
||
#ifndef LIGENT_PRIV_H
|
||
#define LIGENT_PRIV_H
|
||
|
||
#include <stddef.h>
|
||
|
||
/* 有可用的控制终端吗?判据是能不能打开 /dev/tty,**不是** isatty(0):
|
||
* `echo x | ligent ...` 时 stdin 是管道,但终端还在,sudo 照样问得出来。 */
|
||
int priv_have_tty(void);
|
||
|
||
/* 把 argv 包成 `sudo -u <user> -- <原 argv>`(user 为空则 "root")。
|
||
* 故意**不带 -n**:需要密码时就让 sudo 自己去问。
|
||
* 返回 malloc 的数组,元素是借用的指针 —— 调用方 free 数组本身即可。 */
|
||
char **priv_sudo_argv(const char *user, char *const argv[]);
|
||
|
||
/* sudo 失败时把它的原话换成一句能照做的中文(写进 err)。
|
||
* 认不出来就原样透传 —— 宁可给原文,也不要编一句可能不对的解释。 */
|
||
void priv_explain(int rc, const char *out, char *err, size_t errlen);
|
||
|
||
#endif /* LIGENT_PRIV_H */
|