Chapter 10. bash Administration

There are two areas in which system administrators use the shell as part of their job: setting up a generic environment for users and for system security. In this chapter, we’ll discuss bash’s features that relate to these tasks. We assume that you already know the basics of UNIX system administration.[1]

Installing bash as the Standard Shell

As a prelude to system-wide customization, we want to emphasize that bash can be installed as if it were the standard Bourne shell, /bin/sh. Indeed, some systems, such as Linux, come with bash installed instead of the Bourne shell.

If you want to do this with your system, you can just save the original Bourne shell to another filename (in case someone needs to use it) and either install bash as sh in the /bin directory, or better yet install bash in the /bin directory and create a symbolic link from /bin/sh to /bin/bash using the command ln -s /bin/bash /bin/sh. The reason we think that the second option is better is because bash changes its behavior slightly if started as sh, as we will see shortly.

As detailed in Appendix A, bash is backward-compatible with the Bourne shell, except that it doesn’t support ^ as a synonym for the pipe character (|). Unless you have an ancient UNIX system, or you have some very, very old shell scripts, you needn’t worry about this.

But if you want to be absolutely sure, simply search through all shell scripts in all directories in your PATH. An easy way to perform the search is to use the file command, which we saw in Chapter 5 and Chapter 9. file prints “executable shell script” when given the name of one.[2] Here is a script that looks for ^ in shell scripts in every directory in your PATH:

IFS=:
for d in $PATH; do
    echo checking $d:
    cd $d
    scripts=$(file * | grep 'shell script' | cut -d: -f1)
    for f in $scripts; do
        grep '^' $f /dev/null
    done
done

The first line of this script makes it possible to use $PATH as an item list in the for loop. For each directory, it cds there and finds all shell scripts by piping the file command into grep and then, to extract the filename only, into cut. Then for each shell script, it searches for the ^ character.[3]

If you run this script, you will probably find several occurrences of ^—but these carets should be used within regular expressions in grep, sed, or awk commands, not as pipe characters. As long as carets are never used as pipes, it is safe for you to install bash as /bin/sh.

As we mentioned earlier, if bash is started as sh (because the executable file has been renamed sh or there is a link from sh to bash) its startup behavior will change slightly to mimic the Bourne shell as closely as possible. For login shells it only attempts to read /etc/profile and ~/.profile, ignoring any other startup files like ~/.bash_profile. For interactive shells it won’t read the initialization file ~/.bashrc.[4]

POSIX Mode

Besides its native operating mode, bash can also be switched into POSIX mode. The POSIX (Portable Operating System Interface) standard, described in detail in Appendix A, defines guidelines for standardizing UNIX. One part of the POSIX standard covers shells.

bash is nearly 100% POSIX-compliant in its native mode. If you want strict POSIX adherence, you can either start bash with the —posix option, or set it from within the shell with set -o posix.

Only in very rare circumstances would you ever have to use POSIX mode. The differences, outlined in Appendix A, are small and are mostly concerned with the command lookup order and how functions are handled. Most bash users should be able to get through life without ever having to use this option.

Command-Line Options

bash has several command-line options that change the behavior of and pass information to the shell. The options fall into two sets: single character options, like we’ve seen in previous chapters of this book, and multicharacter options, which are a relatively recent improvement to UNIX utilities.[5] Table 10-1 lists all of the options.[6]

Table 10-1. bash command-line options

Option

Meaning

-c string

Commands are read from string, if present. Any arguments after string are interpreted as positional parameters, starting with $0.

-D

A list of all double-quoted strings preceded by $ is printed on the standard ouput. These are the strings that are subject to language translation when the current locale is not C or POSIX. This also turns on the -n option.

-i

Interactive shell. Ignores signals TERM, INT, and QUIT. With job control in effect, TTIN, TTOU, and TSTP are also ignored.

-l

Makes bash act as if invoked as a login shell.

-o option

Takes the same arguments as set -o.

-O, +O shopt-option

shopt-option is one of the shell options accepted by the shopt builtin. If shopt-option is present, -O sets the value of that option; +O unsets it. If shopt-option is not supplied, the names and values of the shell options accepted by shopt are printed on the standard output. If the invocation option is +O, the output is displayed in a format that may be reused as input.

-s

Reads commands from the standard input. If an argument is given to bash, this flag takes precedence (i.e., the argument won’t be treated as a script name and standard input will be read).

-r

Restricted shell. See the Section 10.3.1 later in this chapter.

-v

Prints shell input lines as they’re read.

-

Signals the end of options and disables further option processing. Any options after this are treated as filenames and arguments. is synonymous with -.

—debugger

