我已经创建了一个类似守护进程的程序,它将在特定用户进行身份验证后在其自己的环境下启动 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/