8

I am currently working in a network that uses LDAP for authentication. Having set zsh as my login shell, I ran into a problem of gaining remote access through ssh to one of the machines on the network that, apparently, doesn't have zsh installed. The login fails with

Dec 8 19:16:11 abert sshd[20649]: User sorokine not allowed because shell /bin/zsh does not exist

So the question basically is: How can I tell the remote machine to use a different login shell than the one that was configured in LDAP?

OpenSSH_6.0p1 Debian-4+deb7u2, OpenSSL 1.0.1e

8

If your login shell can't be executed on some machine, then you can't log into it over SSH, or by most other methods for that matter. The SSH server always executes your login shell. If you pass a command on the ssh command line then the login shell is executed with -c and the command string¹ as arguments; otherwise the login shell is executed as a login shell with no argument.

If there was a way to bypass the login shell, that would be a security hole. An account can be configured as a restricted account by making its login shell a program that only performs one specific task; for example, the login shell could be git-shell to allow only access to a git repository, or rssh, etc.

To log in to that machine, you'll need to either arrange for /bin/zsh to be present, or change your login shell to something that is present.

What I recommend in a heterogeneous environment like this is to stick to /bin/sh as your login shell, because it's present everywhere. Set the SHELL environment variable to /bin/zsh if it's present, that way you'll get zsh as an interactive shell.

if [ -x /bin/zsh ]; then
  export SHELL=/bin/zsh
fi

While you're at it, this lets you avoid hard-coding the path to zsh.

if SHELL=$(command -v zsh); then
  export SHELL
else
  unset SHELL
fi

To get zsh to run automatically for a text mode login, invoke it from your .profile. If you want to use .zprofile to set things up, make it a login shell (but then you won't get the same environment on machines where zsh isn't present, so I don't recommend this). Do this only if this is an interactive login, not when your .profile is executed by a script, during GUI mode login, etc.

if case $- in *i*) true;; *) false;; esac &&  # interactive shell
   [ -z "$ZSH_VERSION" ] &&                   # not running zsh yet
   type zsh >/dev/null 2>/dev/null; then      # zsh is present
  exec zsh
fi

¹ The SSH client concatenates its non-option arguments with spaces in between, and sends the resulting string through the connection. The SSH protocols defines the command as a string, not a list of strings.

  • Thanks for the detailed explanation. Looks like it's the only way to go that doesn't involve installing zsh on the remote machine, and it works perfectly, so I'll stick to it. – Sascha Dec 9 '15 at 11:09
  • I also suggest to add a test [ "0$SHLVL" -lt 2 ] in case the default login shell supports $SHLVL so that bash -l or another shell can be run if need be (e.g. in case zsh fails for some reason). Thus ssh -t host bash -l would run a bash login shell without executing zsh behind. Also, I would replace exec zsh by exec zsh -l so that the .zlogin file is sourced. – vinc17 Oct 6 '17 at 20:46
1

You must ether install the shell on the specified machine if you have access in a different way or request it from an administrator to do this for you or change your shell in ldap to a shell that exists on the remote machine.

(open)sshd will always check for the user shell and it will always execute that shell whatever is passed to execute. If another shell is passed to execute it will execute it passing it as an argument to the user shell, for example the user shell is '/bin/sh' and you pass as an argument a csh shell than it will run "/bin/sh -c /bin/csh'.

  • Read redfast comment. openssh does allow you to bypass the default shell. – Rui F Ribeiro Dec 8 '15 at 21:07
  • @Rui F Ribeiro If it did it kind of takes away the logic behind setting the shell to something like '/bin/false' or '/sbin/nologin'. If you're referring to changing the shell after login than ok, but it does it like I wrote above (sh -c othersh), if there's no '/bin/sh' than you're out of luck. (Tested on Redhat). – nkms Dec 8 '15 at 21:32
  • True indeed, if passwd has a shell that is not listed in /etc/shells, you wont login anyway. But if you are able to login, and unless sshd_config does not force you to a particular shell, any command that the user is capable of runnng is fair game. If you do a couple more tests, for instance ssh -l user server "ps ax" | grep bash it is easy to notice the default shell is not always invoked. What it really prevents the other solution from working is the security check of zsh not being in /etc/shells – Rui F Ribeiro Dec 8 '15 at 21:49
  • @Rui F Ribeiro Run strace -f sshd on server side. You will see something like "execve("/bin/bash", ["bash", "-c", "ps"]..." Also, /sbin/nologin is a valid shell in /etc/shells. – nkms Dec 8 '15 at 22:09
  • @RuiFRibeiro redfast00's answer is plain wrong. nkms's is right. – Gilles 'SO- stop being evil' Dec 8 '15 at 23:31

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.