首页 > 解决方案 > 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);

标签: cunixfork

解决方案


调用setuid会更改进程所属的对象,但不会更改如果该用户已登录将设置的环境变量,因此$HOME不会指向正确的位置来获取“.xinitrc”文件。

以下代码行应该为您解决这个问题。

setenv("HOME",userInfo->pw_dir,1);

推荐阅读