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, options, 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 `"` character.
29
30 Also, these variables are merged into
31 [](#opt-environment.variables) and it is
32 therefore not possible to use PAM style variables such as
33 `@{HOME}`.
34 '';
35 inherit (options.environment.variables) type apply;
36 };
37
38 environment.profileRelativeSessionVariables = mkOption {
39 type = types.attrsOf (types.listOf types.str);
40 example = { PATH = [ "/bin" ]; MANPATH = [ "/man" "/share/man" ]; };
41 description = ''
42 Attribute set of environment variable used in the global
43 environment. These variables will be set by PAM early in the
44 login process.
45
46 Variable substitution is available as described in
47 {manpage}`pam_env.conf(5)`.
48
49 Each attribute maps to a list of relative paths. Each relative
50 path is appended to the each profile of
51 {option}`environment.profiles` to form the content of
52 the corresponding environment variable.
53
54 Also, these variables are merged into
55 [](#opt-environment.profileRelativeEnvVars) and it is
56 therefore not possible to use PAM style variables such as
57 `@{HOME}`.
58 '';
59 };
60
61 };
62
63 config = {
64 environment.etc."pam/environment".text = let
65 suffixedVariables =
66 flip mapAttrs cfg.profileRelativeSessionVariables (envVar: suffixes:
67 flip concatMap cfg.profiles (profile:
68 map (suffix: "${profile}${suffix}") suffixes
69 )
70 );
71
72 # We're trying to use the same syntax for PAM variables and env variables.
73 # That means we need to map the env variables that people might use to their
74 # equivalent PAM variable.
75 replaceEnvVars = replaceStrings ["$HOME" "$USER"] ["@{HOME}" "@{PAM_USER}"];
76
77 pamVariable = n: v:
78 ''${n} DEFAULT="${concatStringsSep ":" (map replaceEnvVars (toList v))}"'';
79
80 pamVariables =
81 concatStringsSep "\n"
82 (mapAttrsToList pamVariable
83 (zipAttrsWith (n: concatLists)
84 [
85 # Make sure security wrappers are prioritized without polluting
86 # shell environments with an extra entry. Sessions which depend on
87 # pam for its environment will otherwise have eg. broken sudo. In
88 # particular Gnome Shell sometimes fails to source a proper
89 # environment from a shell.
90 { PATH = [ config.security.wrapperDir ]; }
91
92 (mapAttrs (n: toList) cfg.sessionVariables)
93 suffixedVariables
94 ]));
95 in ''
96 ${pamVariables}
97 '';
98 };
99
100}