diff --git a/nixproc/backends/launchd/generate-launchd-daemon.nix b/nixproc/backends/launchd/generate-launchd-daemon.nix index 7445ca9..bd25874 100644 --- a/nixproc/backends/launchd/generate-launchd-daemon.nix +++ b/nixproc/backends/launchd/generate-launchd-daemon.nix @@ -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; }; diff --git a/nixproc/backends/supervisord/generate-supervisord-program.nix b/nixproc/backends/supervisord/generate-supervisord-program.nix index 3f6abe5..fcc0a01 100644 --- a/nixproc/backends/supervisord/generate-supervisord-program.nix +++ b/nixproc/backends/supervisord/generate-supervisord-program.nix @@ -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; }; diff --git a/nixproc/backends/util/generate-foreground-proxy.nix b/nixproc/backends/util/generate-foreground-proxy.nix index 0f4e9c1..40b6219 100644 --- a/nixproc/backends/util/generate-foreground-proxy.nix +++ b/nixproc/backends/util/generate-foreground-proxy.nix @@ -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; diff --git a/nixproc/create-image-from-steps/steps/su-pam.nix b/nixproc/create-image-from-steps/steps/su-pam.nix index a0ba171..f473da1 100644 --- a/nixproc/create-image-from-steps/steps/su-pam.nix +++ b/nixproc/create-image-from-steps/steps/su-pam.nix @@ -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 ]; diff --git a/nixproc/create-managed-process/universal/create-managed-process-universal.nix b/nixproc/create-managed-process/universal/create-managed-process-universal.nix index 7c9489f..73da5e2 100644 --- a/nixproc/create-managed-process/universal/create-managed-process-universal.nix +++ b/nixproc/create-managed-process/universal/create-managed-process-universal.nix @@ -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 { diff --git a/tools/chainload-user/Makefile b/tools/chainload-user/Makefile new file mode 100644 index 0000000..8ba7ad4 --- /dev/null +++ b/tools/chainload-user/Makefile @@ -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 diff --git a/tools/chainload-user/default.nix b/tools/chainload-user/default.nix new file mode 100644 index 0000000..9fff63a --- /dev/null +++ b/tools/chainload-user/default.nix @@ -0,0 +1,8 @@ +{stdenv}: + +stdenv.mkDerivation { + name = "nixproc-chainload-user"; + src = ./.; + makeFlags = "PREFIX=$(out)"; + dontStrip = true; +} diff --git a/tools/chainload-user/main.c b/tools/chainload-user/main.c new file mode 100644 index 0000000..11c32fe --- /dev/null +++ b/tools/chainload-user/main.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include + +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; + } + } +} diff --git a/tools/default.nix b/tools/default.nix index 2c545f0..4ee549e 100644 --- a/tools/default.nix +++ b/tools/default.nix @@ -3,6 +3,10 @@ }: rec { + chainload-user = import ./chainload-user { + inherit (pkgs) stdenv; + }; + common = import ./common { inherit (pkgs) stdenv getopt; };