Arranges for the debugger profile to be executed before the shell starts. Turns on extended debugging mode and shell function tracing.[7]

—dump-strings

Does the same as -D.

—dump-po-strings

Does the same as -D but the output is in the GNU gettext po (portable object) file format.

—help

Displays a usage message and exits.

—login

Makes bash act as if invoked as a login shell. Same as -l.

—noediting

Does not use the GNU readline library to read command lines if interactive.

—noprofile

Does not read the startup file /etc/profile or any of the personal initialization files.

—norc

Does not read the initialization file ~/.bashrc if the shell is interactive. This is on by default if the shell is invoked as sh.

—posix

Changes the behavior of bash to follow the POSIX guidelines more closely where the default operation of bash is different.

—quiet

Shows no information on shell startup. This is the default.

—rcfile file, —init-file file

Executes commands read from file instead of from the initialization file ~/.bashrc if the shell is interactive.

—verbose

Equivalent to -v.

—version

Shows the version number of this instance of bash and then exits.

[7] Only available in bash version 3.0 and later.

The multicharacter options have to appear on the command line before the single-character options. In addition to these, any set option can be used on the command line. Like shell built-ins, using a + instead of - turns an option off.

Of these options, the most useful are -i (interactive), -r (restricted), -s (read from standard input), -p (privileged), and -m (enable job control). Login shells are usually run with the -i, -s, and -m flags. We’ll look at restricted and privileged modes later in this chapter.

Environment Customization

Like the Bourne shell, bash uses the file /etc/profile for system-wide customization. When a user logs in, the shell reads and runs /etc/profile before running the user’s .bash_profile.

We won’t cover all the possible commands you might want to put in /etc/profile. But bash has a few unique features that are particularly relevant to system-wide customization; we’ll discuss them here.

We’ll start with two built-in commands that you can use in /etc/profile to tailor your users’ environments and constrain their use of system resources. Users can also use these commands in their .bash_profile, or at any other time, to override the default settings.

umask

umask, like the same command in most other shells, lets you specify the default permissions that files have when users create them. It takes the same types of arguments that the chmod command does, i.e., absolute (octal numbers) or symbolic permission values.

The umask contains the permissions that are turned off by default whenever a process creates a file, regardless of what permission the process specifies.[8]

We’ll use octal notation to show how this works. As you probably know, the digits in a permission number stand (left to right) for the permissions of the owner, owner’s group, and all other users, respectively. Each digit, in turn, consists of three bits, which specify read, write, and execute permissions from left to right. (If a file is a directory, the “execute” permission becomes “search” permission, i.e., permission to cd to it, list its files, etc.)

For example, the octal number 640 equals the binary number 110 100 000. If a file has this permission, then its owner can read and write it; users in the owner’s group can only read it; everyone else has no permission on it. A file with permission 755 gives its owner the right to read, write, and execute it and everyone else the right to read and execute (but not write).

022 is a common umask value. This implies that when a file is created, the “most” permission it could possibly have is 755—which is the usual permission of an executable that a compiler might create. A text editor, on the other hand, might create a file with 666 permission (read and write for everyone), but the umask forces it to be 644 instead.

ulimit

The ulimit command was originally used to specify the limit on file creation size. But bash’s version has options that let you put limits on several different system resources. Table 10-2 lists the options.

Table 10-2. ulimit resource options

Option

Resource limited

-a

All limits (for printing values only)

-c

Core file size (1 Kb blocks)

-d

Process data segment (Kb)

-f

File size (1 Kb blocks)

-l

Maximum size of a process that can be locked in memory (Kb)[9]

-m

Maximum resident set size

-n

File descriptors

-p

Pipe size (512 byte blocks)

-s

Process stack segment (Kb)

-t

Process CPU time (seconds)

-u

Maximum number of processes available to a user

-v

Virtual memory (Kb)

[9] Not available in versions of bash prior to 2.0.

Each takes a numerical argument that specifies the limit in units shown in the table. You can also give the argument “unlimited” (which may actually mean some physical limit), “hard” and “soft”, which refer to the current hard and soft limits (see below), or you can omit the argument, in which case it will print the current limit. ulimit -a prints limits (or “unlimited”) of all types.[10] You can specify only one type of resource at a time. If you don’t specify any option, -f is assumed.

Some of these options depend on operating system capabilities that don’t exist in older UNIX versions. In particular, some older versions have a fixed limit of 20 file descriptors per process (making -n irrelevant), and some don’t support virtual memory (making -v irrelevant).

