2

I am trying to setup svn over ssh on an OS X server. In order to do so, I read that I need a wrapper to set umask and - in my case - to set the repository root. A quick and dirty way to do that is to rename /usr/bin/svnserve and place a wrapper script at that location. However SIP protects that location from any changes, and I would prefer a cleaner solution anyway.

So I created a wrapper script at /usr/local/bin/svnserve and created /etc/ssh/sshrc with

PATH=/usr/local/bin:$PATH

I have verified that this file gets executed when initiating a remote ssh command from my client by writing to a log file. However, the modified PATH does not seem to get passed to the command environment:

ssh hostname 'echo $PATH'
Password:
/usr/bin:/bin:/usr/sbin:/sbin

Am I overlooking something? Or is /etc/ssh/sshrc the wrong place to set a path? If so, what's the right place?


Other places I've tried: /etc/profile and /etc/bashrc, but none of these seem to get executed in connection with an ssh command.

Note: It is not an option to change the client behavior (like, for example, adding the desired path to the command).

not2savvy
  • 2,902
  • 3
  • 22
  • 37
  • `ssh hostname echo $PATH` expands `$PATH` **before** it starts ssh. It's exactly the same output as just `echo $PATH` locally. To run the test you intended requires `ssh hostname 'echo $PATH'` (with the single quotes, specifically!) – Charles Duffy Mar 10 '17 at 18:27
  • Goodness! You are right! This changes my question completely to why the $PATH set in sshrc is obviously not propagated to the ssh command environment. Thanks, and I will change the questions accordingly. – not2savvy Mar 10 '17 at 18:31
  • Hmmm. I'd suggest starting by doing some logging in `sshrc`, to see if it's not running, or running and not having any effect (which could happen, for instance, if the `PATH` is overridden again later). `echo "In sshrc" >&2; PS4=':${BASH_SOURCE}:$LINENO+'; set -x` might be a place to start (whether the `BASH_SOURCE` expansion works will depend on whether your `/bin/sh` is provided by `bash`); that way further commands run by the shell will be logged -- just make sure that `>&2` is used for anything that would otherwise write to stdout. – Charles Duffy Mar 10 '17 at 20:13
  • By the way -- can you enable the `PermitUserEnvironment` option in `/etc/ssh` on the server? If so, you could set this in `~/.ssh/environment` for the target user (assuming, again, that nothing else is doing an override later). – Charles Duffy Mar 10 '17 at 20:26
  • (it's also possible that `sshrc` isn't guaranteed to run in the same shell instance that later runs the user-specified command; I'd need to investigate more to confirm that or rule it out -- but if it's the case, the `set -x` log from the above steps will terminate before the remotely-provided command is invoked, which will give us a pretty big clue that it's two different shell instances). – Charles Duffy Mar 10 '17 at 20:57
  • I did as described, and the set -x log indeed terminates before the actual command (for this purpose I used a test script) is executed. $PATH is set correctly in sshrc, but is obviously reset before entering the command script. – not2savvy Mar 10 '17 at 22:36
  • Excellent! I feel a little bad about writing up an answer incorporating something when you did the legwork to verify it, but that gives us fairly solid ground to stand on. Is `PermitUserEnvironment` a workable solution for you? – Charles Duffy Mar 10 '17 at 22:43
  • I have tried PermitUserEnvironment and added PATH to ~/.ssh/environment. This works! The PATH set here available in the command script. The drawback is that you cannot *add* a path because $PATH cannot be resolved. However, this is not a global but only a per-user solution. I have tried the same with /etc/environment, but the PATH set there does not make it into my command script for some reason. Any ideas? – not2savvy Mar 10 '17 at 22:49
  • On Linux, I'd be setting it up via the PAM module configuration. On OS X, on the other hand, I'm not as well-placed to make a suggestion... unless you'd consider it acceptable to configure the server to let `PATH` be passed through from the client. – Charles Duffy Mar 10 '17 at 22:56
  • ...actually... is this account used *only* for `svnserve`? You might just hardcode it only to ever run the command you specify, ignoring what the client requested. (In a past life, I actually wrote my own SSH server, based on the Paramiko library, for wrapping svnserve... but it did a whole lot of magic, most of which I no longer remember). – Charles Duffy Mar 10 '17 at 22:59
  • No, the accounts are not only for svnserve. I have seen solutions using the `ForceCommand` option which I think could be an alternative to creating a ~/.ssh/environment for every user. However, my original question can be answered now, I guess. – not2savvy Mar 10 '17 at 23:19

1 Answers1

2

/etc/sshrc does not run in the same shell instance with the remotely-issued command, so the PATH update does not persist through.

Some of the available options:

  • You can set AcceptEnv PATH on the server to configure it to accept a PATH sent by the remote system, and SendEnv PATH on the client (in ~/.ssh/config, or as an argument to ssh passed with -o, or in /etc/ssh/ssh_config).
  • In /etc/ssh/sshd_config on the server, you can set the option PermitUserEnvironment to yes; with that done, the variable and value can be added to ~/.ssh/environment in the individual user's account on the server.
  • You can use ForceCommand to override the remotely requested command, either with something like /usr/bin/env PATH=/usr/local/bin:/usr/bin:/bin svnserve or simply /usr/local/bin/svnserve
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • **Option 1** is not actually valid because it requires client side modifications which I had explicitly excluded in my question. **Option 2** could be used, but it requires to add `~/.ssh/environment` for each user which is not elegant. It was not possible to `/etc/environment` instead (may only be read at system start). I went for **option 3** because it gives me maximum flexibility. I use ForceCommand to execute a script that checks if an `svnserve` command has been sent. If so, the svnserve wrapper script is executed instead (passing on the original parameters). – not2savvy Mar 12 '17 at 14:42