Allow supervisord and launchd to initialize as root by using nixproc-chainload-user to change identities
This commit is contained in:
parent
aa3900919c
commit
704eb98a42
|
@ -2,6 +2,7 @@
|
|||
, stdenv
|
||||
, writeTextFile
|
||||
, runtimeDir ? "/var/run"
|
||||
, forceDisableUserChange
|
||||
}:
|
||||
|
||||
{ name
|
||||
|
@ -30,10 +31,14 @@ let
|
|||
inherit stdenv writeTextFile;
|
||||
};
|
||||
|
||||
chainLoadUser = if initialize == "" || forceDisableUserChange then null
|
||||
else user;
|
||||
|
||||
Program = if foregroundProcess != null then
|
||||
if initialize == "" then foregroundProcess
|
||||
else generateForegroundProxy ({
|
||||
wrapDaemon = false;
|
||||
user = chainLoadUser;
|
||||
executable = foregroundProcess;
|
||||
inherit name initialize runtimeDir stdenv;
|
||||
} // stdenv.lib.optionalAttrs (instanceName != null) {
|
||||
|
@ -43,6 +48,7 @@ let
|
|||
})
|
||||
else generateForegroundProxy ({
|
||||
wrapDaemon = true;
|
||||
user = chainLoadUser;
|
||||
executable = daemon;
|
||||
inherit name initialize runtimeDir stdenv;
|
||||
} // stdenv.lib.optionalAttrs (instanceName != null) {
|
||||
|
@ -66,7 +72,7 @@ let
|
|||
Umask = umask;
|
||||
} // stdenv.lib.optionalAttrs (nice != null) {
|
||||
Nice = nice;
|
||||
} // stdenv.lib.optionalAttrs (user != null) {
|
||||
} // stdenv.lib.optionalAttrs (user != null && chainLoadUser == null) {
|
||||
UserName = user;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{ createSupervisordProgram, stdenv, writeTextFile, runtimeDir }:
|
||||
{ createSupervisordProgram, stdenv, writeTextFile, runtimeDir, forceDisableUserChange }:
|
||||
|
||||
{ name
|
||||
, description
|
||||
|
@ -26,10 +26,14 @@ let
|
|||
inherit stdenv writeTextFile;
|
||||
};
|
||||
|
||||
chainLoadUser = if initialize == "" || forceDisableUserChange then null
|
||||
else user;
|
||||
|
||||
command = if foregroundProcess != null then
|
||||
(if initialize == ""
|
||||
then foregroundProcess
|
||||
else generateForegroundProxy ({
|
||||
user = chainLoadUser;
|
||||
wrapDaemon = false;
|
||||
executable = foregroundProcess;
|
||||
inherit name initialize runtimeDir stdenv;
|
||||
|
@ -40,6 +44,7 @@ let
|
|||
})) + " ${stdenv.lib.escapeShellArgs foregroundProcessArgs}"
|
||||
else (generateForegroundProxy ({
|
||||
wrapDaemon = true;
|
||||
user = chainLoadUser;
|
||||
executable = daemon;
|
||||
inherit name initialize runtimeDir stdenv;
|
||||
} // stdenv.lib.optionalAttrs (instanceName != null) {
|
||||
|
@ -56,7 +61,7 @@ let
|
|||
inherit nice;
|
||||
} // stdenv.lib.optionalAttrs (pidFile != null) {
|
||||
inherit pidFile;
|
||||
} // stdenv.lib.optionalAttrs (user != null) {
|
||||
} // stdenv.lib.optionalAttrs (user != null && chainLoadUser == null) {
|
||||
inherit user;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{stdenv, writeTextFile}:
|
||||
|
||||
{ name
|
||||
, wrapDaemon
|
||||
, initialize
|
||||
|
@ -7,9 +8,12 @@
|
|||
, runtimeDir
|
||||
, instanceName ? null
|
||||
, pidFile ? (if instanceName == null then null else "${runtimeDir}/${instanceName}.pid")
|
||||
, user ? null
|
||||
}:
|
||||
|
||||
let
|
||||
chainload-user = (import ../../../tools {}).chainload-user;
|
||||
|
||||
_pidFile = if pidFile == null then "${runtimeDir}/$(basename ${executable}).pid" else pidFile;
|
||||
in
|
||||
writeTextFile {
|
||||
|
@ -39,7 +43,7 @@ writeTextFile {
|
|||
trap _interrupt SIGINT
|
||||
|
||||
# Start process in the background as a daemon
|
||||
${executable} "$@"
|
||||
${stdenv.lib.optionalString (user != null) "${chainload-user}/bin/nixproc-chainload-user ${user}"} ${executable} "$@"
|
||||
|
||||
# Wait for the PID file to become available. Useful to work with daemons that don't behave well enough.
|
||||
count=1 # Start with 1, because 0 returns a non-zero exit status when incrementing it
|
||||
|
@ -76,7 +80,7 @@ writeTextFile {
|
|||
blocker_pid=$!
|
||||
wait $blocker_pid
|
||||
'' else ''
|
||||
exec "${executable}" "$@"
|
||||
exec ${stdenv.lib.optionalString (user != null) "${chainload-user}/bin/nixproc-chainload-user ${user} "}"${executable}" "$@"
|
||||
''}
|
||||
'';
|
||||
executable = true;
|
||||
|
|
|
@ -13,6 +13,8 @@ result // {
|
|||
auth required pam_deny.so
|
||||
password sufficient pam_unix.so nullok sha512
|
||||
EOF
|
||||
|
||||
sed -i -e "s|PATH=/bin:/usr/bin|PATH=/bin:/usr/bin:/nix/var/nix/profiles/default/bin|" /etc/login.defs
|
||||
'';
|
||||
|
||||
contents = result.contents or [] ++ [ pkgs.su pkgs.shadow ];
|
||||
|
|
|
@ -46,7 +46,7 @@ let
|
|||
};
|
||||
|
||||
generateSupervisordProgram = import ../../backends/supervisord/generate-supervisord-program.nix {
|
||||
inherit createSupervisordProgram runtimeDir;
|
||||
inherit createSupervisordProgram runtimeDir forceDisableUserChange;
|
||||
inherit (pkgs) stdenv writeTextFile;
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,7 @@ let
|
|||
|
||||
generateLaunchdDaemon = import ../../backends/launchd/generate-launchd-daemon.nix {
|
||||
inherit (pkgs) stdenv writeTextFile;
|
||||
inherit createLaunchdDaemon runtimeDir;
|
||||
inherit createLaunchdDaemon runtimeDir forceDisableUserChange;
|
||||
};
|
||||
|
||||
createCygrunsrvParams = import ../../backends/cygrunsrv/create-cygrunsrv-params.nix {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
CC = cc
|
||||
|
||||
all:
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) main.c -o nixproc-chainload-user
|
||||
|
||||
install: all
|
||||
install -d -m755 $(PREFIX)/bin
|
||||
install -m755 nixproc-chainload-user $(PREFIX)/bin
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f nixproc-chainload-user
|
|
@ -0,0 +1,8 @@
|
|||
{stdenv}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "nixproc-chainload-user";
|
||||
src = ./.;
|
||||
makeFlags = "PREFIX=$(out)";
|
||||
dontStrip = true;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
printf("Usage: %s username command [args]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *username = argv[1];
|
||||
|
||||
/* Query password entry for the user */
|
||||
struct passwd *pwentry = getpwnam(username);
|
||||
|
||||
if(pwentry == NULL)
|
||||
{
|
||||
fprintf(stderr, "Cannot find password entry for user: %s\n", username);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Change user permissions to the requested user */
|
||||
if(setgid(pwentry->pw_gid) == 0 && setuid(pwentry->pw_uid) == 0)
|
||||
{
|
||||
/* Exec into the requested process */
|
||||
char **cmd_argv = argv + 2;
|
||||
execvp(cmd_argv[0], cmd_argv);
|
||||
fprintf(stderr, "Cannot execute command: %s\n", cmd_argv[0]);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Cannot change into user: %s with corresponding group!\n", username);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,10 @@
|
|||
}:
|
||||
|
||||
rec {
|
||||
chainload-user = import ./chainload-user {
|
||||
inherit (pkgs) stdenv;
|
||||
};
|
||||
|
||||
common = import ./common {
|
||||
inherit (pkgs) stdenv getopt;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue