我创建了一个类似守护程序的程序,在他对自己进行身份验证之后,它将在其自己的环境下为特定用户启动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);
答案 0 :(得分:1)
调用setuid
会更改进程所属的人,但不会更改该用户登录后将设置的环境变量,因此$HOME
不会指向正确的位置来拾取“ .xinitrc”文件。
下面的代码行应为您解决此问题。
setenv("HOME",userInfo->pw_dir,1);