Chapter 3. The Boot and Login Environments

Introduction

When it comes to configuring systems, many users are reluctant to change the default boot process. Visions of unbootable systems, inaccessible data, and reinstalls dance in their heads. Yes, it is good to be mindful of such things as they instill the necessary attention to detail you’ll need to use when making changes. However, once you’ve taken the necessary precautions, do take advantage of the hacks found in this chapter. Many of them will increase the security of your system.

This chapter also includes several password hacks. You’ll learn how to create an effective password policy and monitor compliance to that policy. You’ll find tools designed to assist you and your users in making good password choices. You’ll also learn how to configure OTP, an excellent choice for when you’re on the road and wish to access your network’s resources securely.

Customize the Default Boot Menu

Configure a splash screen.

You’re not quite sure what you did to give the impression that you don’t already have enough to do. Somehow, though, you were elected at the latest staff meeting to create a jazzy logo that will appear on every user’s computer when they boot up in the morning.

While you may not be able to tell from first glance, the FreeBSD boot menu supports a surprising amount of customization. Let’s start by examining your current menu to see which tools you have to work with.

The Default Boot Menu

Your default boot menu will vary slightly depending upon your version of FreeBSD and whether you chose to install the boot menu when you installed the system. Let’s start with the most vanilla boot prompt and work our way up from there. In this scenario, you’ll see this message as your system boots:

Hit [Enter] to boot immediately, or any other key for command prompt.
Booting [/boot/kernel/kernel] in 10 seconds...

FreeBSD 5.1 introduced a quasi-graphical boot menu that includes a picture of Beastie and the following options:

Welcome to FreeBSD!

  1. Boot FreeBSD [default]
  2. Boot FreeBSD with ACPI disabled
  3. Boot FreeBSD in Safe Mode
  4. Boot FreeBSD in single user mode
  5. Boot FreeBSD with verbose logging
  6. Escape to loader prompt
  7. Reboot

          Select option, [Enter] for default
          or [Space] to pause timer  10

