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 = lib.mdDoc ''
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 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 = lib.mdDoc ''
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 {manpage}`pam_env.conf(5)`.
49
50 Each attribute maps to a list of relative paths. Each relative
51 path is appended to the each profile of
52 {option}`environment.profiles` to form the content of
53 the corresponding environment variable.
54
55 Also, these variables are merged into
56 [](#opt-environment.profileRelativeEnvVars) and it is
57 therefore not possible to use PAM style variables such as
58 `@{HOME}`.
59 '';
60 };
61
62 };
63
64 config = {
65 environment.etc."pam/environment".text = let
66 suffixedVariables =
67 flip mapAttrs cfg.profileRelativeSessionVariables (envVar: suffixes:
68 flip concatMap cfg.profiles (profile:
69 map (suffix: "${profile}${suffix}") suffixes
70 )
71 );
72
73 # We're trying to use the same syntax for PAM variables and env variables.
74 # That means we need to map the env variables that people might use to their
75 # equivalent PAM variable.
76 replaceEnvVars = replaceStrings ["$HOME" "$USER"] ["@{HOME}" "@{PAM_USER}"];
77
78 pamVariable = n: v:
79 ''${n} DEFAULT="${concatStringsSep ":" (map replaceEnvVars (toList v))}"'';
80
81 pamVariables =
82 concatStringsSep "\n"
83 (mapAttrsToList pamVariable
84 (zipAttrsWith (n: concatLists)
85 [
86 # Make sure security wrappers are prioritized without polluting
87 # shell environments with an extra entry. Sessions which depend on
88 # pam for its environment will otherwise have eg. broken sudo. In
89 # particular Gnome Shell sometimes fails to source a proper
90 # environment from a shell.
91 { PATH = [ config.security.wrapperDir ]; }
92
93 (mapAttrs (n: toList) cfg.sessionVariables)
94 suffixedVariables
95 ]));
96 in ''
97 ${pamVariables}
98 '';
99 };
100
101}