C starting a X11 session using system() vs using execl()












1














I have created a daemon-like program that will start a X11 session for a specific user under its own enviroment, after he authenticates himself.



The first approach was to use a command using system(), where I would impersonate the user and start the x11 session as follows:



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


This works flawless, and calls the .xinitrc file located in the user's home directory, which is a necessary step as I use it to start up the required programs which I need for the purpose the application Im working in.



However, I read about the problems with system(), so I tried to go bit further and use fork to create the user enviroment, and start the session using execl(), as follows:



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


This also works, the debugging command system("whoami"); says im the right user. The X11 session is started, however, the .xinitrc file is not called when the session is started from the fork process. I also tried to execute the command with system, after setting up the user enviroment, with same result (Both options call the default xinitrc in /etc/X11/xinit/xinitrc.



Am I missing something in order the .xinitrc file to be called as well when using the fork() approach?



Disclaimer:
User authentication is performed with libpam, and the user input is sanitetized properly to prevent injections.





EDIT: The final workaround using execle as suggested by @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);









share|improve this question




















  • 1




    Another thing you may want to consider, to use setuid/setgid, your program had to run as root. Consider, if this is an unnecessary risk. You may want to consider running execl("/usr/bin/sudo", "-u", unixUser, "xinit", "--", ":4", (char*)0) and have your daemon user be whitelisted in /etc/sudoers to NOPASSWD when running xinit.
    – Lie Ryan
    Nov 20 at 11:00










  • @LieRyan Thank you very much! I followed both of your advices (and also found a workaround to use pam_authenticate() without root privileges), and Im able to run the daemon without root privs.
    – Nadir
    Nov 20 at 15:18
















1














I have created a daemon-like program that will start a X11 session for a specific user under its own enviroment, after he authenticates himself.



The first approach was to use a command using system(), where I would impersonate the user and start the x11 session as follows:



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


This works flawless, and calls the .xinitrc file located in the user's home directory, which is a necessary step as I use it to start up the required programs which I need for the purpose the application Im working in.



However, I read about the problems with system(), so I tried to go bit further and use fork to create the user enviroment, and start the session using execl(), as follows:



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


This also works, the debugging command system("whoami"); says im the right user. The X11 session is started, however, the .xinitrc file is not called when the session is started from the fork process. I also tried to execute the command with system, after setting up the user enviroment, with same result (Both options call the default xinitrc in /etc/X11/xinit/xinitrc.



Am I missing something in order the .xinitrc file to be called as well when using the fork() approach?



Disclaimer:
User authentication is performed with libpam, and the user input is sanitetized properly to prevent injections.





EDIT: The final workaround using execle as suggested by @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);









share|improve this question




















  • 1




    Another thing you may want to consider, to use setuid/setgid, your program had to run as root. Consider, if this is an unnecessary risk. You may want to consider running execl("/usr/bin/sudo", "-u", unixUser, "xinit", "--", ":4", (char*)0) and have your daemon user be whitelisted in /etc/sudoers to NOPASSWD when running xinit.
    – Lie Ryan
    Nov 20 at 11:00










  • @LieRyan Thank you very much! I followed both of your advices (and also found a workaround to use pam_authenticate() without root privileges), and Im able to run the daemon without root privs.
    – Nadir
    Nov 20 at 15:18














1












1








1







I have created a daemon-like program that will start a X11 session for a specific user under its own enviroment, after he authenticates himself.



The first approach was to use a command using system(), where I would impersonate the user and start the x11 session as follows:



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


This works flawless, and calls the .xinitrc file located in the user's home directory, which is a necessary step as I use it to start up the required programs which I need for the purpose the application Im working in.



However, I read about the problems with system(), so I tried to go bit further and use fork to create the user enviroment, and start the session using execl(), as follows:



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


This also works, the debugging command system("whoami"); says im the right user. The X11 session is started, however, the .xinitrc file is not called when the session is started from the fork process. I also tried to execute the command with system, after setting up the user enviroment, with same result (Both options call the default xinitrc in /etc/X11/xinit/xinitrc.



Am I missing something in order the .xinitrc file to be called as well when using the fork() approach?



Disclaimer:
User authentication is performed with libpam, and the user input is sanitetized properly to prevent injections.





EDIT: The final workaround using execle as suggested by @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);









share|improve this question















I have created a daemon-like program that will start a X11 session for a specific user under its own enviroment, after he authenticates himself.



The first approach was to use a command using system(), where I would impersonate the user and start the x11 session as follows:



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


This works flawless, and calls the .xinitrc file located in the user's home directory, which is a necessary step as I use it to start up the required programs which I need for the purpose the application Im working in.



However, I read about the problems with system(), so I tried to go bit further and use fork to create the user enviroment, and start the session using execl(), as follows:



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


