36

We used to use /etc/environment to set system-wide environment variables on Mountain Lion. However, it seems this file is no longer read.

Ideally the solution should apply to all users, and we need it to work with ssh console sessions. So we need this to work

ssh user@mavericks-machine 'echo $MY_ENV_VAR'

So far we've tried:

  • /etc/launchd.conf

    Works for all users, but only applies to 'windowed' applications, i.e. works in Terminal, but not in an ssh session.

  • ~/.profile, ~/.bash_profile etc.

    Only applies to shells

Any suggestions?

  • The file (/etc/environment) is not read because it is not any cross-system standard - it is just part of Linux PAM facility. Mac OS X is not Linux and does not use PAM, nor do other operating systems to my knowledge. You only got away with it because you were on Linux, apparently. And yes, it is still read - by Linux ;-) – amn Jun 29 '15 at 17:46
17

The correct file, prior to Mavericks, was ~/.MacOSX/environment.plist. This is no longer supported.

In Darwin, and therefore in Mac OS X, the proper place to set these is in /etc/launchd.conf to apply to all processes; if relating to user shells specifically, use the appropriate shell files instead, depending on the shell in question. See the launchd.conf and launchctl man pages for more.

That said...

If you're goal is specifically to see these applied for ssh sessions then you need to be aware that ssh, for security reasons, doesn't apply environment variables in this manner. In fact a ssh session normally receives a much more restrictive set of environment variables from the OS as it's not what is known as a "login" or "interactive" shell, it's classified as an "non-interactive" shell. (See man bash for more on shell types.) The way ssh handles environment variables is well covered in the ssh/sshd docs and man pages.

For ssh -- which is it's own shell, akin to bash -- environment variables for the session are stored in ~/.ssh/environment as the per-user equivalent of setting these for bash or csh, etc in their relevant launch files. This is probably where you want to set your ENV variables for your user ssh sessions, though you don't detail why you're looking to assign ENVs globally in your original post, which would have been helpful in providing a solution. I'd suggest you set them explicitly on a user per user basis to maintain proper security based on each respective account following the least restrictive privilege/attribute best practice.

If for some reason you wish to ignore he security implications of this, then set PermitUserEnvironment in your ssh configs. Note that this is disabled if UseLogin is enabled. IMPORTANT: Realize that this means that user accounts set to use /bin/false as their shell - the typical method for disabling a user account - can now potentially get around this restriction and could now become active, which is dangerous. Many accounts are set to use /bin/false as their shell as a security expectation.

Bottom line is you shouldn't be doing this globally and expecting ssh to propagate ENV for security reasons. Your question is, effectively, purposely asking how to defeat several mechanisms that exist for security reasons.

  • very detailed answer (+10) I like the conclusion as well :) Welcome! – Ruskes Mar 20 '14 at 23:17
  • I would suggest that with the security caveat, there may indeed be valid reasons to do this. It all depends on your threat model. If you're setting up a group of test automation machines, it might make sense to do this. – uchuugaka Apr 18 '16 at 2:50
  • 2
    According to stackoverflow.com/a/26311753/1081043, /etc/launchd.conf no longer works as of OSX 10.10 Yosemite. – wisbucky Apr 19 '16 at 20:45
10

If you are using bash, then setting the environment variables in /etc/profile will apply for all users.

From the bash manual on OS X Mavericks, with my emphasis (this has not changed from previous versions):

When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.
...
If bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well. When invoked as an inter-active interactive active login shell, or a non-interactive shell with the --login option, it first attempts to read and execute commands from /etc/profile and ~/.profile, in that order.

5

What you (and anyone else finding this question) are almost certainly looking for is the following path:

/private/etc/paths

You can always put your edits into the /private/etc/paths.d if you want to avoid changing the main system default "paths" configuration document, but then they will be appended to the end of your $PATH variable, so if you want to add directories at the front of $PATH (to override default system utilities, for example), you'll just have to edit the main /private/etc/paths file itself and add those to the top of the list. For example, I do this for a folder in which I store a handful of scripts I made myself, along with a few key utilities, such as mozjpeg, that I want the system to always use instead of the defaults it comes with (that way all the jpeg files saved by pretty much any program get automatically compressed by up to 10 % more than the regular system cjpeg utility would compress them - I've read that the reason it isn't default on most systems is because it's much slower, but when you're talking something like 0.14 seconds as opposed to 0.02 seconds, the "slower by a factor of 7" doesn't really mean much of anything... assuming this is not a server, of course). I know plenty of people will probably warn about the potential "danger" of making edits this deeply in the system, but I'd say that if you're looking for an answer like this, you probably know enough to deal with any utility naming conflicts that may potentially arise in the future, and simply making your changes in /private/etc/paths really does propagate them to all users/logins/instances possible - all programs, shells, etc will use the paths in that file to build the base of their $PATH variable.

To be honest, I'm quite surprised no one else here mentioned this yet. All that messing around with launchd and distractions about SSH-specific uses... this is the solution anyone searching for this basic issue is really looking for - the clean, straight-to-the-source, always-working solution.

