1
0
Fork 0
mirror of https://github.com/LnL7/nix-darwin.git synced 2024-12-15 17:51:01 +00:00
nix-darwin/modules/system/etc.nix
Emily 36a15e8c6c write-text: remove support for copy
This is a huge anti‐declarative footgun; `copy` files cannot
distinguish if a previous version is managed by nix-darwin, so they
can’t check the hash, so they’re prone to destroying data, and
copied files are not deleted when they’re removed from the system
configuration, which led to a security bug. Nothing else in‐tree
was using this functionality, so let’s make sure it doesn’t
cause any more bugs.
2024-06-15 12:15:13 +01:00

133 lines
3.8 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
text = import ../lib/write-text.nix {
inherit lib;
mkTextDerivation = name: text: pkgs.writeText "etc-${name}" text;
};
etc = filter (f: f.enable) (attrValues config.environment.etc);
in
{
options = {
environment.etc = mkOption {
type = types.attrsOf (types.submodule text);
default = { };
description = ''
Set of files that have to be linked in {file}`/etc`.
'';
};
};
config = {
system.build.etc = pkgs.runCommand "etc"
{ preferLocalBuild = true; }
''
mkdir -p $out/etc
cd $out/etc
${concatMapStringsSep "\n" (attr: ''
mkdir -p "$(dirname ${escapeShellArg attr.target})"
ln -s ${escapeShellArgs [ attr.source attr.target ]}
'') etc}
'';
system.activationScripts.etcChecks.text = ''
declare -A etcSha256Hashes=(
${concatMapStringsSep "\n "
(attr:
"[${escapeShellArg attr.target}]=" +
escapeShellArg (concatStringsSep " " attr.knownSha256Hashes))
etc}
)
declare -a etcProblems=()
while IFS= read -r -d "" configFile; do
subPath=''${configFile#"$systemConfig"/etc/}
etcStaticFile=/etc/static/$subPath
etcFile=/etc/$subPath
# We need to check files that exist and aren't already links to
# $etcStaticFile for known hashes.
if [[
-e $etcFile
&& $(readlink "$etcFile") != "$etcStaticFile"
]]; then
# Only check hashes of paths that resolve to regular files;
# everything else (e.g. directories) we complain about
# unconditionally.
if [[ -f $(readlink -f "$etcFile") ]]; then
etcFileSha256Output=$(shasum -a 256 "$etcFile")
etcFileSha256Hash=''${etcFileSha256Output%% *}
for knownSha256Hash in ''${etcSha256Hashes[$subPath]}; do
if [[ $etcFileSha256Hash == "$knownSha256Hash" ]]; then
# Hash matches, OK to overwrite; go to the next file.
continue 2
fi
done
fi
etcProblems+=("$etcFile")
fi
done < <(find -H "$systemConfig/etc" -type l -print0)
if (( ''${#etcProblems[@]} )); then
printf >&2 '\x1B[1;31merror: Unexpected files in /etc, aborting '
printf >&2 'activation\x1B[0m\n'
printf >&2 'The following files have unrecognized content and would be '
printf >&2 'overwritten:\n\n'
printf >&2 ' %s\n' "''${etcProblems[@]}"
printf >&2 '\nPlease check there is nothing critical in these files, '
printf >&2 'rename them by adding .before-nix-darwin to the end, and '
printf >&2 'then try again.\n'
exit 2
fi
'';
system.activationScripts.etc.text = ''
# Set up the statically computed bits of /etc.
printf >&2 'setting up /etc...\n'
ln -sfn "$(readlink -f "$systemConfig/etc")" /etc/static
while IFS= read -r -d "" etcStaticFile; do
etcFile=/etc/''${etcStaticFile#/etc/static/}
etcDir=''${etcFile%/*}
if [[ ! -d $etcDir ]]; then
mkdir -p "$etcDir"
fi
if [[ -e $etcFile ]]; then
if [[ $(readlink -- "$etcFile") == "$etcStaticFile" ]]; then
continue
else
mv "$etcFile" "$etcFile.before-nix-darwin"
fi
fi
ln -s "$etcStaticFile" "$etcFile"
done < <(find -H /etc/static -type l -print0)
while IFS= read -r -d "" etcFile; do
etcStaticFile=/etc/static/''${etcFile#/etc/}
# Delete stale links into /etc/static.
if [[
$(readlink -- "$etcFile") == "$etcStaticFile"
&& ! -e $etcStaticFile
]]; then
rm "$etcFile"
fi
done < <(find -H /etc -type l -print0)
'';
};
}