如何以编程方式获得根权限? 我写了一些软件(C++,Linux/Mac OSX),它运行为非特权用户,但在某个时候需要root权限(创建一个新的虚拟设备)。
以root用户身份运行这个程序不是一个选项(主要是为了安全问题),我需要知道“真正”用户的身份(uid) 有没有办法模仿“sudo”命令行为(请求用户密码)来临时获得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
非常感谢你的帮助 您可以尝试通过后台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;
}