The -d and -s options have to do with dynamic memory allocation, i.e., memory for which a process asks the operating system at runtime. It’s not necessary for casual users to limit these, though software developers may want to do so to prevent buggy programs from trying to allocate endless amounts of memory due to infinite loops.

The -v and -m options are similar; -v puts a limit on all uses of memory, and -m limits the amount of physical memory that a process is allowed to use. You don’t need these unless your system has severe memory constraints or you want to limit process size to avoid thrashing.

The -u option is another option which is useful if you have system memory constraints or you wish just wish to stop individual users from hogging the system resources.

You may want to specify limits on file size (-f and -c) if you have constraints on disk space. Sometimes users actually mean to create huge files, but more often than not, a huge file is the result of a buggy program that goes into an infinite loop. Software developers who use debuggers like sdb, dbx, and gdb should not limit core file size, because core dumps are necessary for debugging.

The -t option is another possible guard against infinite loops. However, a program that is in an infinite loop but isn’t allocating memory or writing files is not particularly dangerous; it’s better to leave this unlimited and just let the user kill the offending program.

In addition to the types of resources you can limit, ulimit lets you specify hard or soft limits. Hard limits can be lowered by any user but only raised by the super user (root); users can lower soft limits and raise them—but only as high as the hard limit for that resource.

If you give -H along with one (or more) of the options above, ulimit will set hard limits; -S sets soft limits. Without either of these, ulimit sets the hard and soft limit. For example, the following commands set the soft limit on file descriptors to 64 and the hard limit to unlimited:

ulimit -Sn 64
ulimit -Hn unlimited

When ulimit prints current limits, it prints soft limits unless you specify -H.

Types of Global Customization

The best possible approach to globally available customization would be a system-wide environment file that is separate from each user’s environment file—just like /etc/profile is separate from each user’s .bash_profile. Unfortunately, bash doesn’t have this feature.

Nevertheless, the shell gives you a few ways to set up customizations that are available to all users at all times. Environment variables are the most obvious; your /etc/profile file will undoubtedly contain definitions for several of them, including PATH and TERM.

The variable TMOUT is useful when your system supports dialup lines. Set it to a number N, and if a user doesn’t enter a command within N seconds after the shell last issued a prompt, the shell will terminate. This feature is helpful in preventing people from “hogging” the dialup lines.

You may want to include some more complex customizations involving environment variables, such as the prompt string PS1 containing the current directory (as seen in Chapter 4).

You can also turn on options, such as emacs or vi editing modes, or noclobber to protect against inadvertent file overwriting. Any shell scripts you have written for general use also contribute to customization.

Unfortunately, it’s not possible to create a global alias. You can define aliases in /etc/profile, but there is no way to make them part of the environment so that their definitions will propagate to subshells. (In contrast, users can define global aliases by putting their definitions in ~/.bashrc.)

However, you can set up global functions. These are an excellent way to customize your system’s environment, because functions are part of the shell, not separate processes.

System Security Features

UNIX security is a problem of legendary notoriety. Just about every aspect of a UNIX system has some security issue associated with it, and it’s usually the system administrator’s job to worry about this issue.

bash has two features that help solve this problem: the restricted shell, which is intentionally “brain damaged,” and privileged mode, which is used with shell scripts that run as if the user were root.

Restricted Shell

The restricted shell is designed to put the user into an environment where her ability to move around and write files is severely limited. It’s usually used for “guest” accounts.[11] You can make a user’s login shell restricted by putting rbash in the user’s /etc/passwd entry.[12]

The specific constraints imposed by the restricted shell disallow the user from doing the following:

  • Changing working directories: cd is inoperative. If you try to use it, you will get the error message bash: cd: restricted.

  • Redirecting output to a file: the redirectors >, >|, <>, and >> are not allowed.

  • Assigning a new value to the environment variables ENV, BASH_ENV, SHELL, or PATH.

  • Specifying any commands with slashes (/) in them. The shell will treat files outside of the current directory as “not found.”

  • Using the exec built-in.

  • Specifying a filename containing a / as an argument to the . built-in command.

  • Importing function definitions from the shell environment at startup.

  • Adding or deleting built-in commands with the -f and -d options to the enable built-in command.

  • Specifying the -p option to the builtin command.

  • Turning off restricted mode with set +r.

These restrictions go into effect after the user’s .bash_profile and environment files are run. In addition, it is wise to change the owner of the users’ .bash_profile and .bashrc to root, and make these files read-only. The users’ home directory should also be made read-only.

This means that the restricted shell user’s entire environment is set up in /etc/profile and .bash_profile. Since the user can’t access /etc/profile and can’t overwrite .bash_profile, this lets the system administrator configure the environment as he sees fit.

