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

  • Have you considered changing your LDAP shell to something more universal such as /bin/sh and then have your remote ~/.profile exec the appropriate shell if available?
    – RobertL
    Commented Dec 8, 2015 at 19:37
  • That would be an option, but not a very clean one, so I'd rather avoid it if possible.
    – Sascha
    Commented Dec 8, 2015 at 22:16

2 Answers 2


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

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

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

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

¹ 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
    Commented Dec 9, 2015 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
    Commented Oct 6, 2017 at 20:46

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. Commented Dec 8, 2015 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
    Commented Dec 8, 2015 at 21:32
  • 1
    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 Commented Dec 8, 2015 at 21:49
  • 1
    @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
    Commented Dec 8, 2015 at 22:09
  • @RuiFRibeiro redfast00's answer is plain wrong. nkms's is right. Commented Dec 8, 2015 at 23:31

You must log in to answer this question.

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