1{ stdenv, lib, fetchurl, fetchpatch, makeWrapper, autoreconfHook
2, pkg-config, which
3, flex, bison
4, linuxHeaders ? stdenv.cc.libc.linuxHeaders
5, gawk
6, withPerl ? stdenv.hostPlatform == stdenv.buildPlatform && lib.meta.availableOn stdenv.hostPlatform perl, perl
7, withPython ? stdenv.hostPlatform == stdenv.buildPlatform && lib.meta.availableOn stdenv.hostPlatform python3, python3
8, swig
9, ncurses
10, pam
11, libnotify
12, buildPackages
13, coreutils
14, bash
15, gnugrep
16, gnused
17, kmod
18, writeShellScript
19, closureInfo
20, runCommand
21}:
22
23let
24 apparmor-version = "3.0.3";
25
26 apparmor-meta = component: with lib; {
27 homepage = "https://apparmor.net/";
28 description = "A mandatory access control system - ${component}";
29 license = licenses.gpl2;
30 maintainers = with maintainers; [ joachifm julm phreedom thoughtpolice ];
31 platforms = platforms.linux;
32 };
33
34 apparmor-sources = fetchurl {
35 url = "https://launchpad.net/apparmor/${lib.versions.majorMinor apparmor-version}/${apparmor-version}/+download/apparmor-${apparmor-version}.tar.gz";
36 sha256 = "0nasq8pdmzkrf856yg1v8z5hcs0nn6gw2qr60ab0a7j9ixfv0g8m";
37 };
38
39 aa-teardown = writeShellScript "aa-teardown" ''
40 PATH="${lib.makeBinPath [coreutils gnused gnugrep]}:$PATH"
41 . ${apparmor-parser}/lib/apparmor/rc.apparmor.functions
42 remove_profiles
43 '';
44
45 prePatchCommon = ''
46 chmod a+x ./common/list_capabilities.sh ./common/list_af_names.sh
47 patchShebangs ./common/list_capabilities.sh ./common/list_af_names.sh
48 substituteInPlace ./common/Make.rules \
49 --replace "/usr/bin/pod2man" "${buildPackages.perl}/bin/pod2man" \
50 --replace "/usr/bin/pod2html" "${buildPackages.perl}/bin/pod2html" \
51 --replace "/usr/include/linux/capability.h" "${linuxHeaders}/include/linux/capability.h" \
52 --replace "/usr/share/man" "share/man"
53 '';
54
55 patches = lib.optionals stdenv.hostPlatform.isMusl [
56 (fetchpatch {
57 url = "https://git.alpinelinux.org/aports/plain/testing/apparmor/0003-Added-missing-typedef-definitions-on-parser.patch?id=74b8427cc21f04e32030d047ae92caa618105b53";
58 name = "0003-Added-missing-typedef-definitions-on-parser.patch";
59 sha256 = "0yyaqz8jlmn1bm37arggprqz0njb4lhjni2d9c8qfqj0kll0bam0";
60 })
61 ];
62
63 # Set to `true` after the next FIXME gets fixed or this gets some
64 # common derivation infra. Too much copy-paste to fix one by one.
65 doCheck = false;
66
67 # FIXME: convert these to a single multiple-outputs package?
68
69 libapparmor = stdenv.mkDerivation {
70 pname = "libapparmor";
71 version = apparmor-version;
72
73 src = apparmor-sources;
74
75 # checking whether python bindings are enabled... yes
76 # checking for python3... no
77 # configure: error: python is required when enabling python bindings
78 strictDeps = false;
79
80 nativeBuildInputs = [
81 autoreconfHook
82 bison
83 flex
84 pkg-config
85 swig
86 ncurses
87 which
88 perl
89 ] ++ lib.optional withPython python3;
90
91 buildInputs = lib.optional withPerl perl
92 ++ lib.optional withPython python3;
93
94 # required to build apparmor-parser
95 dontDisableStatic = true;
96
97 prePatch = prePatchCommon + ''
98 substituteInPlace ./libraries/libapparmor/swig/perl/Makefile.am --replace install_vendor install_site
99 substituteInPlace ./libraries/libapparmor/swig/perl/Makefile.in --replace install_vendor install_site
100 substituteInPlace ./libraries/libapparmor/src/Makefile.am --replace "/usr/include/netinet/in.h" "${lib.getDev stdenv.cc.libc}/include/netinet/in.h"
101 substituteInPlace ./libraries/libapparmor/src/Makefile.in --replace "/usr/include/netinet/in.h" "${lib.getDev stdenv.cc.libc}/include/netinet/in.h"
102 '';
103 inherit patches;
104
105 postPatch = ''
106 cd ./libraries/libapparmor
107 '';
108
109 # https://gitlab.com/apparmor/apparmor/issues/1
110 configureFlags = [
111 (lib.withFeature withPerl "perl")
112 (lib.withFeature withPython "python")
113 ];
114
115 outputs = [ "out" ] ++ lib.optional withPython "python";
116
117 postInstall = lib.optionalString withPython ''
118 mkdir -p $python/lib
119 mv $out/lib/python* $python/lib/
120 '';
121
122 inherit doCheck;
123
124 meta = apparmor-meta "library";
125 };
126
127 apparmor-utils = stdenv.mkDerivation {
128 pname = "apparmor-utils";
129 version = apparmor-version;
130
131 src = apparmor-sources;
132
133 strictDeps = true;
134
135 nativeBuildInputs = [ makeWrapper which python3 ];
136
137 buildInputs = [
138 bash
139 perl
140 python3
141 libapparmor
142 libapparmor.python
143 ];
144
145 prePatch = prePatchCommon +
146 # Do not build vim file
147 lib.optionalString stdenv.hostPlatform.isMusl ''
148 sed -i ./utils/Makefile -e "/\<vim\>/d"
149 '' + ''
150 for file in utils/apparmor/easyprof.py utils/apparmor/aa.py utils/logprof.conf; do
151 substituteInPlace $file --replace "/sbin/apparmor_parser" "${apparmor-parser}/bin/apparmor_parser"
152 done
153 '';
154 inherit patches;
155 postPatch = "cd ./utils";
156 makeFlags = [ "LANGS=" ];
157 installFlags = [ "DESTDIR=$(out)" "BINDIR=$(out)/bin" "VIM_INSTALL_PATH=$(out)/share" "PYPREFIX=" ];
158
159 postInstall = ''
160 sed -i $out/bin/aa-unconfined -e "/my_env\['PATH'\]/d"
161 for prog in aa-audit aa-autodep aa-cleanprof aa-complain aa-disable aa-enforce aa-genprof aa-logprof aa-mergeprof aa-unconfined ; do
162 wrapProgram $out/bin/$prog --prefix PYTHONPATH : "$out/lib/${python3.libPrefix}/site-packages:$PYTHONPATH"
163 done
164
165 substituteInPlace $out/bin/aa-notify \
166 --replace /usr/bin/notify-send ${libnotify}/bin/notify-send \
167 --replace /usr/bin/perl "${perl}/bin/perl -I ${libapparmor}/${perl.libPrefix}"
168
169 substituteInPlace $out/bin/aa-remove-unknown \
170 --replace "/lib/apparmor/rc.apparmor.functions" "${apparmor-parser}/lib/apparmor/rc.apparmor.functions"
171 wrapProgram $out/bin/aa-remove-unknown \
172 --prefix PATH : ${lib.makeBinPath [ gawk ]}
173
174 ln -s ${aa-teardown} $out/bin/aa-teardown
175 '';
176
177 inherit doCheck;
178
179 meta = apparmor-meta "user-land utilities" // {
180 broken = !(withPython && withPerl);
181 };
182 };
183
184 apparmor-bin-utils = stdenv.mkDerivation {
185 pname = "apparmor-bin-utils";
186 version = apparmor-version;
187
188 src = apparmor-sources;
189
190 nativeBuildInputs = [
191 pkg-config
192 libapparmor
193 gawk
194 which
195 ];
196
197 buildInputs = [
198 libapparmor
199 ];
200
201 prePatch = prePatchCommon;
202 postPatch = ''
203 cd ./binutils
204 '';
205 makeFlags = [ "LANGS=" "USE_SYSTEM=1" ];
206 installFlags = [ "DESTDIR=$(out)" "BINDIR=$(out)/bin" "SBINDIR=$(out)/bin" ];
207
208 inherit doCheck;
209
210 meta = apparmor-meta "binary user-land utilities";
211 };
212
213 apparmor-parser = stdenv.mkDerivation {
214 name = "apparmor-parser";
215 version = apparmor-version;
216
217 src = apparmor-sources;
218
219 nativeBuildInputs = [ bison flex which ];
220
221 buildInputs = [ libapparmor ];
222
223 prePatch = prePatchCommon + ''
224 ## techdoc.pdf still doesn't build ...
225 substituteInPlace ./parser/Makefile \
226 --replace "/usr/bin/bison" "${bison}/bin/bison" \
227 --replace "/usr/bin/flex" "${flex}/bin/flex" \
228 --replace "/usr/include/linux/capability.h" "${linuxHeaders}/include/linux/capability.h" \
229 --replace "manpages htmlmanpages pdf" "manpages htmlmanpages"
230 substituteInPlace parser/rc.apparmor.functions \
231 --replace "/sbin/apparmor_parser" "$out/bin/apparmor_parser"
232 sed -i parser/rc.apparmor.functions -e '2i . ${./fix-rc.apparmor.functions.sh}'
233 '';
234 inherit patches;
235 postPatch = ''
236 cd ./parser
237 '';
238 makeFlags = [
239 "LANGS=" "USE_SYSTEM=1" "INCLUDEDIR=${libapparmor}/include"
240 "AR=${stdenv.cc.bintools.targetPrefix}ar"
241 ];
242 installFlags = [ "DESTDIR=$(out)" "DISTRO=unknown" ];
243
244 inherit doCheck;
245
246 meta = apparmor-meta "rule parser";
247 };
248
249 apparmor-pam = stdenv.mkDerivation {
250 pname = "apparmor-pam";
251 version = apparmor-version;
252
253 src = apparmor-sources;
254
255 nativeBuildInputs = [ pkg-config which ];
256
257 buildInputs = [ libapparmor pam ];
258
259 postPatch = ''
260 cd ./changehat/pam_apparmor
261 '';
262 makeFlags = [ "USE_SYSTEM=1" ];
263 installFlags = [ "DESTDIR=$(out)" ];
264
265 inherit doCheck;
266
267 meta = apparmor-meta "PAM service";
268 };
269
270 apparmor-profiles = stdenv.mkDerivation {
271 pname = "apparmor-profiles";
272 version = apparmor-version;
273
274 src = apparmor-sources;
275
276 nativeBuildInputs = [ which ];
277
278 postPatch = ''
279 cd ./profiles
280 '';
281
282 installFlags = [ "DESTDIR=$(out)" "EXTRAS_DEST=$(out)/share/apparmor/extra-profiles" ];
283
284 inherit doCheck;
285
286 meta = apparmor-meta "profiles";
287 };
288
289 apparmor-kernel-patches = stdenv.mkDerivation {
290 pname = "apparmor-kernel-patches";
291 version = apparmor-version;
292
293 src = apparmor-sources;
294
295 dontBuild = true;
296
297 installPhase = ''
298 mkdir "$out"
299 cp -R ./kernel-patches/* "$out"
300 '';
301
302 inherit doCheck;
303
304 meta = apparmor-meta "kernel patches";
305 };
306
307 # Generate generic AppArmor rules in a file,
308 # from the closure of given rootPaths.
309 # To be included in an AppArmor profile like so:
310 # include "$(apparmorRulesFromClosure {} [pkgs.hello]}"
311 apparmorRulesFromClosure =
312 { # The store path of the derivation is given in $path
313 additionalRules ? []
314 # TODO: factorize here some other common paths
315 # that may emerge from use cases.
316 , baseRules ? [
317 "r $path"
318 "r $path/etc/**"
319 "r $path/share/**"
320 # Note that not all libraries are prefixed with "lib",
321 # eg. glibc-2.30/lib/ld-2.30.so
322 "mr $path/lib/**.so*"
323 # eg. glibc-2.30/lib/gconv/gconv-modules
324 "r $path/lib/**"
325 ]
326 , name ? ""
327 }: rootPaths: runCommand
328 ( "apparmor-closure-rules"
329 + lib.optionalString (name != "") "-${name}" ) {} ''
330 touch $out
331 while read -r path
332 do printf >>$out "%s,\n" ${lib.concatMapStringsSep " " (x: "\"${x}\"") (baseRules ++ additionalRules)}
333 done <${closureInfo { inherit rootPaths; }}/store-paths
334 '';
335in
336{
337 inherit
338 libapparmor
339 apparmor-utils
340 apparmor-bin-utils
341 apparmor-parser
342 apparmor-pam
343 apparmor-profiles
344 apparmor-kernel-patches
345 apparmorRulesFromClosure;
346}