This also works, the debugging command system("whoami"); says im the right user. The X11 session is started, however, the .xinitrc file is not called when the session is started from the fork process. I also tried to execute the command with system, after setting up the user enviroment, with same result (Both options call the default xinitrc in /etc/X11/xinit/xinitrc.



Am I missing something in order the .xinitrc file to be called as well when using the fork() approach?



Disclaimer:
User authentication is performed with libpam, and the user input is sanitetized properly to prevent injections.





EDIT: The final workaround using execle as suggested by @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);






c unix fork






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 at 15:26

























asked Nov 20 at 9:49









Nadir

1,437717




1,437717








  • 1




    Another thing you may want to consider, to use setuid/setgid, your program had to run as root. Consider, if this is an unnecessary risk. You may want to consider running execl("/usr/bin/sudo", "-u", unixUser, "xinit", "--", ":4", (char*)0) and have your daemon user be whitelisted in /etc/sudoers to NOPASSWD when running xinit.
    – Lie Ryan
    Nov 20 at 11:00










  • @LieRyan Thank you very much! I followed both of your advices (and also found a workaround to use pam_authenticate() without root privileges), and Im able to run the daemon without root privs.
    – Nadir
    Nov 20 at 15:18














  • 1




    Another thing you may want to consider, to use setuid/setgid, your program had to run as root. Consider, if this is an unnecessary risk. You may want to consider running execl("/usr/bin/sudo", "-u", unixUser, "xinit", "--", ":4", (char*)0) and have your daemon user be whitelisted in /etc/sudoers to NOPASSWD when running xinit.
    – Lie Ryan
    Nov 20 at 11:00










  • @LieRyan Thank you very much! I followed both of your advices (and also found a workaround to use pam_authenticate() without root privileges), and Im able to run the daemon without root privs.
    – Nadir
    Nov 20 at 15:18








1




1




Another thing you may want to consider, to use setuid/setgid, your program had to run as root. Consider, if this is an unnecessary risk. You may want to consider running execl("/usr/bin/sudo", "-u", unixUser, "xinit", "--", ":4", (char*)0) and have your daemon user be whitelisted in /etc/sudoers to NOPASSWD when running xinit.
– Lie Ryan
Nov 20 at 11:00




Another thing you may want to consider, to use setuid/setgid, your program had to run as root. Consider, if this is an unnecessary risk. You may want to consider running execl("/usr/bin/sudo", "-u", unixUser, "xinit", "--", ":4", (char*)0) and have your daemon user be whitelisted in /etc/sudoers to NOPASSWD when running xinit.
– Lie Ryan
Nov 20 at 11:00












@LieRyan Thank you very much! I followed both of your advices (and also found a workaround to use pam_authenticate() without root privileges), and Im able to run the daemon without root privs.
– Nadir
Nov 20 at 15:18




@LieRyan Thank you very much! I followed both of your advices (and also found a workaround to use pam_authenticate() without root privileges), and Im able to run the daemon without root privs.
– Nadir
Nov 20 at 15:18












1 Answer
1






active

oldest

votes


















1














Calling setuid changes who the process belongs to, but it doesn't alter the environment variables that would be set if that user had logged in so $HOME won't be pointing at the right place to pick up the ".xinitrc" file.



The following line of code should fix that for you.



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





share|improve this answer





















  • That was it. Thank you very much
    – Nadir
    Nov 20 at 10:44






  • 1




    Note that setenv changes the environment variable of the current process as well, which may have unintended side effects, if this is undesirable, you may want to use execle instead.
    – Lie Ryan
    Nov 20 at 11:06






  • 2




    True, @LieRyan, but not much relevant when you've fork()ed, and / or if you're assuming (unsafely) that execl() will not fail, as the OP appears to do, or if you ensure that the process terminates in the event that execl() does fail.
    – John Bollinger
    Nov 20 at 15:41












  • @JohnBollinger if you are referring to check the returned value by execl(), I left it out for the sake of simplicity.
    – Nadir
    Nov 20 at 15:48











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53390266%2fc-starting-a-x11-session-using-system-vs-using-execl%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














Calling setuid changes who the process belongs to, but it doesn't alter the environment variables that would be set if that user had logged in so $HOME won't be pointing at the right place to pick up the ".xinitrc" file.



The following line of code should fix that for you.



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





share|improve this answer





















  • That was it. Thank you very much
    – Nadir
    Nov 20 at 10:44






  • 1




    Note that setenv changes the environment variable of the current process as well, which may have unintended side effects, if this is undesirable, you may want to use execle instead.
    – Lie Ryan
    Nov 20 at 11:06






  • 2




    True, @LieRyan, but not much relevant when you've fork()ed, and / or if you're assuming (unsafely) that execl() will not fail, as the OP appears to do, or if you ensure that the process terminates in the event that execl() does fail.
    – John Bollinger
    Nov 20 at 15:41












  • @JohnBollinger if you are referring to check the returned value by execl(), I left it out for the sake of simplicity.
    – Nadir
    Nov 20 at 15:48
















