1# This module defines a system-wide environment that will be
2# initialised by pam_env (that is, not only in shells).
3{ config, lib, pkgs, ... }:
4
5with lib;
6
7let
8
9 cfg = config.environment;
10
11in
12
13{
14
15 options = {
16
17 environment.sessionVariables = mkOption {
18 default = {};
19 description = ''
20 A set of environment variables used in the global environment.
21 These variables will be set by PAM early in the login process.
22
23 The value of each session variable can be either a string or a
24 list of strings. The latter is concatenated, interspersed with
25 colon characters.
26
27 Note, due to limitations in the PAM format values may not
28 contain the <literal>"</literal> character.
29
30 Also, these variables are merged into
31 <xref linkend="opt-environment.variables"/> and it is
32 therefore not possible to use PAM style variables such as
33 <code>@{HOME}</code>.
34 '';
35 type = with types; attrsOf (either str (listOf str));
36 apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
37 };
38
39 environment.profileRelativeSessionVariables = mkOption {
40 type = types.attrsOf (types.listOf types.str);
41 example = { PATH = [ "/bin" ]; MANPATH = [ "/man" "/share/man" ]; };
42 description = ''
43 Attribute set of environment variable used in the global
44 environment. These variables will be set by PAM early in the
45 login process.
46
47 Variable substitution is available as described in
48 <citerefentry>
49 <refentrytitle>pam_env.conf</refentrytitle>
50 <manvolnum>5</manvolnum>
51 </citerefentry>.
52
53 Each attribute maps to a list of relative paths. Each relative
54 path is appended to the each profile of
55 <option>environment.profiles</option> to form the content of
56 the corresponding environment variable.
57
58 Also, these variables are merged into
59 <xref linkend="opt-environment.profileRelativeEnvVars"/> and it is
60 therefore not possible to use PAM style variables such as
61 <code>@{HOME}</code>.
62 '';
63 };
64
65 };
66
67 config = {
68
69 system.build.pamEnvironment =
70 let
71 suffixedVariables =
72 flip mapAttrs cfg.profileRelativeSessionVariables (envVar: suffixes:
73 flip concatMap cfg.profiles (profile:
74 map (suffix: "${profile}${suffix}") suffixes
75 )
76 );
77
78 # We're trying to use the same syntax for PAM variables and env variables.
79 # That means we need to map the env variables that people might use to their
80 # equivalent PAM variable.
81 replaceEnvVars = replaceStrings ["$HOME" "$USER"] ["@{HOME}" "@{PAM_USER}"];
82
83 pamVariable = n: v:
84 ''${n} DEFAULT="${concatStringsSep ":" (map replaceEnvVars (toList v))}"'';
85
86 pamVariables =
87 concatStringsSep "\n"
88 (mapAttrsToList pamVariable
89 (zipAttrsWith (n: concatLists)
90 [
91 # Make sure security wrappers are prioritized without polluting
92 # shell environments with an extra entry. Sessions which depend on
93 # pam for its environment will otherwise have eg. broken sudo. In
94 # particular Gnome Shell sometimes fails to source a proper
95 # environment from a shell.
96 { PATH = [ config.security.wrapperDir ]; }
97
98 (mapAttrs (n: toList) cfg.sessionVariables)
99 suffixedVariables
100 ]));
101 in
102 pkgs.writeText "pam-environment" "${pamVariables}\n";
103
104 };
105
106}