c - 通过C输入sudo密码

标签 c linux sudo

我之前问过这个问题,但是没有人给出一个直接的答案。我想知道如何通过C代码输入sudo密码。我正在尝试编写一个脚本来执行sudo bash并输入所需的密码。我也知道对密码进行硬编码的风险,但是我不介意这种情况。

最佳答案

否。这样做是antipattern

根据情况,有几种选择:


gksudo(如果设置了DISPLAY环境变量)用于图形提示。
安装要在/usr/share/yourapp/scripts//usr/lib/yourapp/scripts/中执行的脚本以及正确的sudo配置,该配置允许使用sudo运行它们而无需在/etc/sudoers.d/yourapp中提供密码(或在没有/etc/sudoers的系统中使用/etc/sudoers.d/
在程序开始时,检查是否为geteuid() == 0。如果不是,请使用gksudo / sudo重新执行self,以获得root特权。

对于正常操作,您的程序应仅使用执行程序的真实用户的特权。为了能够在以后提高特权,“特权”被保存。因此,最初,您的程序将使用例如

    uid_t  uid = getuid();
    gid_t  gid = getgid();
    if (setresgid(gid, gid, 0) == -1 ||
        setresuid(uid, uid, 0) == -1) {
        /* Failed: no root privileges! */
    }


要重新提升特权,请使用

    if (setresgid(gid, 0, 0) == -1 ||
        setresuid(uid, 0, 0) == -1) {
        /* Failed: no root privileges! */ 
    }


仅将有效身份更改为root(就像setuid二进制文件一样),或者

    if (setresgid(0, 0, 0) == -1 ||
        setresuid(0, 0, 0) == -1) {
        /* Failed: no root privileges! */ 
    }


从而改变了真实身份和有效身份的根源。

通常,特权仅针对派生有特权的子从属而提高,之后,主程序使用以下命令完全放弃特权:

    if (setresgid(gid, gid, gid) == -1 ||
        setresuid(uid, uid, uid) == -1) {
        /* Failed. */
    }


在父母与孩子之间仅保持一对插座或管道;然后孩子可以分叉并执行新的流程。 (如果使用Unix域套接字,则父级甚至可以通过辅助消息发送新的描述符,以用于新进程的标准流。)
使用文件系统功能为您的程序提供所需的功能,而无需提升其所有特权。

例如,sudo setcap CAP_NET_BIND_SERVICE=pe /usr/bin/yourapp使/usr/bin/yourapp具有CAP_NET_BIND_SERVICE功能(允许且有效;未继承),该功能使您的程序可以绑定到任何未使用的TCP / IP和UDP / IP端口,包括1-1024。有关功能的详细说明,请参见man 7 capabilities
使用受信任的帮助程序二进制文件(程序)为您充当sudo。如果您将其安装在/usr/lib/yourapp/execute,您可以添加必要的sudo配置,以允许执行该配置而无需提供密码。或者,您可以将其设置为setuid root,或通过文件系统功能为其提供必要的功能。

为避免其他程序利用此帮助程序,必须确保它仅由您的程序执行。一种确保程序创建Unix域套接字对的方法是,在程序中留出一端,而在另一端留给助手。描述符3.在执行任何操作之前,辅助程序会检查尚无任何内容(以避免“管道填充”攻击),并将单个字节写入父级。父级以单个字节进行响应,但其凭据在ancillary message中。凭据包含父级的进程ID。 (不要简单地使用getppid(),因为它允许某些攻击;这种套接字方法会在我们执行检查时验证父代是否还活着。)最后,使用readlink()读取/proc/PID/exe伪符号链接,其中PID为凭证辅助消息中的父进程ID。此时,帮助程序应该发送一个字节,并再次接收带有凭据的字节作为辅助消息,以确保父进程仍然相同。

验证过程很复杂,但有必要,以避免通过滥用辅助程序而使利用根特权变得容易。要实现此目的的另一种方法,请查看Apache suEXEC,Apache使用该帮助程序以特定的用户特权执行CGI程序。




假设您对以明智的方式进行操作完全不感兴趣,并坚持使用密码。精细;我要问的是您不要发布这样的代码,或者至少警告您的用户它是完全不安全的。

这不仅是一个粗略的骇客:它是一种自杀式行为,类似于在您的电子邮件签名中放置密码到您的网站,因为您只发送给应该首先对您的网站具有管理员访问权限的朋友。因此,脚枪带有发夹,没有安全性,并用河豚毒素包被的弹药武装。带有一个漂亮的标签,上面有孩子们可读的大字母,上面写着“请和我一起玩!我很安全!”,该标签存储在儿童房中。

最简单的方法是使用sudo标志执行-S,这将导致它从标准输入中读取密码。例如example.c:

#define  _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
    FILE  *cmd;
    int    status;

    cmd = popen("/usr/bin/sudo -S id -un 2>/dev/null", "w");
    if (!cmd) {
        fprintf(stderr, "Cannot run sudo: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

    fprintf(cmd, "Password\n");
    fflush(cmd);

    status = pclose(cmd);
    if (WIFEXITED(status)) {
        if (WEXITSTATUS(status) == EXIT_SUCCESS)
            fprintf(stderr, "No errors.\n");
        else
            fprintf(stderr, "Command failed with exit status %d.\n", WEXITSTATUS(status));
    } else
    if (WIFSIGNALED(status))
        fprintf(stderr, "Command killed by signal %d.\n", WTERMSIG(status));
    else
        fprintf(stderr, "Command failed.\n");

    return EXIT_SUCCESS;
}


在写模式下打开命令管道,以便我们可以向其中写入密码。 2>/dev/null重定向隐藏密码提示。

如果密码正确,则上面的命令将以root用户身份运行时将id -un输出的内容输出到标准输出,将root输出为标准错误。

如果密码不正确,sudo将重试几次(因此几秒钟内不会发生任何事情),然后程序将向No errors.报告标准错误,因为当密码不正确时,Command failed with exit status 1.会执行此操作。

关于c - 通过C输入sudo密码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52133408/

相关文章:

linux - 从 Linux 图形工具制作图像幻灯片

linux - 将 SAN 存储共享路径附加到两台 linux 机器

python - 使用 setuptools 安装的提升权限运行 python 脚本

java - 在不使用任何外部函数的情况下生成随机数

c - 我如何定期从 c 中允许值的位掩码中选择值?

c - 创建代码打印 3 个数字之间的最大值时出现问题

未找到 JAVA_HOME 作为 Sudo

c - 更新 c 中的局部 vector 条目

linux - 使用 grep 查找/剪切功能而不是源代码在 bash 中加载配置文件

linux - 在 visudo 中的 root 行之后添加行