mirror of
https://github.com/LnL7/nix-darwin.git
synced 2024-12-15 17:51:01 +00:00
36a15e8c6c
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.
133 lines
3.8 KiB
Nix
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)
|
|
'';
|
|
|
|
};
|
|
}
|