/* priv.c - 提权: 经 sudo 执行单条命令 */ #include "priv.h" #include "util.h" #include #include #include #include #include #include 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 : "提权命令执行失败"); }