cd ~{,/zhs/}

Set Environment Variables with pam_env

Warning: Upstream totally deprecated user level configuration, this article is reserved only for reference.

I hate pam_env, its official documentation isn’t consistent with actual behavior, and oldest code is even older than me.

For now I set my environment variables using fish (my login shell), and use startx startplasma-x11 to startup KDE. Refer to my fish configurations.

Pros

It’s a PAM module and sets environment variables as soon as user logs in.

Bash, zsh or fish; Wayland or Xorg; no need to bother understanding their environment scopes, not as global as pam_env anyway.

Cons

Configuration Files

pam_env reads these three files below in turn:

User-Level Configuration

Since PAM v1.4.0, pam_env module doesn’t read user-level configuration file by default. To enable user-level config, one has to be administrator to append argument in system-level config of PAM.

Run grep pam_env.so /etc/pam.{conf,d/*} to see all the references of pam_env module, file results depend on distros and personal use case.

On Gentoo and Arch Linux it’s /etc/pam.d/system-login to be altered, go to the session required pam_env.so line and append argument user_readenv=1.

(Note for Arch Linux users: pambase package of [has already done the work][pambase_commit] above.)

[pambase_commit]: https://github.com/archlinux/svntogit-packages/commit/2d5af94ae55a5c98837ce9631f331ad2aad32bb3#diff-02a81ec7974f6d6a00a87a0d9ce507b6R19 “Remove options not supported by faillock, Drop sha512 option to pam_u… · archlinux/svntogit-packages@2d5af94 · GitHub”

Additionally, to custom file path instead of default ~/.pam_environment, append argument user_envfile=path, in which the path is relative to every user’s home.

The altered line may look like:

session    required    pam_env.so user_readenv=1 user_envfile=.config/pam_env.conf

Configuration Syntax

VARIABLE_NAME [DEFAULT=[value]] [OVERRIDE=[value]]

For quick and simplest usage: VARIABLE_NAME DEFAULT=value usually works like bash command export VARIABLE_NAME=value.

Priority Mechanism

  1. Override value if provided and expanded to non-empty string;
  2. Undefined (deleted) if literally DEFAULT= provided;
  3. Default value including empty string expanded or provided with "".

Expanding

For defined values:

Special variables @{HOME} and @{SHELL} are expanded to values for user according to its record in user database, which is /etc/passwd file in most cases.

Escaping

Examples

(These examples are from Dave Kinchlea, original author of pam_env module.)

Set the REMOTEHOST variable for any hosts that are remote, default to “localhost” rather than not being set at all:

REMOTEHOST    DEFAULT=localhost    OVERRIDE=@{PAM_RHOST}

Set the DISPLAY variable if it seems reasonable:

DISPLAY    DEFAULT=${REMOTEHOST}:0.0    OVERRIDE=${DISPLAY}

Now some simple variables:

PAGER       DEFAULT=less
MANPAGER    DEFAULT=less
LESS        DEFAULT="M q e h15 z23 b80"
NNTPSERVER  DEFAULT=localhost
PATH        DEFAULT=${HOME}/bin:/usr/local/bin:/bin\
:/usr/bin:/usr/local/bin/X11:/usr/bin/X11

Silly examples of escaped variables, just to show how they work:

DOLLAR          DEFAULT=\$
DOLLARDOLLAR    DEFAULT=    OVERRIDE=\$${DOLLAR}
DOLLARPLUS      DEFAULT=\${REMOTEHOST}${REMOTEHOST}
ATSIGN          DEFAULT=""  OVERRIDE=\@

References

Source Code

linux-pam/pam_env.c at v1.4.0 · linux-pam/linux-pam · GitHub

Documentation

Linux-PAM: 6.6. pam_env - set/unset environment variables

Arch Linux: Environment variables - ArchWiki

Ubuntu: EnvironmentVariables - Community Help Wiki