C starting a X11 session using system() vs using execl()
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
add a comment |
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
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 runningexecl("/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 usepam_authenticate()
without root privileges), and Im able to run the daemon without root privs.
– Nadir
Nov 20 at 15:18
add a comment |
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
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
c unix fork
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 runningexecl("/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 usepam_authenticate()
without root privileges), and Im able to run the daemon without root privs.
– Nadir
Nov 20 at 15:18
add a comment |
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 runningexecl("/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 usepam_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
add a comment |
1 Answer
1
active
oldest
votes
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);
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 useexecle
instead.
– Lie Ryan
Nov 20 at 11:06
2
True, @LieRyan, but not much relevant when you'vefork()
ed, and / or if you're assuming (unsafely) thatexecl()
will not fail, as the OP appears to do, or if you ensure that the process terminates in the event thatexecl()
does fail.
– John Bollinger
Nov 20 at 15:41
@JohnBollinger if you are referring to check the returned value byexecl()
, I left it out for the sake of simplicity.
– Nadir
Nov 20 at 15:48
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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);
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 useexecle
instead.
– Lie Ryan
Nov 20 at 11:06
2
True, @LieRyan, but not much relevant when you'vefork()
ed, and / or if you're assuming (unsafely) thatexecl()
will not fail, as the OP appears to do, or if you ensure that the process terminates in the event thatexecl()
does fail.
– John Bollinger
Nov 20 at 15:41
@JohnBollinger if you are referring to check the returned value byexecl()
, I left it out for the sake of simplicity.
– Nadir
Nov 20 at 15:48
add a comment |
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);
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 useexecle
instead.
– Lie Ryan
Nov 20 at 11:06
2
True, @LieRyan, but not much relevant when you'vefork()
ed, and / or if you're assuming (unsafely) thatexecl()
will not fail, as the OP appears to do, or if you ensure that the process terminates in the event thatexecl()
does fail.
– John Bollinger
Nov 20 at 15:41
@JohnBollinger if you are referring to check the returned value byexecl()
, I left it out for the sake of simplicity.
– Nadir
Nov 20 at 15:48
add a comment |
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);
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);
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 useexecle
instead.
– Lie Ryan
Nov 20 at 11:06
2
True, @LieRyan, but not much relevant when you'vefork()
ed, and / or if you're assuming (unsafely) thatexecl()
will not fail, as the OP appears to do, or if you ensure that the process terminates in the event thatexecl()
does fail.
– John Bollinger
Nov 20 at 15:41
@JohnBollinger if you are referring to check the returned value byexecl()
, I left it out for the sake of simplicity.
– Nadir
Nov 20 at 15:48
add a comment |
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 useexecle
instead.
– Lie Ryan
Nov 20 at 11:06
2
True, @LieRyan, but not much relevant when you'vefork()
ed, and / or if you're assuming (unsafely) thatexecl()
will not fail, as the OP appears to do, or if you ensure that the process terminates in the event thatexecl()
does fail.
– John Bollinger
Nov 20 at 15:41
@JohnBollinger if you are referring to check the returned value byexecl()
, 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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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