C 使用 system() 与使用 execl() 启动 X11 session

标签 c unix fork

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

第一种方法是使用 system() 命令,我将在其中模拟用户并启动 x11 session ,如下所示:

std::string cmd = "echo daemonuserpwd | sudo -S su " + unixUser + " -c 'xinit -- :4' &";
system(cmd.c_str());

这工作完美无缺,并调用位于用户主目录中的 .xinitrc 文件,这是必要的步骤,因为我用它来启动应用程序所需的所需程序我在工作。

但是,我了解到 system() 的问题,所以我尝试更进一步,使用 fork 创建用户环境,并使用 execl()< 启动 session ,如下:

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 session 已启动,但是,当从 fork 进程启动 session 时,不会调用 .xinitrc 文件。我还尝试在设置用户环境后使用系统执行命令,结果相同(两个选项都调用 /etc/X11/xinit/xinitrc 中的默认 xinitrc .

在使用 fork() 方法时,我是否遗漏了一些东西来调用 .xinitrc 文件?

免责声明: 使用 libpam 执行用户身份验证,并正确清理用户输入以防止注入(inject)。


编辑:按照@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);

最佳答案

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

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

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

关于C 使用 system() 与使用 execl() 启动 X11 session ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53390266/

相关文章:

objective-c - 对 c/objective-c 中的 float 进行舍入。最后一位数字为 5 时出错

mysql - 使用 JOOQ 查询 Unix 时间戳

c++ - 使用 `fork()` 反转字符串

c - 在 Linux 上跨进程共享数据

c - 如何在 os x 上用 clang 编译共享库

c - C中双斜杠后的分号

CUDA并发执行

c - 用于数据数组的 mmap 函数

linux - 有没有办法在 unix 或 linux 中列出文件并由创建者删除

c - setpgrp/setpgid 失败(?),适用于 Mac OSX,不适用于 Linux