1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 inherit (config.security) wrapperDir;
8
9 setuidWrapper = pkgs.stdenv.mkDerivation {
10 name = "setuid-wrapper";
11 buildCommand = ''
12 mkdir -p $out/bin
13 cp ${./setuid-wrapper.c} setuid-wrapper.c
14 gcc -Wall -O2 -DWRAPPER_DIR=\"${wrapperDir}\" \
15 setuid-wrapper.c -o $out/bin/setuid-wrapper
16 strip -S $out/bin/setuid-wrapper
17 '';
18 };
19
20in
21
22{
23
24 ###### interface
25
26 options = {
27
28 security.setuidPrograms = mkOption {
29 type = types.listOf types.str;
30 default = [];
31 example = ["passwd"];
32 description = ''
33 The Nix store cannot contain setuid/setgid programs directly.
34 For this reason, NixOS can automatically generate wrapper
35 programs that have the necessary privileges. This option
36 lists the names of programs in the system environment for
37 which setuid root wrappers should be created.
38 '';
39 };
40
41 security.setuidOwners = mkOption {
42 type = types.listOf types.attrs;
43 default = [];
44 example =
45 [ { program = "sendmail";
46 owner = "nobody";
47 group = "postdrop";
48 setuid = false;
49 setgid = true;
50 permissions = "u+rx,g+x,o+x";
51 }
52 ];
53 description = ''
54 This option allows the ownership and permissions on the setuid
55 wrappers for specific programs to be overridden from the
56 default (setuid root, but not setgid root).
57 '';
58 };
59
60 security.wrapperDir = mkOption {
61 internal = true;
62 type = types.path;
63 default = "/var/setuid-wrappers";
64 description = ''
65 This option defines the path to the setuid wrappers. It
66 should generally not be overriden. Some packages in Nixpkgs
67 expect that <option>wrapperDir</option> is
68 <filename>/var/setuid-wrappers</filename>.
69 '';
70 };
71
72 };
73
74
75 ###### implementation
76
77 config = {
78
79 security.setuidPrograms = [ "fusermount" ];
80
81 system.activationScripts.setuid =
82 let
83 setuidPrograms =
84 (map (x: { program = x; owner = "root"; group = "root"; setuid = true; })
85 config.security.setuidPrograms)
86 ++ config.security.setuidOwners;
87
88 makeSetuidWrapper =
89 { program
90 , source ? ""
91 , owner ? "nobody"
92 , group ? "nogroup"
93 , setuid ? false
94 , setgid ? false
95 , permissions ? "u+rx,g+x,o+x"
96 }:
97
98 ''
99 if ! source=${if source != "" then source else "$(PATH=$SETUID_PATH type -tP ${program})"}; then
100 # If we can't find the program, fall back to the
101 # system profile.
102 source=/nix/var/nix/profiles/default/bin/${program}
103 fi
104
105 cp ${setuidWrapper}/bin/setuid-wrapper ${wrapperDir}/${program}
106 echo -n "$source" > ${wrapperDir}/${program}.real
107 chmod 0000 ${wrapperDir}/${program} # to prevent races
108 chown ${owner}.${group} ${wrapperDir}/${program}
109 chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" ${wrapperDir}/${program}
110 '';
111
112 in stringAfter [ "users" ]
113 ''
114 # Look in the system path and in the default profile for
115 # programs to be wrapped.
116 SETUID_PATH=${config.system.path}/bin:${config.system.path}/sbin
117
118 rm -f ${wrapperDir}/* # */
119
120 ${concatMapStrings makeSetuidWrapper setuidPrograms}
121 '';
122
123 };
124
125}