Two common ways of setting up such environments are to set up a directory of “safe” commands and have that directory be the only one in PATH, and to set up a command menu from which the user can’t escape without exiting the shell.

A System Break-In Scenario

Before we explain the other security features, here is some background information on system security that should help you understand why they are necessary.

Many problems with UNIX security hinge on a UNIX file attribute called the suid (set user ID) bit. This is like a permission bit (see umask earlier in this chapter): when an executable file has it turned on, the file runs with an effective user ID equal to the owner of the file, which is usually root. The effective user ID is distinct from the real user ID of the process.

This feature lets administrators write scripts that do certain things that require root privilege (e.g., configure printers) in a controlled way. To set a file’s suid bit, the superuser can type chmod 4755 filename; the 4 is the suid bit.

Modern system administration wisdom says that creating suid shell scripts is a very, very bad idea.[13] This has been especially true under the C shell, because its .cshrc environment file introduces numerous opportunities for break-ins. bash’s environment file feature creates similar security holes, although the security feature we’ll see shortly make this problem less severe.

We’ll show why it’s dangerous to set a script’s suid bit. Recall that in Chapter 3, we mentioned that it’s not a good idea to put your personal bin directory at the front of your PATH. Here is a scenario that shows how this placement combines with suid shell scripts to form a security hole: a variation of the infamous “Trojan horse” scheme. First, the computer cracker has to find a user on the system with an suid shell script. In addition, the user must have a PATH with her personal bin directory listed before the public bin directories, and the cracker must have write permission on the user’s personal bin directory.

Once the cracker finds a user with these requirements, he follows these steps:

  • Looks at the suid script and finds a common utility that it calls. Let’s say it’s grep.

  • Creates the Trojan horse, which is this case is a shell script called grep in the user’s personal bin directory. The script looks like this:

    cp /bin/bash filename
                         chown root 
                         filename
                         chmod 4755 
                         filename
                         /bin/grep "$@
    rm ~/bin/grep

    filename should be some unremarkable filename in a directory with public read and execute permission, such as /bin or /usr/bin. The file, when created, will be that most heinous of security holes: an suid interactive shell.

  • Sits back and waits for the user to run the suid shell script—which calls the Trojan horse, which in turn creates the suid shell and then self-destructs.

  • Runs the suid shell and creates havoc.

Privileged Mode

The one way to protect against Trojan horses is privileged mode. This is a set -o option (set -o privileged or set -p).

In privileged mode, when an suid bash shell script is invoked, the shell does not run the user’s environment file—i.e., it doesn’t expand the user’s BASH_ENV environment variable.

Since privileged mode is an option, it is possible to turn it off with the command set +o privileged (or set +p). But this doesn’t help the potential system cracker: the shell automatically changes its effective user ID to be the same as the real user ID—i.e., if you turn off privileged mode, you also turn off suid.

Privileged mode is an excellent security feature; it solves a problem that originated when the environment file idea first appeared in the C shell.

Nevertheless, we still strongly recommend against creating suid shell scripts. We have shown how bash protects against break-ins in one particular situation, but that certainly does not imply that bash is “safe” in any absolute sense. If you really must have suid scripts, you should carefully consider all relevant security issues.

Finally, if you would like to learn more about UNIX security, we recommend Practical UNIX and Internet Security, by Gene Spafford and Simson Garfinkel (O’Reilly ).



[1] A good source of information on system administration is Essential System Administration by Æleen Frisch (O’Reilly ).

[2] The exact message varies from system to system; make sure that yours prints this message when given the name of a shell script. If not, just substitute the message your file command prints for “shell script” in the following code.

[3] The inclusion of /dev/null in the grep command is a kludge that forces grep to print the names of files that contain a match, even if there is only one such file in a given directory.

[4] bash also enters POSIX mode when started as sh. Versions of bash prior to 2.0 don’t—POSIX mode has to be explicitly set with the —posix command-line option.

[5] Multicharacter options are far more readable and easier to remember than the old, and usually cryptic, single character options. All of the GNU utilities have multicharacter options, but many applications and utilities (certainly those on old UNIX systems) allow only single-character options.

[6] See Appendix B for a list of options for versions of bash prior to 2.0.

[8] If you are comfortable with Boolean logic, think of the umask as a number that the operating system logically ANDs with the permission given by the creating process.

[10] The “hard” and “soft” arguments are not available in bash prior to version 2.05a.

[11] This feature is not documented in the manual pages for old versions of bash.

[12] If this option has been included when the shell was compiled. See Chapter 11 for details on configuring bash.

[13] In fact, most versions of UNIX intentionally disable the suid feature for shell scripts.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.240.21