By the way, in case you're wondering, on OS X /etc is simply a symlink to /private/etc, so you could just as easily do sudo nano /etc/paths and get to the same exact place. The above path is just the complete actual path of the file.

  • 2
    Unless I'm missing something, that will set only one system-wide environment variable - $PATH. The OP seems to be looking for a generic solution - setting any env var, system-wide, e.g. $EDITOR, etc. – John N Mar 5 '17 at 8:52
  • Even with the sudo command, in macOS Sierra, I get permission denied if I try to create, using echo a new file in /private/etc/paths.d containing an addition to the path. But it works to first create the file, then use sudo mv to move the file to /private/etc/paths.d. – murray Sep 25 '17 at 19:12
  • This helped. Other directories were getting prepended to my PATH despite setting $PATH in my ~/.zshrc... the culprit was indeed /private/etc/paths and I had to update this file. Thanks. – nonbeing Jun 20 at 9:55
1

I had a similar problem, specifically ~/.bashrc wasn't being sourced when I connected to my machine via SSH. I found that changing a configuration setting for SSHd did the trick. Perhaps your problem also lies with the SSH daemon?

Modify the SSH service's configuration file as follows:

# /etc/sshd_config
PermitUserEnvironment yes

Then restart the Remote Login service in System Preferences > Sharing.

From the sshd_config manpage:

 PermitUserEnvironment
         Specifies whether ~/.ssh/environment and environment= options in
         ~/.ssh/authorized_keys are processed by sshd(8).  The default is
         ``no''.  Enabling environment processing may enable users to
         bypass access restrictions in some configurations using mecha-
         nisms such as LD_PRELOAD.

(In case it helps, I've written up how I tested this on my personal wiki)

1

If others search for how to set environment variables for processes started from a normal graphical login session, you can use /etc/launchd.conf. To for example add /usr/local/bin to the default path, run

echo setenv PATH /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin|sudo tee -a /etc/launchd.conf

and restart to apply the changes. Another way to apply the changes is to run launchctl</etc/launchd.conf;sudo launchctl</etc/launchd.conf and relaunch processes.

  • /etc/launchd.conf is no longer used in launchd at all. – uchuugaka Apr 18 '16 at 3:43
  • 2
    /etc/launchd.conf is no longer supported since OSX 10.10 Yosemite – wisbucky Apr 19 '16 at 20:46
0

Hmm... As of Mac OS X 10.10.5 and probably earlier, man -s5 launchd.conf tells us: "launchd.conf is no longer respected by the system." I have too much stuff going on right now to put a dummy variable in the file and restart to see if it really does work or not after all, but the documentation says it should not work.

I'm pretty sure it won't. Do man launchctl and you'll see: "The /etc/launchd.conf file is no longer consulted for subcommands to run during early boot time; this functionality was removed for security considerations."

What you can do is put all the environment variables you want to be global-ish into some file, perhaps called environment in keeping with Linux, or (in case Apple decides to do something with that later – you never know) environment.conf, like I did, then source this via /etc/profile:

if [ -f /etc/environment.conf ]; then
   source /etc/environment.conf
fi

or, if you prefer the compact format:

if [ -f /etc/environment.conf ]; then . /etc/environment.conf; fi

If you use some other shell than bash, and it uses the same variable-setting syntax as bash (as does zsh, I think), you'll need to also source this file from that shell's system-wide rc file (e.g. /etc/zshrc). If you use a shell that uses a different syntax, e.g. tcsh, you'll need to either maintain a similar file for that shell and source it from the shell's system-wide rc file (e.g. /etc/csh.cshrc for tcsh), or better yet create a script that auto-generates it, so you only have to edit one file to add/change variables. This isn't the place for such a tutorial; a few seconds on Google turned up how to convert [t]csh variable exports to bash syntax, at https://stackoverflow.com/questions/2710790/how-to-source-a-csh-script-in-bash-to-set-the-enviroment, so there's probably something available to go the other direction.

It's been my experience that Mac OS X is moving further and further away from predictable rc file behavior. As of at least 10.8, it no longer seems to load /etc/rc.common, /etc/rc.conf or /etc/rc.<anything>, nor (since at least 10.9) will it load /etc/bash.bashrc for interactive nonlogin shells (which it certainly should be doing, just like it loads ~/.bashrc for them, still, as of 10.10). Then again I have Fink, MacPorts, and Homebrew all installing stuff, so maybe one of them is interfering with default dotfile behavior. YMMV.

  • Question is for earlier OS X there will be other e.g. apple.stackexchange.com/questions/215932/… for later – Mark Nov 17 '15 at 20:07
  • My post addressed both Mavericks (10.9) in part and 10.10 in part. If your point is that 10.10 is a verboten topic entirely in a thread about 10.9, I'm not sure why you directed me to a 10.11 thread, where 10.10 would also be off-topic (if the thread in question weren't invalid and closed anyway). LOL. – S. McCandlish Mar 6 '16 at 11:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .