如何用root的身份以普通用户权限运行程序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何用root的身份以普通用户权限运行程序相关的知识,希望对你有一定的参考价值。

ubuntu的话安装完后没有root密码,要用你安装时设的用户去给root设一个密码.
sudopasswdroot回车
(输入密码,但不会在屏幕显示出*)
(再输入一次密码)
成功
参考技术A 问题在于有许多程序是不应该用root身份运行的。如果你用自己的身份(非root身份)启动
文件管理器
,然后删除/home,你会丢失自己的所有文件,然后一边寻找
备份文件
一边不停地抱怨自己。万幸的是所有其他用户的文件都还安然无恙。但是,如果你用ro...

如何以编程方式获得 root 权限?

【中文标题】如何以编程方式获得 root 权限?【英文标题】:How to programmatically gain root privileges? 【发布时间】:2011-01-29 20:05:58 【问题描述】:

我正在编写一些软件(在 C++ 中,用于 Linux/Mac OSX),它以非特权用户身份运行,但在某些时候需要 root 特权(以创建新的虚拟设备)。

以 root 身份运行此程序不是一个选项(主要是出于安全问题),我需要知道“真实”用户的身份 (uid)。

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

非常感谢您的帮助!

【问题讨论】:

【参考方案1】:

在 OS X 上,您可以使用 AuthorizationExecuteWithPrivileges 函数。 Authorization Services Tasks 上的页面对此(及相关)功能进行了详细讨论。

下面是一段 C++ 代码,用于以管理员权限执行程序:

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;

【讨论】:

我们在哪里调用这个函数?什么是 arguments 参数?我试图在 main 函数的开头调用,但它崩溃了。参数为空。我的问题是在 /var/log 中创建一个文件。但是需要许可。我该如何处理这个问题? 值得一提的是这段代码需要的所有库,不是吗?【参考方案2】:

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

如果获得root权限是例外而不是规则并且程序交互运行,另一种方法是编写程序add_interface并执行

sudo add_interface args

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

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

【讨论】:

【参考方案3】:

原答案

您可能会考虑可执行文件本身的 setuid 开关。***上有一个article,它甚至可以非常有效地向您展示geteuid()getuid() 之间的区别,前者用于找出您“模仿”谁,而后者用于找出您“是谁”。 sudo 进程,例如,geteuid 应该返回 0(root)并 getuid 您的用户 id,但是,它的子进程确实以 root 身份运行(您可以使用sudo id -u -r 验证这一点)。

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

2013 年更新

我最初的答案是正确的(尽管我 2013 年的自己可能比 2010 年的自己做得更好),但是如果您正在设计一个需要 root 访问权限的应用程序,您可能需要考虑到底需要哪种 root 访问权限并考虑使用POSIX Capabilities(man page)。这些与在 L4 等人中实现的 capability-based security 不同。 POSIX 功能允许您的应用程序被授予 root 权限的子集。例如CAP_SYS_MODULE 将允许您插入内核模块,但不授予您其他根权限。这在发行版中使用,例如Fedora has a feature to completely remove setuid binaries 具有不分青红皂白的 root 访问权限。

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

【讨论】:

执行此操作时,您必须非常注意安全性,因为您的应用现在是特权升级漏洞的目标 当你这样做的时候,尽快做那些需要root权限的事情,然后马上下拉给真正的用户。 Under sudo, for example, geteuid should return 0 (root) and getuid your user's id. 这是错误的。请参阅我关于这个问题的问题:***.com/questions/10272784/… @chacham15 啊,是的。 Sudo 本身应该能够看到这些东西,但继承的进程不会。他们只继承有效的用户 ID 作为他们的真实用户 ID。我会编辑这个,因为它不清楚。 当我在 Mac OS X (Mountain Lion) 下执行此操作时,我得到“带有捆绑 ID (null) 的应用程序正在运行 setugid(),这是不允许的。”当我尝试启动程序时。我能做什么?【参考方案4】:

通常这是通过制作二进制 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;
    

现在非特权代码通过 fd comlink(这是一个连接的套接字)与特权代码对话。相应的特权代码使用 stdin/stdout 作为其 comlink 的结尾。

特权代码需要验证它需要执行的每个操作的安全性,但由于与非特权代码相比,此代码很小,这应该相当容易。

【讨论】:

你的第二个区块我想你的意思是child &gt; 0 其实我认为应该是else if (child == 0) -- else block wait 对于child,所以child需要是中间的else if block。 如果你想通过套接字传递文件描述符,你可能需要AF_UNIX 我故意设计成不传递文件描述符。【参考方案5】:

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

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

【讨论】:

感谢您的回答。不幸的是,该程序并不总是需要 root 权限。有时您可能只是想以某种方式使用它,因此它不需要执行该特定任务。在这种情况下,不需要询问密码。我找到了谈论 setuid() 的线程。我将对此进行调查。 sudo 是否保证在每台机器上都可用?我见过没有它的安装。 不,fedora 上默认没有配置它。我还亲自阻止不属于 wheel 组的用户使用 sudo 或 su 作为传统 unix 行为的扩展。 您当然只需要通过 sudo 运行需要 root 权限的代码部分。当您不需要 root 权限时,不要询问密码。通过 sudo 运行整个程序不是我的答案,“命令”仅指需要 root 权限的命令,而不是整个应用程序。 运行过程中Ubuntu软件中心不是交互获取root权限的吗?显然是通过 polkit。【参考方案6】:

您可能想看看这些 API:

setuid, seteuid, setgid, setegid, ...

它们在 Linux 系统的标头 &lt;unistd.h&gt; 中定义(对 MAC 了解不多,但您应该也有类似的标头)。

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

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

【讨论】:

【参考方案7】:

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

-rwsr-xr-x 2 root root 123504 2010-02-25 18:22 /usr/bin/sudo

当您的程序以 root 权限运行时,您可以调用 setuid(2) 系统调用将您的有效用户 ID 更改为某个非特权用户。我相信(但尚未尝试过)您可以在 setuid 位打开的情况下以 root 身份安装您的程序,立即降低权限,然后根据需要恢复权限(但是,一旦您降低权限,您可能不会可以恢复)。

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

【讨论】:

以上是关于如何用root的身份以普通用户权限运行程序的主要内容,如果未能解决你的问题,请参考以下文章

Linux系统如何用root身份登陆?

我以普通用户的身份安装了Android Studio软件包。那么如何以root身份打开它呢?

sudo 限制普通用户权限

账户和权限管理

用户和组管理及权限

安卓shell root啥意思