diff options
| author | Ophestra Umiker <cat@ophivana.moe> | 2024-09-04 17:03:21 +0900 |
|---|---|---|
| committer | Ophestra Umiker <cat@ophivana.moe> | 2024-09-04 17:03:21 +0900 |
| commit | 945cce2f5e487492730e06e13e920e08c55d8084 (patch) | |
| tree | bbc0147dd26df2c1e950d7b2b8242223ee869e68 /nixos.nix | |
| parent | 5c3e7cf6640721fc2cb5006c879bf570cedf1902 (diff) | |
nix: implement nixos module
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'nixos.nix')
| -rw-r--r-- | nixos.nix | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/nixos.nix b/nixos.nix new file mode 100644 index 00000000..0fe5b713 --- /dev/null +++ b/nixos.nix @@ -0,0 +1,220 @@ +{ + lib, + pkgs, + config, + ... +}: + +let + inherit (lib) + types + mkOption + mkEnableOption + mkIf + mapAttrs + mapAttrsToList + foldlAttrs + optional + ; + + cfg = config.environment.fortify; +in + +{ + options = { + environment.fortify = { + enable = mkEnableOption "fortify"; + + target = mkOption { + default = { }; + type = + let + inherit (types) + str + enum + bool + package + anything + submodule + listOf + attrsOf + nullOr + ; + in + attrsOf (submodule { + options = { + packages = mkOption { + type = listOf package; + default = [ ]; + description = '' + List of extra packages to install via home-manager. + ''; + }; + + launchers = mkOption { + type = attrsOf (submodule { + options = { + command = mkOption { + type = nullOr str; + default = null; + description = '' + Command to run as the target user. + Setting this to null will default command to wrapper name. + ''; + }; + + pulse = mkOption { + type = bool; + default = true; + description = '' + Whether to share the PulseAudio socket and cookie. + ''; + }; + + share = mkOption { + type = nullOr package; + default = null; + description = '' + Package containing share files. + Setting this to null will default package name to wrapper name. + ''; + }; + + method = mkOption { + type = enum [ + "fortify" + "fortify-sudo" + "sudo" + ]; + default = "fortify"; + description = '' + Launch method for the sandboxed program. + ''; + }; + }; + }); + default = { }; + }; + + persistence = mkOption { + type = submodule { + options = { + directories = mkOption { + type = listOf anything; + default = [ ]; + }; + + files = mkOption { + type = listOf anything; + default = [ ]; + }; + }; + }; + description = '' + Per-user state passed to github:nix-community/impermanence. + ''; + }; + + extraConfig = mkOption { + type = anything; + default = { }; + description = "Extra home-manager configuration."; + }; + }; + }); + }; + + package = mkOption { + type = types.package; + default = pkgs.callPackage ./package.nix { }; + description = "Package providing fortify."; + }; + + user = mkOption { + type = types.str; + description = "Privileged user account."; + }; + + shell = mkOption { + type = types.str; + description = '' + Shell set up to source home-manager for the privileged user. + Required for setting up the environment of sandboxed programs. + ''; + }; + + stateDir = mkOption { + type = types.str; + description = '' + The path to persistent storage where per-user state should be stored. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + environment.persistence.${cfg.stateDir}.users = mapAttrs (_: target: target.persistence) cfg.target; + + home-manager.users = + mapAttrs (_: target: target.extraConfig // { home.packages = target.packages; }) cfg.target + // { + ${cfg.user}.home.packages = + let + wrap = + user: launchers: + mapAttrsToList ( + name: launcher: + let + command = if launcher.command == null then name else launcher.command; + in + pkgs.writeShellScriptBin name ( + if launcher.method == "sudo" then + '' + exec sudo -u ${user} -i ${command} $@ + '' + else + '' + exec fortify${if launcher.pulse then " -pulse" else ""} -u ${user}${ + if launcher.method == "fortify-sudo" then " -sudo" else "" + } ${cfg.shell} -c "exec ${command} $@" + '' + ) + ) launchers; + in + foldlAttrs ( + acc: user: target: + acc + ++ (foldlAttrs ( + shares: name: launcher: + let + pkg = if launcher.share != null then launcher.share else pkgs.${name}; + link = source: "[ -d '${source}' ] && ln -sv '${source}' $out/share || true"; + in + shares + ++ optional (launcher.method == "fortify") ( + pkgs.runCommand "${name}-share" { } '' + mkdir -p $out/share + ${link "${pkg}/share/applications"} + ${link "${pkg}/share/icons"} + ${link "${pkg}/share/man"} + '' + ) + ) (wrap user target.launchers) target.launchers) + ) [ cfg.package ] cfg.target; + }; + + security.polkit.extraConfig = + let + allowList = builtins.toJSON (mapAttrsToList (name: _: name) cfg.target); + in + '' + polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.machine1.host-shell" && + ${allowList}.indexOf(action.lookup("user")) > -1 && + subject.user == "${cfg.user}") { + return polkit.Result.YES; + } + }); + ''; + }; +} |
