58 lines
2.1 KiB
C
58 lines
2.1 KiB
C
/* priv.c - 提权: 经 sudo 执行单条命令 */
|
|
#include "priv.h"
|
|
#include "util.h"
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
int priv_have_tty(void) {
|
|
int fd = open("/dev/tty", O_RDWR);
|
|
if (fd < 0)
|
|
return 0;
|
|
close(fd);
|
|
return 1;
|
|
}
|
|
|
|
char **priv_sudo_argv(const char *user, char *const argv[]) {
|
|
size_t n = 0;
|
|
while (argv[n])
|
|
n++;
|
|
const char *u = (user && *user) ? user : "root";
|
|
|
|
/* 刻意不带 -n: 需要密码时就让 sudo 自己问.
|
|
* 也不带 -S: 那要求把密码从 stdin 喂进去, 等于让 ligent 经手密码. */
|
|
/* execvp 的签名要 char *const[], 但这里放进去的都是字面量和调用方的
|
|
* 指针, **没有任何人会去改写它们** (execvp 本身也不会). 所以这里显式
|
|
* 转换, 而不是把整条链路都改成非 const —— 那会把 const 正确性一路丢掉. */
|
|
char **w = xcalloc(n + 5, sizeof *w);
|
|
w[0] = (char *)"sudo";
|
|
w[1] = (char *)"-u";
|
|
w[2] = (char *)u;
|
|
w[3] = (char *)"--";
|
|
for (size_t i = 0; i < n; i++)
|
|
w[4 + i] = argv[i];
|
|
return w;
|
|
}
|
|
|
|
void priv_explain(int rc, const char *out, char *err, size_t errlen) {
|
|
if (!err || !errlen)
|
|
return;
|
|
const char *o = out ? out : "";
|
|
|
|
if (rc == 127 && strstr(o, "无法执行"))
|
|
snprintf(err, errlen, "这台机器上没有 sudo, 无法提权");
|
|
else if (strstr(o, "no tty present") || strstr(o, "a terminal is required"))
|
|
snprintf(err, errlen, "提权需要终端来输入密码, 当前没有可用的控制终端");
|
|
else if (strstr(o, "incorrect password") || strstr(o, "Sorry, try again") ||
|
|
strstr(o, "认证失败") || strstr(o, "密码不正确"))
|
|
snprintf(err, errlen, "sudo 认证没有通过 (密码不对, 或者你取消了)");
|
|
else if (strstr(o, "not in the sudoers") || strstr(o, "不在 sudoers"))
|
|
snprintf(err, errlen, "当前用户没有 sudo 权限");
|
|
else
|
|
snprintf(err, errlen, "%s", *o ? o : "提权命令执行失败");
|
|
}
|