18 December 2007

The bash problem

If you use bash as a login shell you might have had the problem of it getting broken and then being unable to login. Now that's a problem! I've burnt myself on this a couple of times. But, in both cases it was not a big deal to fix. (In one case, though, I was locked out over the weekend until I could get to the box.) This is more of a problem in some operating systems (like FreeBSD) where bash is not part of the base system. In that respect, it's a risk worth having because of FreeBSD's great separation of the base system and third party software -- and the ability to easily update that software. And, bash is just a great shell.

As long as you've got console, it's easy enough to fix. You can just drop into (or boot to) single user mode and then run 'chsh [<username>]'. If you don't have console and all of your network enabled user accounts use bash you've got a real problem.

So, how to prevent this once and for all? I've got several suggestions. 1) Have a back-up account that uses a shell from the base system. This is simple and effective. But, having to remember another user name and having to remember and/or update another password is not ideal. 2) Use a 'toor'-like system on your own user account. This is interesting. I tested this out and it works alright. Just reverse your username (e.g., 'kace' -> 'ecak'), create that account, then use 'vipw' to change the uid on that account to your original uid and the home directory to your home directory. But, make this other username use a base system shell. This is really nearly the same as solution 1), except you'll not need to remember a new user name.

Finally, the one I like best: no new account, no second password: 3) Change your login shell to '/bin/csh' then add this code to the ".login" file in your home directory:

if ( { bash -c 'echo blah > /dev/null' } ) then
    exec bash -l
else
    echo '=== bash broken ==='
endif

This simply tests bash every time you login and then replaces csh with a bash login shell as long as it's working. Simple and effective. It may seem like too much overhead, but it's not really. This isn't some system task that will be repeated hundreds of times a day. You don't actually login that much. The small cost in computer time of running csh and then bash and then finally bash once more is a trifle in comparison to the human time that this measure may one day save you.

I first tested and implemented this solution with '/bin/sh' and it worked, though the code is slightly different and it goes into the ".profile" file. But, upon reflection that's a bad idea. 'sh' is a little faster than 'csh', but using 'sh' requires that you have a ".bash_profile" or a ".bash_login" file in your home directory. If you don't, or something happens to them, then bash will read ".profile" and you'll be in a loop, re-executing bash over and over. Ack! Let's just solve the problem instead of creating new, more interesting ones. :)

Update:

If you want to run any tests on these ideas, you may want to "break" bash or create and assign yourself a broken shell. (Be careful! Don't lock yourself out! Test on a box that you have console access to until you are satisfied.) One quick and easy way to break bash is this: "chmod -x /usr/local/bin/bash" (or your path to bash). On the other hand, the system seems to handle a non-executable shell slightly differently from a broken shell. For testing purposes it's broken enough I think. :) But, if you want to be a stickler, a more realistic way to emulate a broken shell might be to assign yourself as a login shell a utility that always returns a non-zero exit status, perhaps '/usr/bin/false'. (And, you'll have to put it in '/etc/shells/ first.) ... In particular, something like "ssh problem-box '/bin/sh' " may seem to work while your login shell is not broken, but, in fact, the command '/bin/sh' is being passed to your login shell, and if it's broken that won't work.

Labels:

3 Comments:

At 20/12/07 14:02, Anonymous Anonymous said...

If you have an ssh daemon running on the broken computer and can reach that via net, you can also try (from remote computer) "ssh mycomputer -t '/bin/sh'", and then fix the problem with bash.

 
At 22/5/09 20:44, Anonymous Anonymous said...

well, you're not alone. I've managed to lock myself out of my server with a broken bash shell. Have tried everything I can think of to fix it without success. I have ssh access using another account but no root access. Will give your script a try but will also be putting in another su-enabled account as a precaution. Meanwhile, I need to make an unscheduled trip to the office on a saturday morning... bah

 
At 20/10/10 12:11, Anonymous Anonymous said...

If you use "sudo -s" as I often do, you will need to add this to your .bashrc or .bash_profile

export SHELL=/usr/local/bin/bash

This way when sudo runs your prefered shell, you won' be back in csh again.

 

Post a Comment

<< Home