[Chapter 2] 2.16 Approved Shells: Using Unapproved Login Shell
Author: Jerry Peek, Tim O'Reilly & Mike Loukides
Date: 1998-08-04T21:32:22Z

#

| Chapter 2 Logging In |

## 2.16 Approved Shells: Using Unapproved Login Shell

Since 4.2BSD, Berkeley UNIX systems have restricted chsh (or a command like it) to change your login shell only to a shell that's listed in the file /etc/shells. That's partly a safety feature, like requiring you to type your old password before you can change to a new one: it keeps other people from giving you a strange login shell as a joke. It's also for security - a way for the system administrator to give a list of shells that are robust enough to run peoples' accounts.

The usual "approved" shells are the Bourne and C shells. If you want to use another shell as your login shell and your system has /etc/shells, ask the system administrator to add your shell. The shell will need to be stored in a secure system directory to make it harder for system crackers to corrupt the shell.

If the system administrator won't approve your login shell, here's a work-around. It lets you log in with an approved shell, then automatically replace the shell with whatever you want. (For background, see article 51.9.)

1. If your login shell isn't C shell, use chsh or a command like it to change it to the C shell.

2. If your new shell will be bash, you can skip this step. Otherwise:

   In your home directory, make a hard or symbolic link (18.4)directory, to your shell. Use a name starting with a minus sign (`-`); this makes the shell act like a login shell (51.9). For example, to make a symbolic link in your home directory named -ksh to the shell /usr/local/bin/ksh, type this command:

       ./
       % ln -s /usr/local/bin/ksh ./-ksh

3. Add lines to the top of the .cshrc (2.2) file that replace the csh process with your login shell. (The exec (45.7) command replaces a process.)

   - If you use a Bourne-type shell that reads the .profile file at login time, use lines like these:

         TERM
         su
         if $?
         # OVERRIDE DEFAULT LOGIN C SHELL TO USE ksh.
         setenv SHELL /usr/local/bin/ksh
         # IF $TERM SET (BY login OR rlogin), START LOGIN SHELL.
         # UNFORTUNATELY, THIS MAKES su USE A LOGIN SHELL TOO.
         if ($?TERM) then
            cd
            exec -ksh   # USE "LOGIN SHELL" SYMLINK IN $HOME
         else
            exec $SHELL
         endif
         echo "******** WARNING: exec ksh FAILED ********"

     If your new login shell will be bash, you can replace the line `exec -ksh` above with:

     >     exec $SHELL -login

     because bash has a -login option that tells it to act like a login shell. Simple, eh?

   - If your new login shell is a csh-type shell that also reads .cshrc, you need to add a test to .cshrc that prevents an infinite loop. This test uses the SH_EXECD environment variable (6.1) as a flag:

     >     # OVERRIDE DEFAULT LOGIN C SHELL TO USE tcsh.
     >     if (! $?SH_EXECD) then
     >        setenv SH_EXECD yes
     >        setenv SHELL /usr/local/bin/tcsh
     >        # IF $TERM SET (BY login OR rlogin), START LOGIN SHELL.
     >        # USE switch, NOT if, DUE TO csh BUG WITH IMBEDDED else.
     >        # UNFORTUNATELY, THIS MAKES su USE A LOGIN SHELL TOO.
     >        switch ($?TERM)
     >        case 1:
     >           cd
     >           exec -tcsh    # USE "LOGIN SHELL" SYMLINK IN $HOME
     >           breaksw
     >        default:
     >           exec $SHELL   # USE NON-LOGIN SHELL
     >           breaksw
     >        endsw
     >        echo "******** WARNING: exec tcsh FAILED ********"
     >     endif

   - The C shell may not find your new shell (`-ksh` or `-tcsh`) unless you have the current directory (`.`) in your search path (8.7) (put it at the end of your path!). You may also be able to use an absolute pathname (14.2) to the new shell, but that could hide the leading minus sign (`-`) and the shell might not act like a login shell.

   - Is there a chance that your new shell might be missing some day? For instance, is it on a network filesystem that might be unavailable? Then it's a good idea to wrap the new code above with a test:

         -e
         if (-e my-new-shell) then
             ...code to start new shell...
         else
             echo "*** WARNING: new shell failed.  Using csh. ***"
         endif

4. Test your new setup:

   - Try commands that start subshells (38.4), like su, rsh, and so on (2.7), to be sure that they start your new shell.

   - Put the csh command set echo (8.17) at the top of your .cshrc file to be sure your commands there are working.

   - Type a command that will work only in your new shell (not in a C shell).

   - Use the ps (38.5) command `ps` `$$` (on System V, `ps` `-f` `-p` `$$`) to look at your new shell process (`$$` is your shell's process ID number (38.3)).

   - Before you log out of this shell, try logging in from somewhere else (2.4) to be sure your new shell startup files work.

5. You're set to go.

If your login shell isn't listed in /etc/shells, the ftp (52.7) program (actually, the ftpd daemon (1.14)) may refuse to transfer files to your account. That's partly to stop ftp access to your system through special accounts that don't have passwords, like sync, who, finger, and so on. If you use the workaround steps above, though, that shouldn't be a problem; you'll have an approved shell listed in /etc/passwd and ftp usually doesn't run your login shell, anyway.

- JP

2.15 Unclutter Logins: Show Login Messages Just Once |  | 3. Logging Out