/bin/sh as a fallback login shell

Is there a reason why login(8) behaves so interesting?

I'm currently tabularasaing my server, reinstalling all applications, leaving out stalled dependencies and all that. Now I noticed that there is no fallback shell; if zsh is set as the login shell and it is (temporarily) removed, login(8) says "access denied" which is, in my opinion, not a good error message.

I'd propose an automatic fallback to /bin/sh if the set shell is invalid and/or not accessible.

edit: I just noticed that the "Feedback" forum is not meant for "FreeBSD feedback". Some moderator and/or administrator might want to move this where it belongs, sorry for the inconveniences.
 
How would the fallback work if the shell is set to /usr/sbin/nologin?
 
It's definitely for historical reasons and every UNIX like OS probably does the same thing. It's not a bad idea though but implementing it would require a thorough review of the login(8) process so that no security holes are introduced in the process. On another thought, login(8) is not used in ssh(1) connections is that right? This kind of fallback would probably belong in PAM I think.
 
There's no need for this. Mishaps like this can easily be fixed in single-user mode (whose shell defaults to /bin/sh). Another option is to not change you root's shell to something that requires 3rd-party libs (e.g. use a statically linked binary and copy it to /bin).
 
I think there would be too many exceptions and not all of the exceptions are known in advance (/usr/bin/false is another that would work). Which would make the system quite unpredictable. At least now it fails on very predictable occasions.
 
With no chance to fix it when it happens. No access to the shell means you can't even fix the mistake.
(Also, "access denied" is still not really helpful, is it?)
 
SirDice said:
How would the fallback work if the shell is set to /usr/sbin/nologin?
Login could simply stat(2) the user's shell and default to /bin/sh in case it does not exist. The real problem is that having such a fallback would change the default behavior from deny to allow.
 
worldi said:
SirDice said:
How would the fallback work if the shell is set to /usr/sbin/nologin?
Login could simply stat(2) the user's shell and default to /bin/sh in case it does not exist.
That doesn't solve the problem of bash not being able to open libc for example. The file exists, you just cannot execute it properly because some of the libraries it needs have gone missing. And checking the dependency chain each time a user logs in doesn't scale very well.
 
2c.

You can already do this - leave your shell set to /bin/sh and run /usr/local/bin/zsh from your .profile or the system's /etc/profile.

Yes, you will need to exit two shells to log out, but the alternative, having a fall-back shell for a non-existent shell specified in your account will break existing behaviour.

Presumably you are complaining about this because you locked yourself out of root by changing root's shell? If so maybe create/use a fallback account (such as toor) with the default /bin/sh.
 
Cthulhux said:
Is there a reason why login(8) behaves so interesting?

I'm currently tabularasaing my server, reinstalling all applications, leaving out stalled dependencies and all that. Now I noticed that there is no fallback shell; if zsh is set as the login shell and it is (temporarily) removed, login(8) says "access denied" which is, in my opinion, not a good error message.

I'd propose an automatic fallback to /bin/sh if the set shell is invalid and/or not accessible.

edit: I just noticed that the "Feedback" forum is not meant for "FreeBSD feedback". Some moderator and/or administrator might want to move this where it belongs, sorry for the inconveniences.

I actually think this is a very good idea and precisely the type of forward-thinking that is needed.
 
throAU said:
2c.

You can already do this - leave your shell set to /bin/sh and run /usr/local/bin/zsh from your .profile or the system's /etc/profile.

Yes, you will need to exit two shells to log out, but the alternative, having a fall-back shell for a non-existent shell specified in your account will break existing behaviour.
Start the other shell with exec. That will replace the running process (/bin/sh) with the new one (/usr/local/bin/zsh for example). Also note that zsh and bash will also execute ~/.profile. You don't want to start an infinite loop.
 
throAU said:
You can already do this - leave your shell set to /bin/sh and run /usr/local/bin/zsh from your .profile or the system's /etc/profile.
Nice, very clever. The use of exec should probably be reserved for statically linked binaries:

Code:
SHELL2="/usr/local/bin/zsh"
SHELL2_ARGS="-l"

get_shell_type() {
  if test -f "$1" -a -r "$1" -a -x "$1"
  then
    file "$1" | grep -q "dynamically linked" && echo 1
    file "$1" | grep -q  "statically linked" && echo 2
  fi
}

if [ "$SHELL" != "$SHELL2" ]
then
  case $(get_shell_type "$SHELL2") in
  1) SHELL="$SHELL2"      "$SHELL2" $SHELL2_ARGS;;
  2) SHELL="$SHELL2" exec "$SHELL2" $SHELL2_ARGS;;
  *) logger -s -t "WARNING" "cannot run $SHELL2, using $SHELL instead";;
  esac
fi
 
throAU said:
Presumably you are complaining about this because you locked yourself out of root by changing root's shell?

Almost, but only with one of two SSH processes, so I could avert worse things happening.
 
Next time you do a similar upgrade, make sure root's shell is default (/bin/csh) and set the shell for an admin account to /bin/tcsh. Also make sure your admin user is a member of the wheel group. Not only can 3rd party shells break after a major upgrade but also tools like sudo. With an admin account that's a member of wheel you should be able to login and use su(1) to become root.
 
Back
Top