1














Calling setuid changes who the process belongs to, but it doesn't alter the environment variables that would be set if that user had logged in so $HOME won't be pointing at the right place to pick up the ".xinitrc" file.



The following line of code should fix that for you.



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





share|improve this answer





















  • That was it. Thank you very much
    – Nadir
    Nov 20 at 10:44






  • 1




    Note that setenv changes the environment variable of the current process as well, which may have unintended side effects, if this is undesirable, you may want to use execle instead.
    – Lie Ryan
    Nov 20 at 11:06






  • 2




    True, @LieRyan, but not much relevant when you've fork()ed, and / or if you're assuming (unsafely) that execl() will not fail, as the OP appears to do, or if you ensure that the process terminates in the event that execl() does fail.
    – John Bollinger
    Nov 20 at 15:41












  • @JohnBollinger if you are referring to check the returned value by execl(), I left it out for the sake of simplicity.
    – Nadir
    Nov 20 at 15:48














1












1








1






Calling setuid changes who the process belongs to, but it doesn't alter the environment variables that would be set if that user had logged in so $HOME won't be pointing at the right place to pick up the ".xinitrc" file.



The following line of code should fix that for you.



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





share|improve this answer












Calling setuid changes who the process belongs to, but it doesn't alter the environment variables that would be set if that user had logged in so $HOME won't be pointing at the right place to pick up the ".xinitrc" file.



The following line of code should fix that for you.



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






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 20 at 10:39









Chris Turner

6,8881917




6,8881917












  • That was it. Thank you very much
    – Nadir
    Nov 20 at 10:44






  • 1




    Note that setenv changes the environment variable of the current process as well, which may have unintended side effects, if this is undesirable, you may want to use execle instead.
    – Lie Ryan
    Nov 20 at 11:06






  • 2




    True, @LieRyan, but not much relevant when you've fork()ed, and / or if you're assuming (unsafely) that execl() will not fail, as the OP appears to do, or if you ensure that the process terminates in the event that execl() does fail.
    – John Bollinger
    Nov 20 at 15:41












  • @JohnBollinger if you are referring to check the returned value by execl(), I left it out for the sake of simplicity.
    – Nadir
    Nov 20 at 15:48


















  • That was it. Thank you very much
    – Nadir
    Nov 20 at 10:44






  • 1




    Note that setenv changes the environment variable of the current process as well, which may have unintended side effects, if this is undesirable, you may want to use execle instead.
    – Lie Ryan
    Nov 20 at 11:06






  • 2




    True, @LieRyan, but not much relevant when you've fork()ed, and / or if you're assuming (unsafely) that execl() will not fail, as the OP appears to do, or if you ensure that the process terminates in the event that execl() does fail.
    – John Bollinger
    Nov 20 at 15:41












  • @JohnBollinger if you are referring to check the returned value by execl(), I left it out for the sake of simplicity.
    – Nadir
    Nov 20 at 15:48
















That was it. Thank you very much
– Nadir
Nov 20 at 10:44




That was it. Thank you very much
– Nadir
Nov 20 at 10:44




1




1




Note that setenv changes the environment variable of the current process as well, which may have unintended side effects, if this is undesirable, you may want to use execle instead.
– Lie Ryan
Nov 20 at 11:06




Note that setenv changes the environment variable of the current process as well, which may have unintended side effects, if this is undesirable, you may want to use execle instead.
– Lie Ryan
Nov 20 at 11:06




2




2




True, @LieRyan, but not much relevant when you've fork()ed, and / or if you're assuming (unsafely) that execl() will not fail, as the OP appears to do, or if you ensure that the process terminates in the event that execl() does fail.
– John Bollinger
Nov 20 at 15:41






True, @LieRyan, but not much relevant when you've fork()ed, and / or if you're assuming (unsafely) that execl() will not fail, as the OP appears to do, or if you ensure that the process terminates in the event that execl() does fail.
– John Bollinger
Nov 20 at 15:41














@JohnBollinger if you are referring to check the returned value by execl(), I left it out for the sake of simplicity.
– Nadir
Nov 20 at 15:48




@JohnBollinger if you are referring to check the returned value by execl(), I left it out for the sake of simplicity.
– Nadir
Nov 20 at 15:48


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53390266%2fc-starting-a-x11-session-using-system-vs-using-execl%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Create new schema in PostgreSQL using DBeaver

Deepest pit of an array with Javascript: test on Codility

Fotorealismo