From 5fbe320b9173b1ef0725a79548f34f967ad16130 Mon Sep 17 00:00:00 2001 From: tv Date: Fri, 19 Apr 2019 16:32:00 +0200 Subject: krebs.shadow: init --- krebs/3modules/default.nix | 1 + krebs/3modules/shadow.nix | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 krebs/3modules/shadow.nix diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix index 4d40f385..fddb6a31 100644 --- a/krebs/3modules/default.nix +++ b/krebs/3modules/default.nix @@ -49,6 +49,7 @@ let ./rtorrent.nix ./secret.nix ./setuid.nix + ./shadow.nix ./syncthing.nix ./tinc.nix ./tinc_graphs.nix diff --git a/krebs/3modules/shadow.nix b/krebs/3modules/shadow.nix new file mode 100644 index 00000000..cff66492 --- /dev/null +++ b/krebs/3modules/shadow.nix @@ -0,0 +1,79 @@ +with import ; +{ config, pkgs, ... }: let + + cfg = config.krebs.shadow; + + mergeShadowsJq = pkgs.writeJq "merge-shadows.jq" '' + def fields_3_to_9: ["1", "", "", "", "", "", ""]; + + def read_value: + split(":") | + if length == 9 then + if .[2:] == fields_3_to_9 then + . + else + error("unrecognized field contents") + end + elif length == 2 then + if .[1] | test("^\\$6\\$") then + . + fields_3_to_9 + else + error("unrecognized hashed password") + end + else + error("unexpected field count: expected 9 or 2, got \(length)") + end; + + def write_value: + join(":"); + + split("\n") | + map(select(length > 0) | read_value) | + + reverse | + unique_by(.[0]) | + map(write_value) | + sort | + + join("\n") + ''; + +in { + + options.krebs.shadow = { + enable = mkEnableOption "krebs.shadow" // { + default = cfg.overridesFile != null; + }; + overridesFile = mkOption { + apply = x: if typeOf x == "path" then toString x else x; + default = null; + description = '' + Path to a file containing additional shadow entries, used for adding + encrypted passwords which should not be placed into the Nix store. + + The overrides file may contain either regular shadow(5) entries like: + + <login-name>:<hashed-password>:1:::::: + + Or shortened entries only containing login name and password like: + + <login-name>:<hashed-password> + ''; + type = types.nullOr (types.either types.path types.absolute-pathname); + }; + }; + + config = let + in mkIf cfg.enable { + system.activationScripts.users-tv = stringAfter [ "users" ] /* sh */ '' + ( + set -efu + umask 77 + ${pkgs.jq}/bin/jq -Rrs -f ${mergeShadowsJq} \ + /etc/shadow ${cfg.overridesFile} > /etc/shadow~ + ${pkgs.coreutils}/bin/mv /etc/shadow /etc/shadow- + ${pkgs.coreutils}/bin/mv /etc/shadow~ /etc/shadow + ) + ''; + }; +} -- cgit v1.2.3