C使用system()与execl()启动X11会话

时间:2018-11-20 09:49:55

标签: c unix fork

我创建了一个类似守护程序的程序,在他对自己进行身份验证之后,它将在其自己的环境下为特定用户启动X11会话。

第一种方法是使用使用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文件。设置用户环境后,我还尝试使用系统执行命令,结果相同(两个选项都在xinitrc中调用默认的/etc/X11/xinit/xinitrc

使用.xinitrc方法时,我是否也缺少一些东西来使fork()文件也被调用?

免责声明: 使用libpam执行用户身份验证,并且正确清除了用户输入以防止注入。


编辑:@LieRyan建议使用execle的最终解决方法:

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);

1 个答案:

答案 0 :(得分:1)

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

下面的代码行应为您解决此问题。

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