It is possible to get this menu without doing a full install of FreeBSD 5.1. If you’re like me and use cvsup [Hack #80] and buildworld to keep up-to-date, you already have the necessary files but need to do a bit of editing to enable this boot menu. Even if you already have the boot menu, follow along because we’re about to discover some of the logic behind the FreeBSD boot process. This will be excellent preparation for learning how to hack in your own customizations.

Let’s start by taking a look at the directory that contains all of the boot information. Not surprisingly, it’s called /boot:

# ls /boot -F
beastie.4th     cdboot*         kernel.old/     loader.rc      support.4th
boot            defaults/       loader*         mbr
boot0           device.hints    loader.4th      modules/
boot1           frames.4th      loader.conf     pxeboot
boot2           kernel/         loader.help     screen.4th

The actual file containing the new menu is beastie.4th. If your sources are out-of-date and you don’t have this file, you can download it from http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/boot/forth/. Be sure to download also the latest versions of frames.4th and screen.4th.

The /boot directory also contains the loader executable. This application is responsible for finishing the boot process. To do so, it depends on two configuration files, loader.rc and loader.conf. Let’s take a peek at loader.rc:

# more loader.rc
 Loader.rc
 $FreeBSD: src/sys/boot/forth/loader.rc,v 1.2 1999/11/24 17:59:37 dcs Exp $

 Includes additional commands
include /boot/loader.4th

 Reads and processes loader.rc
start

 Tests for password -- executes autoboot first if a password was defined
check-password

 Unless set otherwise, autoboot is automatic at this point

Warning

We’re aiming to be hackers here, not destroyers of systems. A system that refuses to boot completely is not a very fun system to work on. So, before mucking about with any of the files in /boot, make sure you have your Emergency Repair Kit ready (see [Hack #71] and [Hack #72] for more information). Also, take extra care in your editing and be especially alert for typos before saving your changes.

Lines that begin with a backslash () are comments. Additionally, you can add your own comments to lines containing a command by preceding your comment with a # like this:

include /boot/loader.4th    # do NOT remove this line!
start                       # do NOT remove this line!

Those are good comments to add, as you want to make sure you never remove those two lines—they are necessary to the workings of your boot loader.

Before editing this file, make a backup copy first:

# cp loader.rc loader.rc.orig

Then, to tell your system to use beastie.4th, carefully add the following lines to the bottom of /boot/loader.rc.

 Load in the boot menu
include /boot/beastie.4th

 Do the normal initialization and startup
initialize drop

 Start the boot menu
beastie-start

Triple-check for typos. When you’re ready, make sure that you’ve saved all of your work and check that no one else is connected to the system. In order to test out the change, you’re going to have to reboot:

# reboot

If all went well, you now have a Beastie menu to assist you in your bootup selection. If your boss had something else in mind other than the ultracool Beastie menu, let him know that have you not yet begun to customize!

Configuring the Splash Screen

Remember the other file I mentioned, loader.conf? Well, you should actually have two files with that name. /boot/defaults/loader.conf is the system default, and you should never edit this file. Instead, copy it over to /boot/loader.conf and make your changes there. That way, not only do you have a chance to see what is available for customization, you also reduce your risk of typos. Each line in this file is commented and additional information can be gleaned from man loader.conf.

Locate the Splash screen configuration section so you can configure that company logo your boss keeps insisting on. This is what it looks like by default:

splash_bmp_load="NO"          # Set this to YES for bmp splash screen!
splash_pcx_load="NO"          # Set this to YES for pcx splash screen!
vesa_load="NO"                # Set this to YES to load the vesa module
bitmap_load="NO"              # Set this to YES if you want splash screen!
bitmap_name="splash.bmp"      # Set this to the name of the bmp or pcx file
bitmap_type="splash_image_data" # and place it on the module_path

Obviously, we’ll have to change the NO in one of those splash lines to a YES. Which one depends upon your picture format. The two types of images that can be loaded are bmp or pcx. Depending upon the image you have to work with, change the appropriate NO to a YES.

If the image also happens to have eight or more bits of color, set vesa_load to YES. If you have no idea what type or size of picture you’re dealing with, use the file command:

# file logo.bmp
logo.bmp:  PC bitmap data, Windows 3.x format, 408 x 167 x 8

This particular logo is a bitmap that is 408 167 pixels at 8 bits of color.

Don’t forget to set the path of your bitmap file, and make sure you remember to copy that bitmap to the specified location:

bitmap_name="/boot/logo.bmp"

Leave this line as is:

bitmap_type="splash_image_data"     # and place it on the module_path

Finally, enable bitmap loading:

bitmap_load="YES"

When you’re editing /boot/loader.conf, keep in mind that you are asking the loader program to load various portions of the kernel. If you have changed your kernel configuration file [Hack #54] , double-check that you haven’t stripped your kernel of a function you’re now asking loader to load. For example, before rebooting I should double-check that splash functionality is still in my kernel. Here, my new kernel configuration file is named NEW:

# grep splash /usr/src/sys/i386/conf/NEW
device        splash        # Splash screen and screen saver support

splash also requires device sc, so ensure that is your console type:

# grep -w sc /usr/src/sys/i386/conf/NEW
device    sc

The -w flag tells grep to treat sc as a word rather than attempt to match any word containing the letters sc.

Once you’re happy with your changes, make sure no one is working on the system and then reboot. Your bitmap image should appear right after you make your choice at the Beastie menu. It will remain on the screen until you press a key. This behavior has the advantage of displaying your company logo instead of the usual startup messages. However, if you ever need to see those messages, simply press a key and your bitmap will disappear.

The Terminal Screensaver

As it is set up now, the bitmap will also act as a terminal screensaver that will kick in after five minutes. To change the screensaver’s timeout value, add this line to /etc/rc.conf:

blanktime="60"

The number you choose represents the number of seconds. If you decide you don’t like the screensaver functionality, add this line to /etc/rc.conf:

saver="NO"

Those changes to /etc/rc.conf won’t take effect until you reboot the system. To enforce those settings immediately, at least until the next reboot, use the vidcontrol command:

# vidcontrol -t 60

# vidcontrol -t off

Regardless of your timeout setting, you can still launch the screensaver at will—say, when you leave your terminal—by pressing the Shift and Pause keys simultaneously. You may just want to do that before you go grab your boss to show him that jazzy company logo.

See Also

Protect the Boot Process

Thwart unauthorized physical access to a system.

Creating a snazzy boot environment for users is one thing. However, when it comes to booting up servers, your mind automatically shifts gears to security mode. Your goal is to ensure that only a very precious few on very rare occasions ever see the boot process on a server. After all, the golden rule in security land is “physical access equals complete access.”

Here’s a prime example—consider recovering from an unknown or forgotten root password. Go into the server closet, reboot that system, and press a key to interrupt the boot process to change the password. A few moments later, the system continues to boot as normal. This can be a real lifesaver if an admin leaves without divulging the root password. However, consider the security implications of an unauthorized user gaining physical access to that server: instant root access!

Limiting Unauthorized Reboots

Let’s start by ensuring that regular users can’t reboot the system either inadvertently or maliciously. By default, if a user presses Ctrl-Alt-Delete, the system will clean up and reboot. Typically this isn’t an issue for servers, as most administration is done remotely and the server is safely locked away in a server closet. However, it can wreak havoc on workstations, especially if the user is used to working in a Windows environment and has become accustomed to pressing Ctrl-Alt-Delete. It’s also worthwhile disabling on a server, as it ensures that a person has to first become the superuser in order to issue the reboot command.

Tip

If you’re logged into a remote machine over SSH and try Ctrl-Alt-Delete, it will affect your own machine, not the remote machine. reboot works well over the network, though.

Disabling this feature requires a kernel rebuild. (See [Hack #54] for detailed instructions.) Add one of these lines to your kernel configuration file, then rebuild and reinstall the kernel:

options SC_DISABLE_REBOOT  # if using syscons console driver

# or

options PCVT_CTRL_ALT_DEL  # if using pcvt console driver

You’re probably thinking, “If I wanted to reboot a system and didn’t know the superuser password, I’d simply hit the power button.” Yup! That kernel option certainly won’t prevent that, but a carefully thought out CMOS[1] configuration will decide if and how that system will reboot.

At a minimum, the CMOS configuration should allow only one boot device. This is to prevent an intruder from trying to boot an alternate kernel from a floppy, CD-ROM drive, or other supported boot device. Additionally, you should set a password for CMOS and record it in a safe place. This will prevent an intruder from simply changing the CMOS configuration. Keep in mind that this is not fail-proof; you are merely adding layers of inconvenience. A determined intruder can simply pop open the case and drain the CMOS battery, but that takes time and additional effort.

Password Protecting Single-User Mode

All the magic happens when you interrupt the boot process. This is where you can change the superuser password without having to first know the superuser password. This is where you can unload the currently loaded kernel and replace it with another. This is where you can change any configuration file or binary without worrying about securelevels or system flags [Hack #56] . This is the reason why you lock up your servers, monitor access to the server room, and run them headless [Hack #26] .

Fortunately, interrupting the boot process requires keyboard input, meaning the user needs physical access to the system. What happens when a malicious user does bypass your physical security measures, gaining physical access to the system? All she has to do is interrupt that boot process, and the system is hers to do as she wishes.

On a system without the graphical boot menu [Hack #24] , pressing any key at the timer will pause the boot process. If the system has the graphical boot menu, pressing 6 to Escape to loader prompt will show the same timer. The timer option looks like this:

Hit [Enter] to boot immediately, or any other key for command prompt.
Booting [/boot/kernel/kernel] in 10 seconds...

If you press any key other than Enter, you’ll receive this:

Type '?' for a list of commands, 'help' for more detailed help.
OK boot -s

Type boot -s to enter single-user mode. The kernel will appear to load normally, but, instead of processing the rc scripts, this prompt will appear:

Enter full pathname of shell or RETURN for /bin/sh:
#

Once you’ve finished making your desired changes, simply type exit. The system will continue to boot into multiuser mode.

Now, how do you prevent a user from doing that? Password protect single-user mode by editing /etc/ttys. Find this line:

# If console is marked "insecure", then init will ask for the root password
# when going to single-user mode.
console none              unknown off secure

Follow the comments and change the word secure to insecure. While that may seem nonintuitive, you’re saying the system is considered to be insecure, thus you want a password. The next time a user attempts single-user mode, the kernel will load, but the user will receive this prompt instead:

Enter root password, or ^D to go multi-user
Password:

Warning

You must not forget the root password if you password protect single-user mode!

Password Protecting loader

Let’s return to the timer section of the boot process. A user can type more than boot -s after interrupting the boot process. In fact, if you press ? at that OK prompt, you’ll see that you can unload the current kernel, load another kernel, load and unload kernel modules, and view and change variables. You can muck about with just about every part of the boot process that would normally be controlled by the loader command.

Fortunately, you can also require a user to input a password before receiving that OK prompt. Set the password by adding this line to /boot/loader.conf:

password=12345

Of course, your password should be harder to guess than 12345. Now the boot process will prompt the user for a password. Without that password, you cannot enter single-user mode or load or unload kernel modules. You can still boot; you just cannot interrupt the boot process.

Also, if your CMOS supports it, you can require a password to boot the machine. However, this is often considered to be a bad thing, especially on a co-located web or mail server.

Tip

The password in /boot/loader.conf is in clear text. Although you can’t encrypt this password, you can tighten up its permissions so only the superuser can read it:

# chmod 600 /boot/loader.conf

See Also

Run a Headless System

For those times when you want to run a system “headless."

Sometimes it is a simple matter of economy. Perhaps you’ve managed to scrounge up another system, but you don’t have enough monitors, keyboards, or mice to go around. You also don’t have the budget to purchase either those or a KVM switch. Sometimes it is a matter of security. Perhaps you’re introducing a PC to a server closet and your physical security policy prevents server closet devices from being attached to monitors, keyboards, and mice.

Before you can run a system “headless,” you need to have an alternative for accessing that system. Once you’ve removed input and output peripherals, your entry point into the system is now either through the network card or a serial port.

Going in through the network card is the easiest and is quite secure if you’re using SSH. However, you should also consider a plan B. What if for some reason the system becomes inaccessible over the network? How do you get into the system then? Do you really want to gather up a spare monitor, keyboard, and mouse and carry them into the server closet?

A more attractive plan B may be to purchase a null modem cable as insurance. This is a crossed serial cable that is designed to go from one computer’s serial port to another computer’s serial port. This type of cable allows you to access a system without going through the network, which is a real lifesaver when the system isn’t responding to the network. You can purchase this type of cable at any store that sells networking cables.

Your last consideration is whether the system BIOS will cooperate with your plan. Most newer BIOSes will. Many have a CMOS option that can be configured to disable “halt on errors.” It’s always a good idea to check out your available CMOS options before you start unplugging your peripherals.

Preparing the System

I’ve just installed a new FreeBSD 5.1 system. Since I didn’t have a null modem cable handy, I installed the old-fashioned way with the monitor and keyboard attached. If you do have a null modem cable and want to experiment with a headless install, follow the directions in the Handbook section referenced at the end of this hack.

Since I want to access the server over the network, I’ll double-check that the NIC is properly configured and that sshd is running:

% ifconfig ed0
ed0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        inet 192.168.2.94 netmask 0xffffff00 broadcast 192.168.2.255
        ether 00:80:ad:79:4e:fd

% sockstat | grep sshd
root     sshd       389   4  tcp4   *:22                  *:*

The ifconfig command is used to verify an interface’s configuration; in this example, the interface is ed0. The flags indicate that this interface is UP and RUNNING. The interface also has an IP address of 192.168.2.94.

The sockstat command is similar to the netstat command, but I find it provides a more intuitive output. For each open port it will display the owner of the service (root), the name of the service (sshd), the PID (389), the socket file descriptor (4), the transport (tcp4), the local address (*:22), and the foreign address (*.*).

The PID is useful if you need to send a signal to the process. The local address indicates which interfaces on this system (in this case, all, or *) are listening on which port number (22). There aren’t any current sessions, as the foreign address section is *.*. If there were a current session, it would show the address of the other system followed by the socket number being used for the connection.

If for some reason sshd isn’t running on your system, add the following line to /etc/rc.conf:

sshd_enable="YES"

and double-check that it’ll be available at bootup, like so:

# /etc/rc.d/sshd rcvar
#sshd
$sshd_enable=YES

Finally, typing sshd as the superuser should start the daemon. You can prove this by checking that it’s listening with sockstat | grep sshd.

One last test—I’ll make sure I can log into the system over the network:

% ssh 192.168.2.94
Password:
%

Now that I knew the system was accessible over the network, it was time for the moment of truth. After halting the system, I entered its CMOS configuration. I was a little bit worried because there weren’t any options dealing with “halt errors.” Undaunted, I left CMOS and powered off and unplugged the monitor, keyboard, and mouse. I then opened the case and physically removed the video card.

When I powered up, the system responded with a longer than ordinary beep. But after a few seconds, my hard drive light flashed and I could hear the operating system probing my devices and loading the drivers. After a moment or so, I tried to ssh into the system and was greeted with my password prompt! Assuming your BIOS is willing to cooperate, FreeBSD has no problem loading headless.

If the Headless System Becomes Inaccessible

Should your system ever stop responding over the network, you’ll be glad you purchased that null modem serial cable. Connect one end to the COM port of the headless system, and the other end to the COM port of another system that you can access either directly or over the network.

If that other system is running a Windows operating system, go to Start Programs Accessories Communications HyperTerminal (or open hypertrm.exe). You’ll need to create a new connection, so choose a name and icon for it. Under Connect using:, choose the COM port to which the serial cable is attached.

You’ll also have to configure the port properties for that COM port. Change the default 2400 bits per second to 9600. Finally, change hardware flow control to none. Press Enter, and you should be connected to the headless system. If you’re not, double-check that you chose the correct COM port.

If you’re attaching from a system running any variant of Unix, you can use either the cu or tip commands to connect via the serial cable.

To use cu, simply specify your COM port using the line switch -l and a speed of 9600 baud using the speed switch -s. For example, this syntax allows you to connect to COM2 or cuaa1:

# cu -l /dev/cuaa1 -s 9600
Connected.

You should now be able to see what is happening on your headless system. One of the advantages of connecting through a serial cable is that you can watch the boot process of the system. You can’t do this over a network connection, because initializing the network occurs toward the end of a successful boot.

Before the network can be initialized, the kernel must successfully load into memory and the necessary hardware must be probed. If you’re having problems booting a system, it is usually due to a missing or corrupt kernel or a hardware problem.

To disconnect from the cu session, type ~., then press the Enter key. You should receive a Disconnected. message and receive the prompt of the system you started from.

The tip utility doesn’t use line or speed switches. It instead expects you to use one of the finger friendly shortcuts found at the end of the /etc/remote file. Let’s take a look at that section:

# tail /etc/remote
# Hardwired line
cuaa0b|cua0b:dv=/dev/cuaa0:br#2400:pa=none:
cuaa0c|cua0c:dv=/dev/cuaa0:br#9600:pa=none:

# Finger friendly shortcuts
com1:dv=/dev/cuaa0:br#9600:pa=none:
com2:dv=/dev/cuaa1:br#9600:pa=none:
com3:dv=/dev/cuaa2:br#9600:pa=none:
com4:dv=/dev/cuaa3:br#9600:pa=none:

Notice that there is an entry for each COM port. This means that to connect to COM2, you simply have to type:

# tip com2
connected

You need a little bit more coordination to disconnect, though. Hold down Shift while you press the ~ key. Keep your finger on Shift as you press the Ctrl key, then the letter D:

# ~^D
[EOT]

See Also

Log a Headless Server Remotely

More on headless systems, but this time from the NetBSD perspective.

We’ve already seen in [Hack #26] that it’s important to have an alternative method for connecting to a headless server. It’s also important to be able to receive a headless system’s console messages. This hack will show how to configure both on a NetBSD system.

Enabling a Serial Console

If you have another machine close to your headless server, it may be convenient to enable the serial console so that you can connect to it using a serial communication program. tip, included in the base system, and minicom , available through the packages collection, allow you to handle the server as if you were working on a real physical console.

To enable the serial console under NetBSD, simply tell the bootblocks to use the serial port as the console; they will configure the kernel on the fly to use it instead of the physical screen. You also need kernel support for the serial port device, which is included in the default GENERIC kernel.

However, changing the bootblocks configuration is a bit tricky because you need write permissions to the raw root device. As we are talking about a server, I assume the securelevel functionality is enabled; you must temporarily disable it by adding the options INSECURE line to your kernel. While in the kernel configuration file, double-check that it includes serial port support. Then, recompile your kernel.

Once you have access to the raw partition, update the bootblocks using the installboot utility. The process depends on the NetBSD version you are using.

If you are running 2.0 or higher, use the command shown next. Replace the bootxx_ffsv1 file with the one that matches your root filesystem type; failure to do so will render your system unbootable.

# /usr/sbin/installboot -o console=com0 /dev/rwd0a /usr/mdec/bootxx_ffsv1

If you are running 1.6, use the following command instead:

# /usr/mdec/installboot /usr/mdec/biosboot_com0.sym /dev/rwd0a

When done, rebuild your kernel without the options INSECURE line to reenable securelevel. You can also remove the console drivers wscons and pccons to reduce the kernel size, though you must keep the serial port driver.

Tip

As an alternative to building an insecure kernel, you can boot from a floppy disk to get direct access to the partition and update the bootblocks as described earlier. The floppies you used to install the system are fine.

Setting Up the Logging Server

Even if you have configured a serial console, you won’t always be connected to it. Therefore, it is very convenient to redirect important console messages to another machine that has a physical screen connected to it. syslogd lets you do this.

Start by allowing incoming syslogd connections on the machine that will be receiving log messages. (I call mine logger.local.) To do this, add the following lines to /etc/rc.conf:

syslogd_enable="YES"
syslogd_flags="-ss"

The first option is not really needed, as syslogd is enabled by default. The second option overrides the secure (s) flag that otherwise would be passed to the daemon through /etc/defaults/rc.conf. This flag tells syslogd not to listen on a UDP socket, and in this scenario we want to receive log messages over the network.

Then, restart the daemon:

# /etc/rc.d/syslogd restart

logger.local can now receive incoming syslogd connections from any host. If required, you can restrict this by using the built-in firewall, ipf.

Setting Up the Headless System

You are ready to configure your headless server to send messages to the logger machine. As an example, we are going to redirect all messages that are actually sent to the serial console to logger.local.

Open /etc/syslog.conf in your favorite editor. You will notice that the first uncommented line directs messages to /dev/console. Append the @logger.local string to it, separated by a comma. After the changes, you should end up with something like:

*.err;kern.*;auth.notice;authpriv.none;mail.crit  /dev/console,@logger.local

Repeat for any other categories you want to redirect. When done, restart syslogd as shown earlier.

Shutting Down the Server Using wsmoused

Tip

The next two sections of this hack require NetBSD 2.0 and above.

If you are running a headless system at home, you may want to shut it down at night. You could do this by sshing into the server and executing shutdown manually, but this requires a second system. However, since you have physical access to the headless system, you can simply use wsmoused, which will let you execute two or three commands from a mouse—one for each mouse button.

wsmoused’s “action mode” lets you assign commands to mouse buttons. Here’s a sample configuration file to shut down and reboot the machine, which you can copy to /etc/wsmoused.conf:

device = /dev/wsmoused;
modes = action;

mode action {
        button_0_down = "shutdown -p now";
        button_2_down = "shutdown -r now";
}

Here I’ve mapped the left mouse button, 0, to the command that will halt the system and the right mouse button, 2, to the command that will reboot the system. (The middle mouse button is 1.) Since I don’t plan on using this mouse for its usual input functions, such as copy and paste, this is a really convenient way to power off the system quickly and safely.

Enable the startup of wsmoused at boot time:

# echo "wsmoused=YES" >> /etc/rc.conf

Tip

If you have a dial-up connection, you could use a similar configuration to connect and disconnect the link.

Beep on Halt

Some headless servers don’t support APM or ACP, so the kernel can’t power them down automatically. The i386 architecture has another option: beep on halt. It beeps the speaker multiple times when it is safe to power off the machine after a successful halt.

To enable this feature, add the following line to your kernel configuration file and rebuild it:

options BEEP_ONHALT

In case you do not like the default tone, you have several other options. Here they’re shown with their default values:

options BEEP_ONHALT_COUNT=3    # Times to beep
options BEEP_ONHALT_PITCH=1500 # Default frequency (in Hz)
options BEEP_ONHALT_PERIOD=250 # Default duration (in msecs)

See Also

  • man 8 installboot

  • man syslogd

  • man wsmoused

  • man shutdown

Remove the Terminal Login Banner

Give users the information you want them to receive when they log in.

The default login process on a FreeBSD system produces a fair bit of information. The terminal message before the login prompt clearly indicates that the machine is a FreeBSD system. After logging in, a user will receive a copyright message and a Message of the Day (or motd), both of which contain many references to FreeBSD.

This may or may not be a good thing, depending upon the security requirements of your network. Your organization may also require you to provide legal information regarding network access or perhaps a banner touting the benefits of your corporation. Fortunately, a few simple hacks are all that stand between the defaults and your network’s particular requirements.

Changing the Copyright Display

Let’s start with the copyright information. That’s this part of the default login process:

Copyright (c) 1992-2003 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.

To prevent users from seeing this information, simply:

# touch /etc/COPYRIGHT

Changing the Message of the Day

Technically, you could add your own information to /etc/COPYRIGHT instead of leaving it as an empty file. However, it is common practice to put your information in /etc/motd instead. The default /etc/motd contains very useful information to the new user, but it does get rather old after a few hundred logins.

You can edit /etc/motd to say whatever suits your purposes—anything from your favorite sci-fi excerpt to all the nasty things that will happen to someone if they continue to try to log into your system. Here’s a very simple example:

# more /etc/motd
*********************************************************
*****            Authorized users only!!            *****
*********************************************************

You’ll note that after you customize your motd, users will still see this text prepended to it:

FreeBSD 5.1-RELEASE (GENERIC) #0: Thu Jun 5 02:55:42 GMT 2003

If you don’t want to advertise your operating system version and kernel information, you’ll need one more hack. Add this line to /etc/rc.conf:

update_motd="NO"

If you’re using FreeBSD 5.x, you no longer have to reboot or go into single-user mode to initialize a change to /etc/rc.conf. Instead, you can use one of the many scripts available in /etc/rc.d. Let’s see if there’s a script that deals with motd:

# ls -F /etc/rc.d | grep motd
motd*

Excellent. Let’s see what syntax that command expects:

# /etc/rc.d/motd
Usage: /etc/rc.d/motd [fast|force](start|stop|restart|rcvar)

Parameters in square brackets are optional, whereas parameters in parentheses are mandatory. Notice each option is separated by the or symbol (|), meaning you just pick one out of the list. In our case, we want to use the rcvar parameter. This will tell the motd script to reread its setting in /etc/rc.conf:

# /etc/rc.d/motd rcvar
# motd
$update_motd=NO

Warning

OpenBSD users, read man motd and /etc/rc (search for motd) to understand how the system constructs the banner. Otherwise, it’ll update when you least expect it!

Changing the Login Prompt

Finally, let’s change the text that first appears at the login prompt. This requires an edit to /etc/gettytab. This is a fairly important file as it controls access to your terminals, which is how users access the system. Before editing this file, always make a backup copy first:

# cp /etc/gettytab /etc/gettytab.orig

Next, open up /etc/gettytab in your favorite text editor and look for this line:

default:
:cb:ce:ck:lc:fd#1000:im=
 %s/%m (%h) (%t) 

:sp#1200:

See the part in bold? That’s the part you can replace with what you’d like the world to see when they receive their login prompt. Right now, they see this:

FreeBSD/i386 (host.domain.com) (ttyv1)

That’s because that default string contains the variables in Table 3-1.

Table 3-1. Login prompt variables

Variable

Meaning

%s

Operating system

%m

Architecture

%h

Hostname

%t

tty name

You can very carefully change those characters to something else. For example, mine looks like this:

:cb:ce:ck:lc:fd#1000:im=
 I'm a node in Cyberspace. Who are you? 


:sp#1200:

Again, I’ve put my changes in bold for emphasis. Carefully double-check that you didn’t lose any carriage return ( ) or newline ( ) characters along the way, then save your change.

Testing Your Changes

It’s important to test your change immediately at a different terminal to ensure you can still log into your system. This way, if you did make a typo that prevents logins, you can return to your previous terminal and fix it.

I’ll press Alt-F4 to go to a terminal with a login prompt. I’ll probably still see the old terminal message, so I’ll log in, log out, then log in again:

login:
Password:
% exit
logout
I'm a node in Cyberspace. Who are you?

login:

See Also

Protecting Passwords With Blowfish Hashes

Take these simple steps to thwart password crackers.

All good administrators know that passwords can be a weak link in the security chain. A malicious and determined user armed with a password cracker could conceivably guess enough of your network’s passwords to access unauthorized resources.

Protecting System Passwords in General

Fortunately, you can make a password cracker’s life very difficult in several ways. First, educate your users to choose complex, hard-to-guess passwords that are meaningful enough for them to remember. This will thwart dictionary password crackers [Hack #30] , which use lists of dictionary and easy-to-guess words.

Second, be aware of who has superuser privileges and who has the right to backup /etc. This directory contains the two password databases that are required to run a brute-force password cracker. As the name implies, this type of cracker will eventually guess every password in your password databases as it systematically tries every possible keyboard combination. Your best protection from this type of cracker is to prevent access to those password databases. This includes locking up your backup tapes and monitoring their access.

It is also a good idea to increase the amount of time it would take a brute-force cracker to crack a password database. FreeBSD, like most Unix systems, adds a magic bit of randomness—known as a salt—to the password when it is stored in the password database. The upshot is that a password cracker may have to try up to 4,096 different combinations for each and every password it tries to guess.

Using a strong algorithm to protect your passwords can also slow down a brute-force cracker. FreeBSD supports a hard-to-crack algorithm known as Blowfish. One of the first things I do after a FreeBSD install is to configure the password database to use Blowfish. While it is easier to do this before you create your users, it is still worth your while to implement it after you’ve created your user accounts.

Protecting System Passwords with Blowfish

To use Blowfish, start by opening up /etc/login.conf in your favorite editor. Look for this line:

:passwd_format=md5:

Carefully edit it so it looks like this:

:passwd_format=blf:

Check for typos before saving your change.

You may have noticed this comment when you modified /etc/login.conf:

# Remember to rebuild the database after each change to this file:
#
#        cap_mkdb /etc/login.conf
#

Let’s take a closer look at what we’re being asked to do. According to that comment, login.conf is more than a configuration file, it is a database. Not only that, it is a capability database, a database that supports different capabilities. That is the reason behind the weird syntax within login.conf. Whenever you edit a capability database, you have to use the cap_mkdb command to integrate your changes within the database.

So, follow the directions:

# cap_mkdb /etc/login.conf

Converting existing passwords

If you have any existing users, you need to convert their passwords from MD5 to Blowfish. This is why it’s a good idea to make the change before you create your users.

If you’ve already created users, it’s back to the password database to find all of the active accounts. Inactive accounts—accounts that don’t allow logins—have the * character instead of an encrypted password. Since we want to find all of the lines in the password database that do not contain an asterisk, we need an inverted grep:

# grep -v '*' /etc/master.passwd
root:$1$ywXbyPT/$GC8tXN91c.lsKRpLZori61:0:0::0:0:Charlie &:/root:/bin/csh
dru:$1$GFm1nh6I$jh3v4I.QNf450ARgltZU5.:1008:0::0:0:User &:/home/dru:/bin/csh

Well, that worked, but we could make the output look much prettier:

# grep -v '*' /etc/master.passwd | cut -d ':' -f 1
root
dru

Let’s pick apart that command syntax. grep -v creates a reverse filter. In effect, it says, “Show me the lines in /etc/master.passwd that do not contain an *.” Since those lines are long and contain much more than just the username, I piped the output to the cut utility to literally cut out the portions I don’t need to see. Notice that the usernames are the very first thing in each line, and they are always followed by the : field separator. -d tells cut to consider the colon character, not the tab character, as the separator. -f 1 tells cut that I’m interested in the very first field of that line.

It looks like my particular system has two active accounts: root and dru. Notice in the original output the long sequence of characters that starts with $1 and ends with :. No, my users’ passwords aren’t quite that complex. Rather, you’re seeing the password after it’s been encrypted by the MD5 algorithm. That $1 means MD5. It’ll be $2 after we switch to Blowfish encryption. (Be aware that you can’t edit the file directly; the entire password must be changed.)

I’ll now change those two passwords:

# passwd dru
Changing local password for dru
New Password:
Retype New Password:

# passwd
Changing local password for root
New Password:
Retype New Password:

Note that the superuser can change any user’s password by specifying the appropriate username. If you don’t specify a name, you will instead change the root password.

When you’re finished, repeat the original grep -v command and double-check that all of the encrypted passwords now start with $2.

Tip

Don’t forget to tell your users that you have changed their passwords! Also caution them to use passwd to reset their password to a value known only to themselves.

Forcing new passwords to use Blowfish

Finally, configure the adduser utility to use Blowfish whenever you create a new user by editing /etc/auth.conf. Look for this line:

# crypt_default = md5 des

and carefully change it to:

crypt_default = blf

Once you’ve saved your change, test it by creating a new user. The easiest way to do this is to type adduser and follow the prompts.

See Also

Monitor Password Policy Compliance

When to use a password cracker utility.

Now that you’ve tightened up your password policy to thwart password crackers, it’s time to learn how to use a password cracker to monitor the effectiveness of that password policy.

You’re probably thinking, “Hey, wait a minute! Isn’t that some sort of oxymoron? An administrator cracking passwords?” Well, it depends upon the type of password cracker you plan on using.

A brute-force password cracker such as John the ripper or slurpie will systematically try every possible keyboard combination until it has cracked every password in the password database. Does an administrator need to know every password in his network? Definitely not.

However, an administrator does need to know if her users are choosing easy-to-guess passwords, especially if she’s responsible for enforcing compliance to the network’s password policy. A properly tweaked dictionary password cracker such as crack is an effective way to monitor that compliance.

It is important that a network’s security policy indicates in writing who runs the dictionary cracker, when it is run, and how the results are handled. For example, if the password policy forces users to change their passwords every 30 days, the following day is an excellent time for the delegated administrator to run the cracker. Ideally, the cracker will return no results. This means all users chose a strong password. Should the cracker find some weak passwords, the security policy should clearly outline the procedure used to ensure that noncompliant users change their passwords to ones that are harder to guess.

Installing and Using crack

Let’s take a look at the most commonly used dictionary password cracker used on Unix systems, crack. You’ll have to be the superuser for this entire hack because, fortunately, only the superuser has permission to crack the passwd database. crack should build on any Unix system; I’ll demonstrate on FreeBSD:

# cd /usr/ports/security/crack
# make install clean

On my system, this creates the /usr/local/crack directory which only the superuser can access. I need to cd into that directory in order to crack passwords. I’ll start with a simple crack, then show you how to tweak this utility to serve your particular network.

# cd /usr/local/crack
# ./Crack -fmt bsd /etc/master.passwd

Crack is a Bourne shell script contained within this directory, so you’ll have to run it with the command ./Crack. Use the -fmt switch to indicate the type of system; in my case, it is bsd. Finally, pass the path of the database containing the actual password hashes. On my system, this is the BSD shadow password database at /etc/master.passwd. The command and output on my test system is:

# ./Crack -fmt bsd /etc/master.passwd
Crack 5.0a: The Password Cracker.
(c) Alec Muffett, 1991, 1992, 1993, 1994, 1995, 1996
System: FreeBSD genisis 5.1-RELEASE FreeBSD 5.1-RELEASE #7: 
    Tue Jul 29 09:54:11 EDT 2003 dru@genisis:/usr/obj/usr/src/sys/NEW i386
Home: /usr/local/crack
Invoked: ./Crack -fmt bsd /etc/master.passwd
Stamp: freebsd-5-i386_

Crack: making utilities in run/bin/freebsd-5-i386_
find . -name "*~" -print | xargs -n50 rm -f
( cd src; for dir in * ; do ( cd $dir ; make clean ) ; done )
rm -f dawglib.o debug.o rules.o stringlib.o *~
/bin/rm -f *.o tags core rpw destest des speed libdes.a .nfs* *.old 
    *.bak destest rpw des speed
rm -f *.o *~
`../../run/bin/freebsd-5-i386_/libc5.a' is up to date.
all made in util
Crack: The dictionaries seem up to date...
Crack: Sorting out and merging feedback, please be patient...
Crack: Merging password files...
Crack: Creating gecos-derived dictionaries
mkgecosd: making non-permuted words dictionary
mkgecosd: making permuted words dictionary
Crack: launching: cracker -kill run/Kgenisis.27478   
Done

Note that the word Done is a bit of a misnomer. The gecos test is finished, but the actual dictionary attack has just begun and is quietly perking along in the background:

# ps -acux | grep cracker
root      14013 97.0  2.8  9448 8916  v5  R    10:32AM   4:17.68 cracker

Monitoring the results

Let’s take a look at my current results, then analyze what is happening here:

# ./Reporter -quiet
---- passwords cracked as of Mon Nov 17 10:33:18 EST 2003 ----

1069099872:Guessed test [test]  User & [/etc/master.passwd /bin/csh]

---- done ----

The Reporter script, which is also found in the /usr/local/crack/ directory, sends the current results of the dictionary crack to standard output. I ran Reporter shortly after Crack had returned my prompt. Notice that it found that the password for the test account was test.

The reason why it found this password so quickly is because of the gecos field in /etc/master.passwd. If you’re familiar with man master.passwd, you know that the gecos field contains the user’s full name, possibly followed by her extension, office phone number, and home phone number. This means that if a user uses any of those values for a password, her password can be cracked within a second or two.

The actual dictionary attack will take a while to run. How long will depend upon the speed of your CPU. However, you should expect crack to run for a good portion of a business day.

Why so long? If you’ve ever had the opportunity to run a dictionary cracker on a non-Unix system, you may have had your results back in well under an hour. The answer is that BSD password hashes are protected by a salt. In simple terms, the salt adds random characters to a user’s password before the encryption algorithm creates the hash. Those are encrypted hashes, not the actual passwords, stored in /etc/master.passwd. In order for the password cracker to bypass the salt, it has to try many variations of the same word before it can determine if that word is indeed the user’s password.

You may want to write a script that will tell you when Crack is finished. Here is a simple example:

#!/bin/sh
#script to see if Crack is still running
#and to display current report

while ps -acux | grep -l "cracker" > /dev/null
do sleep 600
    echo "Still running. Here's the latest report:"
    cd /usr/local/crack && ./Reporter -quiet
done

echo "Execution is complete."

This script uses a simple while loop that runs every ten minutes (600 seconds). If cracker still shows up as a running process in the ps output, the ./Reporter -quiet script will run. Otherwise, the script ends, printing Execution is complete.

Tip

If you’d like to receive a pop-up message showing the results of the script, see [Hack #100] .

Cleanup

Your security policy should also provide guidelines on how to clean up after crack finishes. The program stores several working files in the run subdirectory. They will all have a numeric extension:

# ls run
D.boot.69783      Egenisis.69783    bin/
Dgenisis.69783    Kgenisis.69783    dict/

When you remove those files, ensure you leave the subdirectories intact:

# cd run
# rm *.69783

# ls
bin/    dict/

Customizing Password Dictionaries

Once you implement regular dictionary cracks, you’ll find that after a few months, your users will start to consistently choose strong passwords. However, bear in mind that a dictionary cracker is only as good as its dictionaries. The dictionaries that come with crack are a good start if your users speak English.

Let’s start by seeing what dictionaries crack included:

# ls dict/1/
abbr.dwg                        list.dwg
assurnames.dwg                  male-names.dwg
asteroids.dwg                   movies.dwg
bad_pws.dat.dwg                 myths-legends.dwg
biology.dwg                     names.french.dwg
cartoon.dwg                     numbers.dwg
chars.dwg                       other-names.dwg
common-passwords.txt.dwg        paradise.lost.dwg
crl.words.dwg                   phrases.dwg
dosref.dwg                      places.dwg
family-names.dwg                python.dwg
famous.dwg                      roget.words.dwg
fast-names.dwg                  sf.dwg
female-names.dwg                sports.dwg
given-names.dwg                 trek.dwg
jargon.dwg                      unix.dict.dwg
junk.dwg                        yiddish.dwg
lcarrol.dwg

Notice that each built-in dictionary ends with a dwg extension. However, crack understands any dictionary or word list, even if it is compressed (i.e., its filename ends in either .Z or .gz).

If you use the file command on the dwg files, you’ll find that each file is ASCII text. Mind you, the contents don’t look like the average dictionary file:

# head abbr.dwg
#!xdawg
02bon2b
04sa7ya
0bbroyg
6bvgw
0egbdf
0fsasya
0gok
0oottfogvh
0roygbiv

Don’t worry, those aren’t the actual words. Instead, the numbers sort the words by likelihood. That is, the words don’t appear in alphabetical order, but rather in the order they’re likely to appear as a password. For example, the word password is much more likely to be used as a password than pasul.

If your users speak other languages, consider downloading additional dictionaries. Start at the Cerias site mentioned at the end of this hack. It’s well worth your while to browse through the site’s dictionaries, local, and wordlists subdirectories looking for dictionaries that suit your particular needs.

Let’s go there now and check out the possible word lists:

# ftp ftp.cerias.purdue.edu
Connected to ftp.cerias.purdue.edu.
<snip long banner>
Name (ftp.cerias.purdue.edu:dru): anonymous
331 Guest login ok, send your complete e-mail address as password.
230 Logged in anonymously.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd pub/dict/wordlists
250 "/pub/dict/wordlists" is new cwd.
ftp> ls
227 Entering Passive Mode (128,10,252,10,169,45)
150 Data connection accepted from 1.2.3.4:49460; transfer starting.

-rw-rw-r--   1 ftpuser  ftpusers      1971 Jun 14  2000 README.gz
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 aussie
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 chinese
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 computer
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 danish
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 dictionaries
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 dutch
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 french
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 german
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 italian
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 japanese
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 literature
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 movieTV
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 names
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 norwegian
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 places
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 random
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 religion
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 science
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 spanish
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 swedish
drwxrwxr-x   2 ftpuser  ftpusers      4096 Jun 14  2000 yiddish
226 Listing completed.

My network includes several French-speaking users, so I’ll take a look at the French word list:

ftp> cd french 
250 "/pub/dict/wordlists/french" is new cwd.
ftp> ls 
227 Entering Passive Mode (128,10,252,10,175,158)
150 Data connection accepted from 1.2.3.4:49530; transfer starting.
-rw-rw-r--   1 ftpuser  ftpusers    332537 Jun 14  2000 dico.gz
226 Listing completed.

Before downloading the word list, I’ll use the local change directory command to ensure I’m downloading the file to the correct directory on my system:

ftp> lcd /usr/local/crack/dict/1
Local directory now /usr/local/crack/dict/1
ftp> get dico.gz 
local: dico.gz remote: dico.gz
227 Entering Passive Mode (128,10,252,10,175,160)
150 Data connection accepted from 1.2.3.4:49531; 
    transfer starting for dico.gz (332537 bytes).
226 Transfer completed.
332537 bytes received in 00:02 (142.24 KB/s)
ftp> bye 
221 Goodbye.

Now that I have a new word list in /usr/local/crack/dict/1/, I’ll run the following command:

# cd /usr/local/crack
# make rmdict 
# rm -rf run/dict

That’s it. The next time I run ./Crack, I’ll see the following message appended to the usual Crack message:

Crack: making dictionary groups, please be patient...
doing group 1...
doing group 2...
doing group 3...
mkdictgrps: uniq'ing dictionary groups...
group 1 and 2...
group 1 and 3...
group 2 and 3...
mkdictgrps: compressing dictionary groups...
Crack: Created new dictionaries...
Crack: Sorting out and merging feedback, please be patient...
Crack: Merging password files...
Crack: Creating gecos-derived dictionaries
mkgecosd: making non-permuted words dictionary
mkgecosd: making permuted words dictionary
Crack: launching: cracker -kill run/Kgenisis.55941   
Done

This indicates that crack has found the new dictionary and is merging it into its logic.

See Also

Create an Effective, Reusable Password Policy

Traditionally, it has been difficult for a Unix administrator to create and enforce a reusable password policy. Fortunately, PAM addresses this.

If you’re using FreeBSD 5.0 or higher, your system has a PAM (Pluggable Authentication Modules) module specifically designed to assist in the creation and enforcement of a reusable password policy. If you’re running a different version of BSD, see the end of this hack for other sources for this module.

Introducing pam_passwdqc

Before using this module, spend some time reading man pam_passwdqc, as it thoroughly covers each option and its possible values. Any values contained within parentheses are defaults. As you read through this manpage, compare those defaults with your own network’s security policy and make note of any values that will require a change.

This PAM module is fairly comprehensive, allowing you to enable many of the features expected in a password policy. Here’s an overview of the configurable features:

  • Minimum and maximum password lengths

  • Force a mix of digits, lowercase, uppercase, symbols, and non-ASCII characters

  • Minimum number of words in a passphrase

  • Minimum number of characters to consider as a string (dictionary word)

  • Ability to search for strings that are words written backwards, or are words written in a mix of upper- and lowercase

  • Check new password for similar string contained within old password

  • Suggest a randomly generated password

  • Setting to either warn about weak passwords or enforce strong passwords

  • How many times a user is allowed to retry setting a password if he fails to choose a strong password

Enabling pam_passwdqc

Once you’ve finished perusing the manpage, you should have a list of values that you’ll want to modify to reflect your network’s security policy. Enabling pam_passwdqc is simply a matter of adding or editing a line so that it contains your customized options.

On FreeBSD 4.x, add that line to the password section of /etc/pam.conf. On 5.x, edit instead the password section of /etc/pam.d/passwd. Let’s look at that file on a FreeBSD 5.1 system:

# more /etc/pam.d/passwd
# $FreeBSD: src/etc/pam.d/passwd,v 1.1 2002/04/15 03:01:31 des Exp $
# PAM configuration for the "passwd" service
# passwd(1) does not use the auth, account or session services.
# password
#password        requisite        pam_passwdqc.so        enforce=users
password        required        pam_unix.so        no_warn try_first_pass

Obviously, you’ll need to uncomment the pam_passwdqc.so line to enable the module. Note the one included option, enforce=users, overrides the default setting of enforce=everyone.

Let’s see what happens when I remove that remark and then try to use passwd as a regular user named test. Even though passwords aren’t echoed to the terminal, I’ve shown in this output the passwords that I typed in:

% passwd 
Changing local password for test
Old Password: test
You can now choose the new password or passphrase.
A valid password should be a mix of upper and lower case letters,
digits and other characters.  You can use an 8 character long
password with characters from at least 3 of these 4 classes, or
a 7 character long password containing characters from all the
classes.  Characters that form a common pattern are discarded by
the check.
A passphrase should be of at least 3 words, 12 to 40 characters
long and contain enough different characters.
Alternatively, if noone else can see your terminal now, you can
pick this as your password: "inward!smell:Milan".

As you can see, the password policy is provided, along with an example of a strong password that meets the policy requirements. Except for that one option, this particular policy includes the default settings mentioned in man pam_passwdqc.

Enter new password: test
Weak password: is the same as the old one.
Try again.

Here I tried to use the same password. Even worse, it doesn’t meet any of the password policy’s requirements. However, pam_passwdqc rejected the password, gave me another try, and patiently repeated the password policy along with another password suggestion:

You can now choose the new password or passphrase.
A valid password should be a mix of upper and lower case letters,
digits and other characters.  You can use an 8 character long
password with characters from at least 3 of these 4 classes, or
a 7 character long password containing characters from all the
classes.  Characters that form a common pattern are discarded by
the check.
A passphrase should be of at least 3 words, 12 to 40 characters
long and contain enough different characters.
Alternatively, if noone else can see your terminal now, you can
pick this as your password: "Sony,seed,cereal".
Enter new password: test1 
Weak password: too short.
Try again.

Well, I tried another variation of my old password, but it is still too short. Here we go again:

You can now choose the new password or passphrase.
A valid password should be a mix of upper and lower case letters,
digits and other characters.  You can use an 8 character long
password with characters from at least 3 of these 4 classes, or
a 7 character long password containing characters from all the
classes.  Characters that form a common pattern are discarded by
the check.
A passphrase should be of at least 3 words, 12 to 40 characters
long and contain enough different characters.
Alternatively, if noone else can see your terminal now, you can
pick this as your password: "torso&lotus_burly".
Enter new password: test1234
Weak password: not enough different characters or classes for this length.
passwd: pam_chauthtok( ): authentication token failure
%

Looks like the default retry count is three, as I was booted out after three tries. This time the password was long enough at eight characters, but only contained numbers and lowercase characters. The instructions clearly state that an eight-character password needs a mix of three different types of characters.

It’s important to note that if the superuser changes a user’s password, she will receive the same error messages if the password does not comply with the policy. However, after the error message, the superuser will be asked to retype that poor password and it will be accepted. Why? Because of that enforce=users option. If you remove that option, it will default back to enforce=everyone, which requires even the superuser to choose good passwords. The method you choose will depend upon the security requirements of your password policy.

Adding Your Own Options

It’s easy to change the default settings. Simply add your option to the end of the pam_passwdqc.so line. Then, test your change as a regular user to see what effect it has. You may want to create a test account for just this purpose.

For example, to force users to choose a password that is 10 characters long and a mix of uppercase letters, lowercase letters, numbers, and symbols, set N4 to 10 and disable the other options. Don’t know what N4 is? Better reread that section of the manpage before changing this parameter.

password  requisite  pam_passwdqc.so 
min=disabled,disabled,disabled,disabled,10

Or, to force users to use the randomly picked password:

password        requisite        pam_passwdqc.so        random=42,only

Here I’ve used the default random value of 42. You can experiment by increasing that number until the randomly generated passwords meet your strength requirements. Settings much higher than 70 may produce error messages; this is what the end user will see:

System configuration error. Please contact your administrator.
passwd: pam_chauthtok(1): authentication token failure

The superuser will see:

This system is configured to use randomly generated passwords
only, but the attempt to generate a password has failed. This
could happen for a number of reasons: you could have requested
an impossible password length, or the access to kernel random
number pool could have failed.
passwd: pam_chauthtok(1): authentication token failure

That’s your hint to choose a lower random number.

Once you’ve settled on a reasonable number, this is what users will see when they change their passwords:

% passwd
Changing local password for test
Old Password:

You can now choose the new password.
This system is configured to permit randomly generated passwords
only.  If noone else can see your terminal now, you can pick this
as your password: "lounge-mummy:cellar-dozen".  Otherwise, come back later.
Enter new password:

A user who hates that password can retry a few times to see other possibilities. Pressing Enter will generate another random password. Typing in anything other than the randomly generated password will cause the password change to fail.

Additional Configuration

You may have noticed that pam_passwdqc does not control how often a user is forced to change his password. Set this instead in /etc/login.conf. Besides the actual expiry period, you can also change the amount of advance warning users will receive about an impending password change.

If you make any changes to /etc/login.conf, test your changes by immediately logging in at another terminal. A typo in this file can prevent logins to a system!

For example, adding these lines to the default: section will set a password expiry of 30 days, giving 5 days warning:

:warnpassword=5d:
:passwordtime=30d:

Tip

If one of those entries happens to be the final entry in the default: section, don’t include the trailing in that last entry.

Don’t forget to rebuild the database once you’ve saved your changes:

# cap_mkdb /etc/login.conf

See Also

Automate Memorable Password Generation

Make it easier for your users to choose good passwords.

It doesn’t matter whether you’re an administrator responsible for enforcing a password policy or an end user trying to comply with said policy. You’re struggling against human nature when you ask users to choose—and remember—hard-to-guess passwords. Passwords that aren’t random are easy to guess, and passwords that are too random tend to manifest themselves on sticky notes under users’ keyboards or in their top drawers.

Wouldn’t it be great if you could somehow offer users random but memorable password choices? There’s a standard designed for just this purpose: APG, the Automated Password Generator.

Installing and Using apg

If you’re running FreeBSD, you can install apg from the ports collection:

# cd /usr/ports/security/apg
# make install clean

Once the port is installed, any user can run apg to generate a list of random, but pronounceable and memorable, passwords:

% apg -q -m 10 -x 10 -M NC -n 10
plerOcGot5 (pler-Oc-Got-FIVE)
fobEbpigh6 (fob-Eb-pigh-SIX)
Ekjigyerj7 (Ek-jig-yerj-SEVEN)
CaujIvOwk8 (Cauj-Iv-Owk-EIGHT)
yenViapag0 (yen-Viap-ag-ZERO)
Fiwioshev3 (Fi-wi-osh-ev-THREE)
Twomitvac4 (Twom-it-vac-FOUR)
varbidCyd2 (varb-id-Cyd-TWO)
KlepezHap0 (Klep-ez-Hap-ZERO)
Naccudhav8 (Nac-cud-hav-EIGHT)

Notice that each password comes with a pronunciation guide, since it’s easier to remember something you can pronounce.

Also, note that syntax. We’re definitely going to have to do something about all of those switches! But first, let’s take a look at Section 3.2 and make sure we understand them.

Table 3-2. apg switches

Option

Explanation

-q

Suppresses warnings (think quiet), which will be useful when we write a script

-m 10

Sets the minimum password length to 10 characters

-x 10

Sets the maximum password length to 10 characters

-M NC

Requires numerals and capitals

-n 10

Generates 10 password choices

While this utility is very handy, we can definitely hack in our own improvements. For starters, users aren’t going to use a utility that requires a line’s worth of switches. Second, we don’t want to install this utility on every system in our network. Instead, let’s work out a CGI script. That way users can access the script from their web browsers.

Improving apg

First, let’s sort out all of the switches we’ll use in the script. We need something to add a punctuation character in the middle, or we won’t meet Air Force password regulations. The simplest fix is to run apg twice with smaller password requirements, concatenating the results. The first run, without punctuation characters, looks like this:

% apg -q -m 4 -x 4 -M NC -E Ol -n 10
Dij6 (Dij-SIX)
Voj6 (Voj-SIX)
Pam0 (Pam-ZERO)
Dev9 (Dev-NINE)
Non6 (Non-SIX)
Eyd7 (Eyd-SEVEN)
Vig9 (Vig-NINE)
Not8 (Not-EIGHT)
Nog2 (Nog-TWO)
Von9 (Von-NINE)

Here I’ve reduced the minimum and maximum password length to four characters. I’ve also added the option -E Ol to exclude capital “oh” and small “ell” from passwords, because they’re easily confused with the digits zero and one.

The second run includes the -S option, which makes the password generator use special characters:

% apg -q -m 4 -x 4 -M S -E Ol -n 10
orc) (orc-RIGHT_PARENTHESIS)
tof| (tof-VERTICAL_BAR)
fed^ (fed-CIRCUMFLEX)
gos@ (gos-AT_SIGN)
sig& (sig-AMPERSAND)
eif) (eif-RIGHT_PARENTHESIS)
eds{ (eds-LEFT_BRACE)
lek> (lek-GREATER_THAN)
tij: (tij-COLON)
rot] (rot-RIGHT_BRACKET)

Now for a CGI script to paste the results together. I’ve numbered each line of the script for explanation purposes. Don’t include line numbers when you create your own script.

This script is written in the Korn shell, but can be modified for any shell. To run as is, install the Korn shell from /usr/ports/shells/ksh93.

1  #!/bin/ksh
2  # run apg twice, concatenate results.
3  # exclude most special characters requiring shift key,
4  # capital "oh" (looks like zero),
5  # lowercase "ell" (looks like digit "one")

6  PATH=/bin:/usr/bin:/usr/local/bin; export PATH
7  umask 077

8  a=/tmp/apg.$RANDOM
9  b=/tmp/apg.$RANDOM

10  cat << EOF
11  Content-type: text/html

12  <!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
13  <html>
14    <head>
15      <title>Help generating a new password</title>
16    </head>

17    <body>
18      <h3>Help generating a new password</h3>

19      <blockquote>
20        These passwords should be reasonably safe.
21        Feel free to use one, or reload the page
22        for a new batch.</p>
23        <blockquote> <pre> <font size="+1">
24  EOF

25  apg -q -m 4 -x 4 -M NC -E '!@#$%^&*( )' -n 10 > $a
26  apg -q -m 4 -x 4 -M S  -E '!@#$%^&*( )' -n 10 > $b

27  # tr command is for bug workaround; apg is not supposed to
28  # include characters specified after -E option.

29  paste $a $b |
30      tr 'l' 'L' |
31      awk '
32        BEGIN {
33          printf "Password	Rough guess at pronunciation
<hr />"
34        }
35        {
36          printf "%s%s	%s %s
", $1, $3, $2, $4
37        }'

38  cat << EOF
39        </font>
40        </pre>
41        </blockquote>
42      </blockquote>
43      <hr />
44    </body>
45  </html>
46  EOF

47  rm $a $b
48  exit 0

Script Walkthrough

Line 6 sets the PATH to a known safe value. This lessens the possibility that an attacker can cause this program to execute a hazardous binary. Make sure apg is in this path.

Line 7 sets the umask so that only this user can read the temporary files to be generated later.

Lines 8 and 9 work because Korn shell scripts generate random numbers automatically. If /bin/ksh is not on your system, use mktemp to generate temporary files safely.

Lines 10-24 print the page header. I usually make a sample page and then run it through /usr/ports/www/tidy to get a decent DOCTYPE header and indentation.

Lines 25 and 26 issue apg commands to generate two separate files containing four-character passwords.

Lines 31-37 use an awk script to print the password plus its pronunciation. The BEGIN section prints only once, before any lines are read. The printf section expects lines with four fields: two pairs of password and pronunciation strings from the temporary files. The first and third fields are printed together to form the password, and the second and fourth fields are printed together to form the pronunciation guess.

Lines 38-46 finish the page.

Lines 47 and 48 clean up the temporary files.

See Also

Use One Time Passwords

Sometimes even a complex password may not meet your security needs.

If you are on the road and need to access the corporate network from a non-secure computer in a public place, the risk of password leakage increases. Could the person next to you be shoulder surfing, watching as you log into the network? Does the computer you’re using have some sort of installed spyware or keystroke logger? Is there a packet sniffer running somewhere on the network? In such a situation, a One Time Password can be a real lifesaver.

Configuring OPIE

FreeBSD comes with OPIE, or One-time Passwords In Everything, a type of software OTP system. It is easy to configure and doesn’t require any additional hardware or proprietary software running on a server. Ideally, you should configure OPIE before leaving your secure network. For example, if you plan on traveling with your laptop, configure OPIE while connected to the office network. Make sure you are logged in as your regular user account to the particular system you’ll need to access while on the road.

Start by adding yourself to the OPIE database, or /etc/opiekeys, using opiepasswd. If you intend to access your workstation while on the road, run this command while physically sitting at your workstation. Include the console switch (-c) to indicate you are at that station’s console, so it is safe to enter a passphrase:

% opiepasswd -c
Adding dru:
Only use this method from the console; NEVER from remote. If you are using
telnet, xterm, or a dial-in, type ^C now or exit with no password.
Then run opiepasswd without the -c parameter.
Using MD5 to compute responses.
Enter new secret pass phrase: 
Secret pass phrases must be between 10 and 127 characters long.
Enter new secret pass phrase: 
Again new secret pass phrase: 

ID dru OTP key is 499 dh0391
CHUG ROSA HIRE MALT DEBT EBEN

See that warning at the beginning? If you don’t have physical access to the system’s keyboard—say, you’re logging into a server—make sure you use ssh to log into that system before running the opiepasswd -c command. Your only protection from another user using your one-time password is your passphrase, which is basically a long password that can include spaces. If that passphrase is transmitted over the network in clear text, you’ve defeated the whole purpose of this exercise.

Note that the passphrase isn’t used as a password per se; instead, it is used to prove who added the account to the database and is therefore the rightful owner of the resulting response or one-time password. You’ll need to issue that passphrase whenever you need to view your responses. Responses are always comprised of six uppercase nonsense words.

Next, verify that you are indeed in the OPIE database:

% opieinfo
498 dh0391

The opieinfo command displays the count (498) that will be used at the next login. It will also display the seed associated with that count (dh0391). In this example, it is expecting the response associated with 498, but I only know the response for 499. I’ll need to use an OTP password calculator to figure out the correct response; that calculator is really just the opiekey command.

You could use the calculator from a separate terminal every time you login, but it is usually more convenient to print a list of responses and regenerate a new list whenever you run out of responses.

Generating Responses

In order to use the calculator, you need to know three things:

  • Your current counter

  • Your seed

  • Your secret passphrase

The challenge at the login prompt will display the current counter and seed. However, it is important that only you know your secret passphrase. Otherwise, anyone could calculate the response and log into your account.

To generate a list of responses, use the number switch (-n), followed by the number of desired responses and your current count and seed:

% opiekey -n 5 498 dh0391
Using the MD5 algorithm to compute response.
Reminder: Don't use opiekey from telnet or dial-in sessions.
Enter secret pass phrase: 
494: MEAN ADD NEON CAIN LION LAUD
495: LYLE HOLD HIGH HOME ITEM MEL
496: WICK BALI MAY EGO INK TOOK
497: RENT ARM WARN ARC LICE DOME
498: LEAD JAG MUCH MADE NONE WRIT

You can either direct that output to a printer or record those responses by hand. Either way, store those responses in a safe place such as your wallet, as these are your next five one-time passwords. The next time you log in, use the response that matches the count at your login prompt:

login: dru
otp-md5 498 dh0391 ext
Password: (here I pressed Enter)
otp-md5 498 dh0391 ext
Password [echo on]: LEAD JAG MUCH MADE NONE WRIT

Once you configure OPIE on a 5.1 FreeBSD system, you will be required to respond to the OTP challenge whenever you log into that system. If you press Enter, you’ll turn on echo so you can see the response as you type it.

Echo is usually a bad thing when logging in because anyone can see your password. However, with a one-time password, it doesn’t matter if anyone sees that password, as it can’t be reused. Also, unlike a reusable password, the response is not case-sensitive, so it doesn’t matter if you type it in upper- or lowercase. Do take care, though, that no one sees your list of responses or your passphrase.

If your counter gets low—say, 10 or less—reset it before it hits 0. Use opiepasswd again, but this time specify a new count and a new seed. Here I’ll use a count of 499 and a new seed of dh1357:

% opiepasswd -n 499 -s dh1357
Updating dru:
You need the response from an OTP generator.
Old secret pass phrase:
        otp-md5 8 dh0391 ext
        Response: loot omit safe eric jolt dark
New secret pass phrase:
        otp-md5 499 dh1357
        Response: hewn as dot mel mali mann

How long it will take you to cycle through your OTP passwords will depend upon how often you need to log in. You may find it convenient to generate a week’s worth of responses at the beginning of each week.

It’s also a good idea to consider how often to change your passphrase. You’ll be prompted to when you reset your counter. For example, if you plan on changing your passphrase every 100 responses, specify -n 100 when you run opiepasswd. The passphrase itself needs to be memorable. Fortunately, it can contain spaces, so you can input, say, a line from a song or a poem.

Choosing When to Use OTP

Starting with FreeBSD 5.1-RELEASE, users are forced to use OTP once they’ve added themselves to the OPIE database. It doesn’t matter if the user logs into that system using a local keyboard or over the network using ssh. This behavior is controlled by PAM, or, to be more specific, the auth section of /etc/pam.d/login:

% more /etc/pam.d/login
#
# $FreeBSD: src/etc/pam.d/login,v 1.11 2002/05/08 00:33:02 des Exp $
#
# PAM configuration for the "login" service
#

# auth
auth    required      pam_nologin.so      no_warn
auth    sufficient    pam_self.so         no_warn
auth    sufficient    pam_opie.so         no_warn no_fake_prompts
auth    requisite     pam_opieaccess.so   no_warn
#auth   sufficient    pam_kerberosIV.so   no_warn try_first_pass
#auth   sufficient    pam_krb5.so         no_warn try_first_pass
#auth   sufficient    pam_ssh.so          no_warn try_first_pass
auth    required      pam_unix.so         no_warn try_first_pass nullok
snip

Perhaps you’d like users to have the option of using their regular password when logging in locally, but force them to use OTP when logging in over the network. To achieve that, add the allow_local option to the opieaccess line so it looks like this:

auth    requisite    pam_opieaccess.so    allow_local no_warn

This option lets the user type either her regular password or her OTP response if she’s logging in locally. However, if she’s logging in over the network, the login attempt will fail unless she gives the correct OTP response.

See Also

  • man opiepasswd

  • man opieinfo

  • man opiekey

  • man pam_opie

  • /usr/share/doc/en_US.ISO8859-1/articles/pam/article.html (FreeBSD PAM documentation)

Restrict Logins

In this chapter, we’ve covered many methods of securing the boot and login environments. It’s probably no surprise that you can further control who can log into your system and when: Unix systems contain many built-in mechanisms, allowing you to choose the most appropriate means and policy for your network.

Furthermore, the defaults may not always suit your needs. Do you really want users to be logged into multiple terminals when they can effectively do their work from one? For that matter, do you want any user, including nonemployees, to try his hand at logging into your systems at any hour of the night and day? Here’s how to tighten up some defaults.

/etc/ttys

Since users log into terminals, a logical file to secure is the terminal configuration file, /etc/ttys. We briefly saw this file in [Hack #25] when we password protected single-user mode.

This file is divided into three sections, one for each of the three types of terminals. Let’s concern ourselves with the virtual terminals, ttyv, which are the terminals available for users physically seated at the system’s keyboard.

# grep ttyv /etc/ttys
ttyv0      "/usr/libexec/getty Pc"             cons25        on  secure
ttyv1      "/usr/libexec/getty Pc"             cons25        on  secure
ttyv2      "/usr/libexec/getty Pc"             cons25        on  secure
ttyv3      "/usr/libexec/getty Pc"             cons25        on  secure
ttyv4      "/usr/libexec/getty Pc"             cons25        on  secure
ttyv5      "/usr/libexec/getty Pc"             cons25        on  secure
ttyv6      "/usr/libexec/getty Pc"             cons25        on  secure
ttyv7      "/usr/libexec/getty Pc"             cons25        on  secure
ttyv8      "/usr/X11R6/bin/xdm -nodaemon"      xterm        off  secure

The word on indicates that that terminal is available for logins. By default, the first eight terminals, ttyv0 through ttyv7, will accept logins. You’ve probably discovered this yourself by pressing Alt-Fx, where x is a number between 1 and 8. On a server system, you may need only one virtual terminal. Disable the other terminals by changing the word on to off.

Warning

If the system is running headless [Hack #26] , disable all of the virtual terminals only after you’ve ensured that you have an alternate way to access the system.

The word secure means that the system is physically secure, implying that it’s okay for a user to walk up to the keyboard and log in as root. Since it’s never okay for a user to log in as root, you should disable that default. For whatever virtual terminals you’ve left on, either change the word secure to insecure or simply remove the word secure.

Warning

Be careful when editing /etc/ttys. A typo could prevent logins to your system. Always log in from another terminal before making changes, and test your changes immediately before logging out.

/etc/login.access

Now let’s see what can be done with /etc/login.access. At its most stringent, you can use this file to prevent all remote logins, meaning you can log in only if you are physically sitting at that system:

-:ALL:ALL EXCEPT LOCAL

Note the syntax that is used for each line in this file. The - means access denied. Its alter ego is +, which means access granted. The first ALL is a wildcard for all users. The second ALL is a wildcard for all locations. The EXCEPT LOCAL is the exception that allows just the local location.

You could modify that rule slightly to disallow remote and local root logins:

-:root:ALL

Take some care when modifying this file. Its syntax supports both user and group names, allowing you to specify exactly who is allowed to log into a system. This can be extremely useful in limiting access to a server system.

The syntax also supports IP addresses. This can also be useful in ensuring that only hosts in your network or a particular subnet can access certain systems. But, as in any security mechanism that relies on IP addresses, do keep in mind that IP addresses can be spoofed.

Finally, if you make changes to this file, test your changes immediately. If you restrict access to certain users, ensure those users can still log in. Further, try to log in as other users to ensure that they are actually being denied access.

/etc/ssh/sshd_config

Think for a moment. Other than logins to virtual terminals, how else do your users log into systems? Most likely (and, hopefully) through ssh. You can control exactly who can ssh into a system by adding a line to the /etc/ssh/sshd_config file of the system running the SSH daemon.

There are two ways you can control this. One is through AllowGroups. By default, all groups—meaning all users—can ssh into a system. The other way is through AllowUsers, where again, all users are allowed by default.

Suppose I want to allow only the users genisis, biko, and dru to ssh into a particular system. I could create a group called remote that contains those users:

# grep 100 /etc/group
#
# pw groupadd remote -g 100 -M genisis biko dru

In this example, I first double-checked that the group ID of 100 was not currently in use. I then created, with pw groupadd, the remote group with a GID of 100 (-g 100) and with those three members (-M genisis biko dru).

Now I can limit ssh access to just the members of that group:

# echo 'AllowGroups remote' >> /etc/ssh/sshd_config

Alternatively, I could have just added those three users directly:

# echo 'AllowUsers genisis biko dru' >> /etc/ssh/sshd_config

Any user who does not match either AllowGroups or AllowUsers will still receive a password prompt when attempting to connect to the SSH daemon. However, the connection attempt will fail with a permission denied message, even if the user provides a correct username and password. The SSH daemon will print a message regarding the failed attempt to its console, sending a copy to /var/log/messages and emailing to root as part of the daily security run output.

To be even pickier, if your users always log in from the same system, you can do this:

AllowUsers [email protected] [email protected] [email protected]

However, don’t be that picky if your users don’t have static IPs!

Remember, if you make any changes to the SSH daemon’s configuration file, you’ll need to send a “signal one” to sshd to notify it of the changes:

# killall -1 sshd

After informing sshd of the changes, immediately use a ssh client to test your changes. For example, if I instead add the line Allowusers genisis biko dru, I’ll find that user nastygirl is still able to connect. Why? The parameters in /etc/ssh/sshd_config are case-sensitive. You don’t want to find out six months later that anyone was allowed to connect when you thought you had restricted connections to certain users.

/etc/login.conf

We’ve restricted who can log in and from where for both local and remote ssh logins, but we still haven’t restricted when those users can log in. To do that, let’s look at some other options that are available in our old friend /etc/login.conf [Hack #29] .

This file supports the options times.allow and times.deny. For example, to allow all users to log in between 9:00 AM and 5:00 PM every Monday through Friday, add this line to the default: section:

:times.allow=Mo-Fr0900-1700:

Once you introduce the times.allow option, access will automatically be denied for the time period not listed.

The converse also works. That is, you can specify the denied times in times.deny, and all other times will be allowed.

Remember, whenever you make a change to /etc/login.conf, rebuild the database with cap_mkdb /etc/login.conf and test your changes.

See Also

  • man ttys

  • man login.access

  • man sshd_config

  • man login.conf



[1] CMOS is battery-powered memory that holds system settings such as the time, date, and system configuration.

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

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