nixpkgs/modules/security/setuid-wrappers.nix
Eelco Dolstra dba1964122 * setuid-wrappers: support setting the mode. For instance, some
programs require that the mode is 4550 so that execution of the
  setuid program can be restricted to members of a group.
* setuid-wrappers: remove a race condition in the creation of the
  wrappers if the ownership or mode was different than root:root and
  4555.
* setuid-wrappers: allow the full path of the wrapped program to be
  specified, rather than looking it up in $PATH.

svn path=/nixos/trunk/; revision=16733
2009-08-16 17:24:59 +00:00

127 lines
3.4 KiB
Nix

{pkgs, config, ...}:
with pkgs.lib;
let
inherit (config.security) wrapperDir;
setuidWrapper = pkgs.stdenv.mkDerivation {
name = "setuid-wrapper";
buildCommand = ''
ensureDir $out/bin
gcc -Wall -O2 -DWRAPPER_DIR=\"${wrapperDir}\" ${./setuid-wrapper.c} -o $out/bin/setuid-wrapper
strip -s $out/bin/setuid-wrapper
'';
};
in
{
###### interface
options = {
security.setuidPrograms = mkOption {
default =
[ "passwd" "su" "crontab" "ping" "ping6"
"fusermount" "wodim" "cdrdao" "growisofs"
];
description = ''
Only the programs from system path listed here will be made
setuid root (through a wrapper program).
'';
};
# !!! obsolete
security.extraSetuidPrograms = mkOption {
default = [];
example = ["fusermount"];
description = ''
This option lists additional programs that must be made setuid
root.
'';
};
security.setuidOwners = mkOption {
default = [];
example =
[ { program = "sendmail";
owner = "nobody";
group = "postdrop";
setuid = false;
setgid = true;
}
];
description = ''
This option allows the ownership and permissions on the setuid
wrappers for specific programs to be overriden from the
default (setuid root, but not setgid root).
'';
};
security.wrapperDir = mkOption {
default = "/var/setuid-wrappers";
description = ''
This option defines the path to the setuid wrappers. It
should generally not be overriden.
'';
};
};
###### implementation
config = {
system.activationScripts.setuid =
let
setuidPrograms =
(map (x: { program = x; owner = "root"; group = "root"; setuid = true; })
(config.security.setuidPrograms ++
config.security.extraSetuidPrograms))
++ config.security.setuidOwners;
makeSetuidWrapper =
{ program
, source ? ""
, owner ? "nobody"
, group ? "nogroup"
, setuid ? false
, setgid ? false
, permissions ? "u+rx,g+rx,o+rx"
}:
''
source=${if source != "" then source else "$(PATH=$SETUID_PATH type -tP ${program})"}
if test -z "$source"; then
# If we can't find the program, fall back to the
# system profile.
source=/nix/var/nix/profiles/default/bin/${program}
fi
cp ${setuidWrapper}/bin/setuid-wrapper ${wrapperDir}/${program}
echo -n "$source" > ${wrapperDir}/${program}.real
chmod 0000 ${wrapperDir}/${program} # to prevent races
chown ${owner}.${group} ${wrapperDir}/${program}
chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" ${wrapperDir}/${program}
'';
in pkgs.stringsWithDeps.fullDepEntry
''
# Look in the system path and in the default profile for
# programs to be wrapped.
SETUID_PATH=${config.system.path}/bin:${config.system.path}/sbin
if test -d ${wrapperDir}; then rm -f ${wrapperDir}/*; fi # */
mkdir -p ${wrapperDir}
${concatMapStrings makeSetuidWrapper setuidPrograms}
'' [ "defaultPath" "users" ];
};
}