summaryrefslogtreecommitdiffstats
path: root/nixos/modules/config/system-environment.nix
blob: 96cd67d93d401a30bf0610403146183833c6e126 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# This module defines a system-wide environment that will be
# initialised by pam_env (that is, not only in shells).
{
  config,
  lib,
  options,
  pkgs,
  ...
}:
let

  cfg = config.environment;

  suffixedVariables = lib.flip lib.mapAttrs cfg.profileRelativeSessionVariables (
    envVar: suffixes:
    lib.flip lib.concatMap cfg.profiles (profile: map (suffix: "${profile}${suffix}") suffixes)
  );

  combinedSessionVars = lib.zipAttrsWith (n: lib.concatLists) [
    # Make sure security wrappers are prioritized without polluting
    # shell environments with an extra entry. Sessions which depend on
    # pam for its environment will otherwise have eg. broken sudo. In
    # particular Gnome Shell sometimes fails to source a proper
    # environment from a shell.
    { PATH = [ config.security.wrapperDir ]; }

    (lib.mapAttrs (n: lib.toList) cfg.sessionVariables)
    suffixedVariables
  ];

in

{

  options = {

    environment.sessionVariables = lib.mkOption {
      default = { };
      description = ''
        A set of environment variables used in the global environment.
        These variables will be set by PAM early in the login process.

        The value of each session variable can be either a string or a
        list of strings. The latter is concatenated, interspersed with
        colon characters.

        Setting a variable to `null` does nothing. You can override a
        variable set by another module to `null` to unset it.

        Note, due to limitations in the PAM format values may not
        contain the `"` character.

        Also, these variables are merged into
        [](#opt-environment.variables) and it is
        therefore not possible to use PAM style variables such as
        `@{HOME}`.
      '';
      inherit (options.environment.variables) type apply;
    };

    environment.profileRelativeSessionVariables = lib.mkOption {
      type = lib.types.attrsOf (lib.types.listOf lib.types.str);
      example = {
        PATH = [ "/bin" ];
        MANPATH = [
          "/man"
          "/share/man"
        ];
      };
      description = ''
        Attribute set of environment variable used in the global
        environment. These variables will be set by PAM early in the
        login process.

        Variable substitution is available as described in
        {manpage}`pam_env.conf(5)`.

        Each attribute maps to a list of relative paths. Each relative
        path is appended to the each profile of
        {option}`environment.profiles` to form the content of
        the corresponding environment variable.

        Also, these variables are merged into
        [](#opt-environment.profileRelativeEnvVars) and it is
        therefore not possible to use PAM style variables such as
        `@{HOME}`.
      '';
    };

  };

  config = {
    environment.etc."environment.d/50-systemd-path.conf".text = ''
      PATH="${lib.concatStringsSep ":" combinedSessionVars.PATH}"
    '';
    environment.etc."pam/environment".text =
      let
        # We're trying to use the same syntax for PAM variables and env variables.
        # That means we need to map the env variables that people might use to their
        # equivalent PAM variable.
        replaceEnvVars = lib.replaceStrings [ "$HOME" "$USER" ] [ "@{HOME}" "@{PAM_USER}" ];

        pamVariable =
          n: v: ''${n}   DEFAULT="${lib.concatStringsSep ":" (map replaceEnvVars (lib.toList v))}"'';

        pamVariables = lib.concatStringsSep "\n" (lib.mapAttrsToList pamVariable combinedSessionVars);
      in
      ''
        ${pamVariables}
      '';
  };

}