如何以编程方式获得根权限? 我写了一些软件(C++,Linux/Mac OSX),它运行为非特权用户,但在某个时候需要root权限(创建一个新的虚拟设备)。

如何以编程方式获得根权限? 我写了一些软件(C++,Linux/Mac OSX),它运行为非特权用户,但在某个时候需要root权限(创建一个新的虚拟设备)。,c++,root,elevated-privileges,C++,Root,Elevated Privileges,以root用户身份运行这个程序不是一个选项(主要是为了安全问题),我需要知道“真正”用户的身份(uid) 有没有办法模仿“sudo”命令行为(请求用户密码)来临时获得root权限并执行特定任务?如果是,我会使用哪些函数 非常感谢你的帮助 您可以尝试通过后台shell启动命令来创建虚拟设备(包括sudo)。在您自己的对话框中请求用户密码,并在sudo请求时将其导入shell。还有其他解决方案,比如使用gksu,但这些并不能保证在每台机器上都可用 您不以root用户身份运行整个程序,而是只运行需要r

以root用户身份运行这个程序不是一个选项(主要是为了安全问题),我需要知道“真正”用户的身份(uid)

有没有办法模仿“sudo”命令行为(请求用户密码)来临时获得root权限并执行特定任务?如果是,我会使用哪些函数


非常感谢你的帮助

您可以尝试通过后台shell启动命令来创建虚拟设备(包括sudo)。在您自己的对话框中请求用户密码,并在sudo请求时将其导入shell。还有其他解决方案,比如使用gksu,但这些并不能保证在每台机器上都可用


您不以root用户身份运行整个程序,而是只运行需要root用户的一小部分程序。您应该为此生成一个单独的进程,sudo可能会对您有所帮助。

如果您每次都需要root权限,最好是以root身份启动您的程序,并使用和删除它们(在子进程中)。当apache需要绑定到受限端口80时,它就是这样做的

如果获得根权限是例外而不是规则,并且程序以交互方式运行,那么另一种方法是编写一个程序add_接口并执行

sudo add_interface args
让sudo为您处理身份验证。代替sudo,您可能需要使用图形前端,如gksu、gksudo、kdesu或kdesudo。我不会自己尝试实现安全的密码输入;这可能是一个棘手的问题,您可能会留下巨大的安全漏洞和功能问题(您支持指纹阅读器吗?)


另一种选择是,以前称为PolicyKit。

原始答案

您可以考虑可执行文件本身上的StuuID开关。Wikipedia上有一个例子,它甚至可以非常有效地告诉你

geteuid()
getuid()
之间的区别,前者是为了找出你在“模仿”谁,后者是为了找出你“是谁”。例如,sudo进程geteuid应该返回0(root)和用户id的getuid,但是,它的子进程确实以root身份运行(您可以使用
sudo id-u-r
验证这一点)

我不认为有一种方法可以通过编程轻松地获得根访问权——毕竟,应用最小特权原则,为什么需要这样做?通常的做法是仅以提升的权限运行代码的有限部分。许多守护进程等都是在现代系统下设置的,它们以自己的用户身份运行,拥有所需的大部分权限。只有非常特定的操作(装载等)才真正需要根权限

2013年更新

我原来的答案是(虽然我的2013个自我可能比我的2010个更好),但是如果你正在设计一个需要root访问的应用程序,你可能需要考虑到底需要什么样的root访问,并考虑使用它。这些与L4等中实现的不同。POSIX功能允许您的应用程序被授予root权限的子集。例如,

CAP\u SYS\u MODULE
将允许您插入内核模块,但不提供其他根权限。这在发行版中使用,例如不分青红皂白的根访问


这很重要,因为作为程序员,您的代码显然是完美的!但是,您所依赖的库(唉,如果您编写它们就好了!)中可能存在漏洞。使用这些功能,您可以限制此漏洞的使用,并使您自己和您的公司免于安全相关的审查。这让每个人都更快乐。

