init: Support starting services as a separate user
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
apio 2023-08-14 10:46:45 +02:00
parent cfb60fad25
commit ba3e32917e
Signed by: apio
GPG Key ID: B8A7D06E42258954

View File

@ -9,6 +9,7 @@
#include <os/File.h> #include <os/File.h>
#include <os/Process.h> #include <os/Process.h>
#include <os/Security.h> #include <os/Security.h>
#include <pwd.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -19,6 +20,8 @@
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
#include <unistd.h> #include <unistd.h>
static bool g_is_system = false;
FILE* g_init_log = nullptr; FILE* g_init_log = nullptr;
// Request a successful exit from the system (for tests) // Request a successful exit from the system (for tests)
@ -42,6 +45,8 @@ struct Service
String standard_output; String standard_output;
String standard_error; String standard_error;
String standard_input; String standard_input;
Option<uid_t> user {};
Option<gid_t> group {};
bool wait { false }; bool wait { false };
Option<pid_t> pid {}; Option<pid_t> pid {};
}; };
@ -67,6 +72,12 @@ static Result<void> service_child(const Service& service, SharedPtr<os::File> ou
if (error) dup2(error->fd(), STDERR_FILENO); if (error) dup2(error->fd(), STDERR_FILENO);
if (input) dup2(input->fd(), STDIN_FILENO); if (input) dup2(input->fd(), STDIN_FILENO);
if (service.user.has_value())
{
setgid(service.group.value());
setuid(service.user.value());
}
if (service.environment.is_empty()) { TRY(os::Process::exec(args[0].view(), args.slice(), false)); } if (service.environment.is_empty()) { TRY(os::Process::exec(args[0].view(), args.slice(), false)); }
else else
{ {
@ -216,6 +227,15 @@ static Result<void> load_service(const os::Path& path)
continue; continue;
} }
if (g_is_system && parts[0].view() == "User")
{
auto* pw = getpwnam(parts[1].chars());
if (!pw) continue;
service.user = pw->pw_uid;
service.group = pw->pw_gid;
continue;
}
if (parts[0].view() == "Wait") if (parts[0].view() == "Wait")
{ {
if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1) if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1)
@ -311,6 +331,8 @@ Result<int> sysinit()
return 1; return 1;
} }
g_is_system = true;
// Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us) // Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us)
// can print stuff. // can print stuff.
stdin = fopen("/dev/console", "r"); stdin = fopen("/dev/console", "r");