Home / Alt manpages / pam_env(8)

  • pam_env(8)
  • Admin command
  • linux

Set Login Environment Variables Safely with pam_env

You will configure a system-wide environment variable for PAM sessions, understand which file supplies it, and check that the relevant PAM service actually invokes pam_env. The examples use Linux-PAM 1.5.3, installed here as Debian package libpam-modules:amd64 version 1.5.3-5ubuntu5.7.

Allow about fifteen minutes. You need root access to change system configuration and a second login or session in which to test it. This guide changes the environment inherited by PAM-managed sessions. Keep an existing root shell open while editing authentication configuration, and do not use a personal environment file as a way to bypass an administrator's policy.

1. Check how the target service calls pam_env

pam_env is a PAM module, not a shell command that changes the current terminal. It provides auth and session module types, and the local services commonly call it in their session stack. Inspect the service you care about, such as SSH:

grep -n 'pam_env' /etc/pam.d/sshd
ls -l /lib/x86_64-linux-gnu/security/pam_env.so

On this machine, SSH calls the module once with the default files and again with envfile=/etc/default/locale. That matters: a setting can be read more than once, and a service can use a different environment file from the default. The module manual says it should be last on the PAM stack because the variables it sets can affect later modules.

Checkpoint

Record the exact service file and every pam_env.so line it contains. Do not add a second line merely because a variable did not appear in your current shell.

2. Choose the right input file

The module reads up to three sources in order. First it reads /etc/security/pam_env.conf, whose rules have a variable name followed by optional DEFAULT= and OVERRIDE= values. Next it reads simple KEY=VALUE pairs from /etc/environment. Finally it can read $HOME/.pam_environment, but user_readenv is off by default and deprecated since Linux-PAM 1.5.0.

Use pam_env.conf when a default should apply only if the variable is not already present, or when you need PAM substitutions. Use /etc/environment for a plain system-wide pair. Do not put shell commands, command substitutions or shell syntax into either file. The environment file accepts one pair per line; an export word is tolerated for Bash compatibility but ignored.

For this example, set a default pager in the administrator-controlled rules file. First make a recoverable backup, then append one rule:

sudo cp -a /etc/security/pam_env.conf /etc/security/pam_env.conf.bak
sudo sh -c 'printf "%s\n" "PAGER DEFAULT=less" >> /etc/security/pam_env.conf'

The rule supplies less when PAGER is absent. It does not overwrite an existing value because there is no OVERRIDE clause. Check the saved line before opening a new session:

tail -n 3 /etc/security/pam_env.conf

Recovery

If the line is wrong, remove only that exact new line with a root editor, or restore the backup after reviewing any changes made by other administrators. Do not blindly restore an old copy if the file was already being maintained.

3. Use substitutions only when their source is reliable

Values in pam_env.conf can use ${NAME} for an already-set environment variable and @{NAME} for a PAM item. The special @{HOME} and @{SHELL} values come from the user's passwd entry. This distinction prevents a common trap: ${HOME} may not exist yet when a PAM application calls the module, while @{HOME} is the account value described by the manual.

For a per-user data directory based on the account database, an administrator could use:

XDG_DATA_HOME DEFAULT=@{HOME}/share/

Keep values quoted when they contain spaces, and remember that an escaped dollar or at-sign is literal. A literal quote cannot be escaped according to the configuration manual, so choose a value that does not need one. A line beginning with # at column one is a comment; do not rely on an indented comment being treated the same way.

4. Test from a fresh PAM session

Existing processes do not receive an environment update when a configuration file changes. Start a fresh session through the service you inspected. For SSH, open a separate terminal and connect as the intended account:

ssh USERNAME@HOSTNAME 'printf "%s\n" "$PAGER"'

Replace both placeholders with real values. The expected output for the rule above is:

less

Run the check in the same kind of session that will consume the variable. A local login, sudo, a cron job and an SSH session can use different PAM service files and therefore different module arguments. If the output is empty, inspect the service's pam_env.so lines, the spelling and spacing of the rule, and whether another earlier source already sets PAGER. If the value is unexpectedly different, check every envfile= occurrence rather than assuming /etc/environment was used.

5. Treat user environment files as a security boundary

The optional user_readenv=1 setting reads a user-specific file, with the default path $HOME/.pam_environment. The manual marks this feature deprecated because user-supplied PAM variables can affect later modules without the administrator's consent. Leave it disabled unless you have a documented compatibility requirement, understand the whole PAM stack, and have a rollback plan.

If a service currently enables it, record that fact and look for the controlling line:

rg -n 'pam_env|user_readenv' /etc/pam.d

Removing or changing a PAM line can disrupt logins, so treat that as a maintenance-window change. Make a backup of the specific service file, keep an existing privileged session open, test a new session, and restore the prior line if authentication or session setup fails.

Done means

  • The target PAM service and its pam_env.so arguments are recorded.
  • The variable is in the intended source file, with a clear choice between DEFAULT and OVERRIDE.
  • A fresh, relevant PAM session shows the expected value.
  • User configuration reading remains disabled unless a reviewed exception requires it.
  • The backup and recovery path are known before any PAM stack edit.