您无法获得root权限,您必须从它们开始,并根据需要减少您的权限。通常的方法是安装设置了“setuid”位的程序:它使用文件所有者的有效用户ID运行程序。如果在
sudo
上运行
ls-l
,您将看到它是这样安装的:

-rwsr-xr-x 2 root root 123504 2010-02-25 18:22 /usr/bin/sudo
当您的程序以root权限运行时,您可以调用
setuid(2)
系统调用将您的有效userid更改为某个非特权用户。我相信(但还没有尝试过)您可以在setuid位打开的情况下以root用户身份安装程序,立即减少特权,然后根据需要恢复特权(不过,有可能一旦降低特权,就无法恢复特权)


一个更好的解决方案是分离出需要以root身份运行的程序部分,并在setuid位打开的情况下安装它。当然,您需要采取合理的预防措施,使其不能在主程序之外调用。

您可能需要了解以下API:

setuid, seteuid, setgid, setegid, ...
在Linux系统中,它们是在头文件
中定义的(不太了解MAC,但您也应该在那里有一个类似的头文件)

我看到的一个问题是进程必须有足够的权限来更改其用户/组ID。否则,调用上述函数将导致将
errorno
设置为
EPERM
时出错


我建议您以
root
用户的身份运行程序,从一开始就将有效用户ID(使用
seteuid
)更改为弱势用户。然后,每当需要提升权限时,提示输入密码,然后再次使用
seteuid
还原到
root
用户。

通常这是通过将二进制suid设置为root来完成的

管理这一点的一种方法是尽量减少以root身份运行的代码,从而避免对程序的攻击:

int privileged_server(int argc, char **argv);
int unprivileged_client(int argc, char **argv, int comlink);


int main(int argc, char **argv) {
    int sockets[2];
    pid_t child;
    socketpair(AF_INET, SOCK_STREAM, 0);  /* or is it AF_UNIX? */

    child = fork();
    if (child < 0) {
        perror("fork");
        exit(3);
    } elseif (child == 0) {
        close(sockets[0]);
        dup2(sockets[1], 0);
        close(sockets[1]);
        dup2(0, 1);
        dup2(0, 2); /* or not */
        _exit(privileged_server(argc, argv));
    } else {
        close(sockets[1]);
        int rtn;
        setuid(getuid());
        rtn = unprivileged_client(argc, argv, sockets[0]);
        wait(child);
        return rtn;
    }
}
int-privileged_服务器(int-argc,char**argv);
int非特权客户端(int-argc、char**argv、int-comlink);
int main(int argc,字符**argv){
int插座[2];
pid_t儿童;
static bool execute(const std::string &program, const std::vector<std::string> &arguments)
{
    AuthorizationRef ref;
    if (AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &ref) != errAuthorizationSuccess) {
        return false;
    }

    AuthorizationItem item = {
        kAuthorizationRightExecute, 0, 0, 0
    };
    AuthorizationRights rights = { 1, &item };
    const AuthorizationFlags flags = kAuthorizationFlagDefaults
                                   | kAuthorizationFlagInteractionAllowed
                                   | kAuthorizationFlagPreAuthorize
                                   | kAuthorizationFlagExtendRights;

    if (AuthorizationCopyRights(ref, &rights, kAuthorizationEmptyEnvironment, flags, 0) != errAuthorizationSuccess) {
        AuthorizationFree(ref, kAuthorizationFlagDestroyRights);
        return false;
    }

    std::vector<char*> args;
    for (std::vector<std::string>::const_iterator it = arguments.begin(); it != arguments.end(); ++it) {
        args.push_back(it->c_str());
    }
    args.push_back(0);

    OSStatus status = AuthorizationExecuteWithPrivileges(ref, program.c_str(), kAuthorizationFlagDefaults, &args[0], 0);

    AuthorizationFree(ref, kAuthorizationFlagDestroyRights);
    return status == errAuthorizationSuccess;
}