c - C 使用 system() 与使用 execl() 启动 X11 会话
问题描述
我创建了一个类似守护进程的程序,该程序将在特定用户在其自己的环境下对其进行身份验证后启动 X11 会话。
第一种方法是使用 using 命令system()
,我将在其中模拟用户并启动 x11 会话,如下所示:
std::string cmd = "echo daemonuserpwd | sudo -S su " + unixUser + " -c 'xinit -- :4' &";
system(cmd.c_str());
这完美无缺,并调用.xinitrc
位于用户主目录中的文件,这是一个必要的步骤,因为我使用它来启动所需的程序,我需要这些程序来实现我正在工作的应用程序。
但是,我阅读了有关 的问题system()
,因此我尝试更进一步并使用 fork 创建用户环境,并使用 启动会话execl()
,如下所示:
int child = fork();
if(child == 0)
{
struct passwd * userInfo = getpwnam(unixUser.c_str());
setgid(userInfo->pw_gid);
setuid(userInfo->pw_uid);
system("whoami");
execl("/usr/bin/xinit", "xinit", "--", ":4", (char*)0);
//system("xinit -- :4");
}
这也有效,调试命令system("whoami");
说我是正确的用户。X11 会话已启动,但是.xinitrc
从 fork 进程启动会话时不会调用该文件。在设置用户环境后,我还尝试使用系统执行命令,结果相同(两个选项都xinitrc
在/etc/X11/xinit/xinitrc
.
在使用该方法时,我是否遗漏了一些东西以便.xinitrc
调用文件fork()
?
免责声明:使用 libpam 执行用户身份验证,并正确清理用户输入以防止注入。
编辑:使用execle
@LieRyan 建议的最终解决方法:
struct passwd * userInfo = getpwnam(unixUser.c_str());
char buf[0xff];
sprintf(buf, "HOME=%s", userInfo->pw_dir);
char *env[] = {buf, NULL};
execle("/usr/bin/sudo", "sudo", "-u", unixUser.c_str(), "xinit", "--", ":4", (char*)0, env);
解决方案
调用setuid
会更改进程所属的对象,但不会更改如果该用户已登录将设置的环境变量,因此$HOME
不会指向正确的位置来获取“.xinitrc”文件。
以下代码行应该为您解决这个问题。
setenv("HOME",userInfo->pw_dir,1);
推荐阅读
- sqlite - UWP sqlite-net 异步数据库访问
- spring-boot - 在 Spring Cloud AWS 中使用 Java 配置配置邮件发件人
- android - 无法从 google play 更新
- c# - 如何使用 C# 中的 NetworkComms.Net 库通过 Internet 建立 UDP 连接
- java - Java:我的文本解密系统不起作用
- vba - 从 .To 中选择电子邮件地址
- c# - 在 xamarin 中设置 iOS 光标
- regex - matlab开关+正则表达式
- haskell - 这些例子是正确的还是教程有错误?
- c# - 通过 C# 代码从 DocuSign 文档中检索名字、姓氏等字段