I struggle to see the difference between pam_env.conf and /etc/environment. To me they both do the same thing, with a difference syntax. The manpages were no help. So what is the difference?

Additionally, I'd like to find a way to add paths to the PATH environment variable for all users. Adding them to the two aforementioned files works for all users, but doesn't work with sudo, as can be verified by running sudo sh -c 'echo $PATH'.

To solve that problem, I believe I should edit the file /etc/pam.d/sudo, but what should I put in there?


There are 2 fundamental differences between /etc/security/pam_env.conf and /etc/environment.

  1. The order in which PAM processes them.

    /etc/environment is parsed first, but anything defined here is overridden by definitions for those same variables if they also exist in pam_env.conf. However, it's possible to subsume + extend the variables from /etc/environment in /etc/security/pam_env.conf, e.g.:

    PATH   DEFAULT=${PATH}:/usr/sbin
  2. Variable expansion

    a. /etc/environment is not a script, but a set of assignment expressions, i.e. ${PATH} is not expanded, but used literally.

    b. /etc/security/pam_env.conf is a different animal altogether. It's not a script per se; it's still just a set of KEY=VALUE assignments, but PAM can expand existing variables (ex: ${PATH}, ${DISPLAY}) and other PAM_ITEMs (ex: @{PAM_SERVICE}, @{PAM_USER}, etc.). Take special note of $ vs @ here.

    PAM also handles the special variables @{HOME} and @{SHELL}, which expand to whatever is defined in /etc/passwd. *Note: in most PAM applications, the traditional variables ${HOME} and ${SHELL} (compare @ vs $) are not available this early in PAM's flow.

    Using the example given in the comments of /etc/security/pam_env.conf, this replacing/expanding behavior can be used to modify the DISPLAY variable for remote login sessions.

    REMOTE_HOST     DEFAULT=localhost           OVERRIDE=@{PAM_RHOST}

To the specific problem you described here, the values you configured in /etc/environment weren't available in the sudo temporary environment because the session facility given by the PAM application definition for /etc/pam.d/sudo never calls pam_env.so for sessions.

In /etc/pam.d/sudo, sessions only import the rules from /etc/pam.d/system-auth. Following the trail, in /etc/pam.d/system-auth, the session stack doesn't have an entry for pam_env.so.

There are a few ways to customize the variables available in a sudo environment.

If you need some custom set of environment variables that only exist in sudo-land, it's fairly straightforward.

  1. Create a file to contain your exclusive-to-sudo environment variables.

    GREET   DEFAULT="hello from sudo land"
    VAR1    DEFAULT="${GREET}"
    _VAR2   DEFAULT="VAR2 not passed to sudo, ...but"
    VAR2    DEFAULT="${_VAR2} ${GREET}"                 OVERRIDE=${VAR2}
    VAR3    DEFAULT="Nope. Unknown users cannot sudo."  OVERRIDE=@{PAM_RUSER}
  2. Make a copy of /etc/pam.d/system-auth, rename it along the lines of /etc/pam.d/sudo-environment, and add a directive to the bottom of the session stack:

    session     required    pam_unix.so
    session     optional    pam_permit.so
    # Add a line for using pam_env.so
    session     optional    pam_env.so conffile=/etc/security/sudo_custom_vars.conf

    If you want pass variables from the non-sudo environment, include the user_readenv=1 flag

    session     optional    pam_env.so      conffile=/etc/security/sudo_custom_vars.conf    user_readenv=1
  3. In the PAM application definition /etc/pam.d/sudo, make the replacement:

    -   session    include       system-auth
    +   session    include       sudo-environment
  4. Open a new terminal to test

    $ su <your username>                    # Testing PAM without logging out
    $ export VAR1=""
    $ export VAR2="hello from down here"    # Set var in non-sudo environment
    $ echo $VAR1
    $ sudo sh -c 'echo $VAR1'               # Test sudo's DEFAULT value
    hello from sudo land
    $ echo $VAR2
    hello from down here
    $ sudo sh -c 'echo $VAR2'               # VAR2 not passed to sudo
    VAR2 not passed to sudo, ...but hello from sudo land
    $ sudo -E su -c 'echo $VAR2'            # VAR2 (and everything else) passed to sudo
    hello from down here
    $ sudo env VAR2="inline override" su -c 'echo $VAR2'
    inline override
    $ sudo sh -c 'echo $VAR3'               # Testing we can read a PAM_ITEM

An alternative to tinkering around with the PAM modules is to edit /etc/sudoers with # visudo, as you did. I realize this is an old question and way-back-when, commenting Default env_reset was the the thing to do.

Moving forward, the accepted best practice when using sudoers to pull in variable definitions from the environment is to append the variables to env_keep. (...that is, unless you need a unique set of variables as shown above)

    Defaults env_keep += "var1 var2, etc..."
| improve this answer | |

I managed to get more or less what I wanted for sudo:

I edited the /etc/sudoers file (with sudo visudo) and commented out the lines Default env_reset and Default secure_path = ....

Now sudo will use the user's environment.

The difference between pam_env.conf and /etc/environmentstill isn't clear to me tough, so the question is not yet answered.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.