Home -> Library -> Hardening -> BSD Home
Articles on how to Securing/Hardening BSD


Hardening BSD


Hardening BSD is definitely trickier than hardening a Linux based workstation being that the top 3 distributions of BSD, Net, Open, Free, have done an excellent job of strengthening the systems on their own. Using FreeBSD at home while I write this, I'll try to focus in on it, but in general (and I may get flamed from the OpenBSD advocates or even NetBSD advocates) you could follow suit between the three. (Dare I say it) FreeBSD does its daily audit via way of /etc/periodic/daily/$SCRIPTS which are run to ensure some integrity is met on the machines however after installing third party programs, you're going to lose some of the integrity you could otherwise expect on a default install.


USERS HAVE NO RIGHTS
At least to a BOFH they have no rights. One of the things I've done is sorted programs which I added into their genre, such as: I have a networking group of binaries running, sysadmin group of binaries running, and I'm sure many can see where I'm going with this. After sorting through the add-ons, and separating them into their own respective directories, I created separate groups for them. Methods of thinking in this fashion were a bit simple; Should someone find a way around the program to escalate their priveledges, I wanted to isolate them into only having perms of that group, however I wouldn't want them escalating via another problem within that group.

Well lets say this in english terms: Say I have Netsaint, Portsentry running both as GID wheel, and someone leveraged Portsentry to escalate their priveledges. Now Portsentry say has only X amount of access being in the wheel group, but is owned by user portsentry, now Netsaint also in the wheel group has access to more since his UID is of root because I never took the time to install properly, whatever case. Simple explanation?

Well it may sound off base here, and I could be completely wrong, but personally I don't want to take any chances with my system, so in essence I divided binaries into their genre, created a GID for 4 different groups which would only have access to their respective programs, without being able to cross between each other. This in my mind ensures me that no one is going to be able to go digging should I forget to administrate my machine, or should I go on vacation, or $INSERT_YOUR_EXCUSE_HERE.

So what about those programs I need to run as root? Well since it does become tedious to keep reading those messages telling me X program needs to run as root, or other perm error messages, I created a simple if script which I enter the name of the script to run, check to make sure I have perms on it, and if not chmod it for me, run whatever, then change it back after I'm done running it. This script is in a directory owned by root, readable to no one but root, which can only be run as root or by someone with sudo priveledges to run. On my personal machine /sbin, /usr/sbin, and /usr/local/sbin cannot be accessed by anyone aside from root, and those who have sudo privs. Personally I feel no user should access anything in those directories by any means, and yes even at home I've made it a practice to use sudo even though no one has an account on my machine whatsoever.

Now these examples aren't feasible to those who have to care for a large network though so another method of safeguarding your system from users would be to use sudo, and monitor users' actions, and I wish to emphasize to those unfamiliar with sudo, this is one of the best programs to use on your machine, for auditing users' actions, and for safeguarding your root account which in my opinion no one should have but the administrator/owner of the machine. Should you have 10 administrators complaining about having to use sudo, then you should seek out those who know the value of keeping a secure machine running, who'll respect the fact you've chosen to have them use sudo as opposed to just distributing the root password.


Who's running what
Do you know what's running on your system, who owns the process, and why is it running? Often left unchecked, especially on a large network, are the programs running on a system. What's more important is who is running that program and why.

ps -aux|awk '{print $1, $11}' | sort | uniq

By taking a close look at what's running, an administrator can ensure that only processes that are supposed to be running, are running, and being run by the proper user. I created an alias called "chu" (check user) which does this for me. Bottom line is, I want to know that nothing out of the ordinary is occurring. This does little should someone have backdoored ps to hide their actions, but if you have something like Tripwire, or FreeVeracity running, or even a simple echo `which ps` | md5 >> /mnt/floppy/checksums, you could rest a bit easier knowing ps is safe.

We know keeping tabs on many users is difficult, but we also know if things, are done the right way from the ground up, you'll save yourself a large amount of time, and headaches in the long run, should things get `borked'. Groups, groups, groups... I've seen many servers with little usage of groups being taken advantage of. Groups are simple and should be self defined when you think about them, you have X amount of people who need to access X amount of programs/files, while other other amounts of users who don't need to access the same files as one another, and vice versa, solution, create a group for say the gaming group who only needs to access /usr/local/games or a group called devel for those who need to access /usr/include it truly is that simple, and yet so many get it wrong.

Personally I would rather take an extra 5 minutes setting things up in this fashion, then taking a few hours assessing the damage done to my machines, because I overlooked some procedures I could have taken to prevent anything from happening. As for services, and identd, the same rules apply as were stated on the Linux version of this document, so I won't rewrite anything on this subject. Yes we could have written scripts to do most of the tasks neccessary to check things for you, but this does not offer an understanding of how something is done, educating someone we feel or at least we hope is the better method to use.

I also added the following options to my kernel:

options IPFIREWALL_VERBOSE
options IPFILTER
options IPFILTER_LOG
options TCP_DROP_SYNFIN
options TCP_RESTRICT_RST
options ICMP_BANDLIM


These options should speak for themselves so I see no need to describe them, and one should look into getting familiar with compiling their kernels. First option allows the firewall to print output, second enables IPFiltering, while the third enables logging for it. Fourth drops SYN+FIN packets from coming into the machine, fifth restricts RST packets from coming in, and the final limits the amount of ICMP packets from coming in, 4th, 5th, and 6th lower the possibilities of DoS attacks affecting your machine. Removing some of the things you don't have on the machine is also a plus since your machine will load faster at boot time.


Trusted, Secure, Open, Free, Net So many choices so little time to tinker with them all. We don't want to get into an all out holy war over distributions here, and I've poked fun at just about all of them, with my FreeBSD spoof, OpenBSD fake advisory email, you name it we've done it. For the record though I started using FreeBSD, moving to Linux for a short time, switching to OpenBSD, then back and forth between Open and Free. Reasons for the madness was simple, my employers were already using FreeBSD, and I've been using OpenBSD since v 2.2, plus OpenBSD is what this site is running currently. (v 2.8 for those who'll run over to Netcraft to peek at it, why bother we have powered by OpenBSD buttons all over the place.)

"Advice is generally a drug on the market, because it is so often passed on from dope to dope." If your looking for strong security, and hardcore crypto support, than the choice is OpenBSD which wins hands down. If your looking for a secure OS in general, the truth of the matter is, an OS is only as secure as the administrator who hardened it. Listen I don't care if your running Free, Open, SecureBSD over Free, etc., if you don't know what your doing, those distributions can be as insecure as a clean install of (eek dare I spell it) Windows NT, and that is the bottom line.

OpenBSD is my favorite since I favor crypto, and I also enjoy the fact that I could quickly install it, leave it as is without having to worry about it. It is also my favorite choice for running IPF on a network that's clustered into groups of servers, since I see purchasing a firewall for every single group of servers is overkill Even better looking for this is emBSD or Embedded BSD.

Personally I haven't used Trusted, and its been some months since I configured a SecureBSD based server so there's not much I can add here, it all boils down to your needs, so any argument can go on for hours about which is best, and why. You be the judge of that. Personally I use both Free, and Open, and am happy using both, and accomplish whatever it is I'm trying to do with both.

Well we just want to touch off on things briefly, and we've found the following already written documentation clarifies all of the things we wanted to say on our own. It's definitely more informative than anything I could have written so here it is unaltered. (grewvy now no one can flame me for not writing RFC based material, and taking my time here...)


--------------------------------------------------------------------------


If there are any questions or comments, please direct them to
walt@erudition.net. The
newest copy of this HowTo can always be retrieved from
www.freebsd-howto.com. All rights
for the reproduction of this document are reserved.

Summary.

This HowTo deals with BSD Login Classes as they are implemented in FreeBSD 3.x systems. Login Classes are powerful administration tools that allow one to maintain extensive control over user resources limit issues, environment settings issues, authentication issues, and session accounting issues.

1. Background
2. Implementation

2.1. "default" Login Class in Depth

2.1.1 Structure of a Login Class
2.1.2. Examining Capabilities in "default" Login
Class

2.2. Additional Useful Capabilities

2.2.1. Environment Capabilities
2.2.2. Authentication Capabilities
2.2.3. Accounting Capabilities

2.3. The "tc" Capability
2.4. Current and Maximum Capabilities

3. Sample Login Class
4. Appendix

1. Background

BSD systems all support a complex and powerful method for controlling collections of users called "login classes." Following the GID field in the master.passwd file, is the login class field, specifying the name of the login class to which the user belongs. Alternatively, the field can be left blank to exclude the user from any login class (which includes the user into the "default" login class by default).

For instance, in the following sample /etc/master.passwd entry, the user
belongs
to the login class "restricted:"

boff:$1(fjertrIyu:1001:1001:restricted:0:0:Boff:/home/boff:/bin/zsh

The login class field can be edited with vipw.

The main system configuration file for login classes is /etc/login.conf. The format of the file may seem difficult at first glance, but after closer examination, it will become clear. All users that are not specified as part of a login class, that is, the login class field in their master.passwd entry is blank, are by default included in the "default" login class. The following is an example of a "default" login class similar to what you may find in /etc/login.conf:

default:\
:copyright=/etc/COPYRIGHT:\
:welcome=/etc/motd:\
:setenv=MAIL=/var/mail/$,BLOCKSIZE=K:\
:path=~/bin /bin /usr/bin /usr/local/bin /usr/X11R6/bin:\
:nologin=/var/run/nologin:\
:cputime=unlimited:\
:datasize=unlimited:\
:stacksize=unlimited:\
:memorylocked=unlimited:\
:memoryuse=unlimited:\
:filesize=unlimited:\
:coredumpsize=unlimited:\
:openfiles=unlimited:\
:maxproc=unlimited:\
:priority=0:\
:umask=022:

We will quickly examine each line of the "default" login class, and then in the following sections review additional options, and in the final section, create a sample "restricted" login class that will enforce strict policies so as to lessen the possibility of a user misbehaving and lessening the chance that misbehaviour will cause damage to the system.

2. Implementation

2.1. "default" Login Class In-Depth

2.1.1. Structure of a Login Class

The first thing to be noticed is the somewhat unusual syntax of a login class. The name of the login class ends with the suffix ':\' as do all options within the login class, except for the last. Specifically, the type of format used by login.conf(5) is called a "Capabilities Database." Specific information on the structure and semantics of Capabilities Databases can be acquired in the man page for getcap(3). In short, the following semantic rules for a Capabilities Database one should be acquainted with to clearly read login.conf(5):

a) The name of the entry can have aliases. The first alias of an entry should be the shortest version of the name, which is used for ease of spelling, and the final alias should be a long, descriptive version, which may include spaces and upper and lower case for readability. Each alias is separated by a '|'. For instance:

simpu|Simple Login Class:\
:cputime=unlimited:\
:datasize=unlimited:

In the above example, the name of the login class has two aliases:
"simpu" and "Simple Login Class." The first is for use in specifying the users' login class in the master.passwd file, and the last is a descriptive version of the login class, which quickly allows the reader understand what it is. Both aliases are valid names for the login class, and both can be used in master.passwd, however, the shorter/simpler is preferred for use in master.passwd for obvious reasons. A long descriptive version is recommended for all entries so as to allow the administrator to quickly know its purpose.

b) The '\' which terminates every line, except the last (as it has
nothing to
continue after it) is a symbol indicating 'to continue the previous line', just as it would be used in any shell or command prompt line which gets very long. A Capabilities Database consists of a first capability (field/entry; henceforth, each field within a login class will be referred to as a 'capability') indicating the name, with '|\ separated aliases, and then in turn followed by ':' separated fields containing the capabilities. Because a single line, wrapping around, with a couple dozen options would be difficult to read, the fields are broken into separate lines with a trailing '\'.

c) Each capability on a separate line must begin and end with a ':', nd as stated above, finally terminate with a '\' unless it is the last line.

Knowing these three general syntax rules, one can easily understand and read the structure of any login class in login.conf(5).


2.1.2. Examining Capabilities in "default" Login Class


Next, let us examine, one by one, each of the capabilities in the default login class. We will quickly observe that it is very loose its resource allocation.

The first capability specifies a copyright file with additional copyright information to be displayed during login for all users defaulted to the "default" login class:

:copyright=/etc/COPYRIGHT:\


The second capability specifies what the message of the day file will be, in this case, the default being the familiar /etc/motd:

:welcome=/etc/motd:\

The third capability specifies two environment variables: MAIL and BLOCKSIZE:

:setenv=MAIL=/var/mail/$,BLOCKSIZE=K:\

The MAIL environment variable specifies the directory where incoming user mail is stored. Notice the '$' in the path specified for MAIL. When specifying environment variables, all instances of '$' are replaced with the user's name, and '~' are replaced with the user's home directory.

The BLOCKSIZE environment variable will specify the block size with which various utilities will display disk usage information. The default is 512B blocks. The above capability sets it to 'K', an alias for 1024B. Utilities such as df(1) and du(1) use this environment variable when displaying information in blocks.

Note: that any environment variable set in the login class may be over-written by settings in the users' shell init files.

The next capability in the "default" login class sets the users' search PATH:

:path=~/bin /bin /usr/bin /usr/local/bin /usr/X11R6/bin:\

Each search path is separated by a space. Once again, it may be over-written by the PATH being reset to something else in the users' shell init files.

The next line is an interesting one. It specifies a file to display and then terminate the login session:

:nologin=/var/run/nologin:\

However, as you may have noticed, not specifying a login class for a user in master.passwd, causing the user's login class to default to "default," doesn't disable the user's ability to login. As it stands, this line will only disable users in the "default" login class from logging in if the specified file exists - which if it did, it would be displayed prior to disconnecting the login attempt. Because the base FreeBSD system does not include a /var/run/nologin, users in the "default" login class with the "default" settings given above are still able to log in. This line (I presume) is for demonstrative purposes and not to actually disconnect the users in the "default" login class; specifically, to suggest to the administrator that any user not specified within a special login class should be treated sternly if defaulted to "default."

Next we come to important resource control capabilities. The first of these defines the total cpu time that the user can use:

:cputime=unlimited:\

For most purposes, it is unnecessary to restrict this resource, and indeed, in many instances, if one is running a shell server, for instance, it is undesirable to put a max time limit that a user's process can run.

Note: that in a number of capabilities the keyword "unlimited" is used. It is a special reserved term to specify that 100% of the particular resource in question
can be used up by the user's processes.

Aside from the keyword "unlimited," time notation is done in digits, followed by a units indictator. We will cover the units table in depth later in the HowTo.

Following "cputime" we have "datasize" specified in the "default" login class. It defines the maximum data size that that user can have:

:datasize=unlimited:\

It will affect "anonymous memory" allocated by processes with the malloc() family of functions, array initialization, etc. For more information on "anonymous memory" see Swap-HOWTO at www.freebsd-howto.com. Clearly, lest one submit oneself to the possibility of a user's processes monopolizing the system's memory, this resource should be limited
accordingly.

The "datasize" capability, aside from the "unlimited" keyword, is defined in
units of size. The following size units are valid:

b explicitly selects 512-byte blocks
k selects kilobytes (1024 bytes)
m specifies a multiplier of 1 megabyte (1048576 bytes),
g specifies units of gigabytes, and
t represents terabytes.

For instance, if all processes of user within a particular login class were to have their maximum potential data sizes (memory usage) capped at 5.5 megabytes,
the following capability would suffice:

datasize=1m500k:\

The capability after "datasize" defines the "stacksize" limitations. Stacks are ubiquitous data structures in programs, utilities, daemons, and if grown too large, may also use a considerable amount of memory. The capability in the "default" login class for "stacksize" defines it as "unlimited" as well:

:stacksize=unlimited:\

The "stacksize" capability is also managed in size units as the "datasize" capability as.

The proceeding two capabilities in "default" are:

:memorylocked=unlimited:\
:memoryuse=unlimited:\

They both limit similar memory use aspects of running processes; and, like the previous two capabilities, the prudent administrator would not allow "unlimited" use of memory. Here, the administrator has direct control over the amount of memory space that a user can use up at maximum. Both of these entries use the "size" units of measure.

Next, we come to defining the maximum file size allowed by the users in the login class:

:filesize=unlimited:\

The "filesize" capability just as the previous capability, is defined with "size" units. Likewise, the next capability which defines the maximum possible coredump
size uses "size" units:

:coredumpsize=unlimited:\

Following the "coredump" capability is the "openfiles" capability:

:openfiles=unlimited:\

It, as it suggests, defines the maximum number of possible simultaneously
open files by
a process. Next comes an important one:

:maxproc=unlimited:\

Also rather intuitively apparent, its purpose is to limit the maximum amount of processes allowed by the user. This is extremely important as it can subvert fork() type Denial of Service attacks committed by malicious users, as well as controlling whether the user stays close to the number of processes that their account allots him/her. As such, it is strongly suggested that the prudent administrator restrict the limit for "maxproc" down from the default unlimited state.

The next capability specifies the priority at which the users' processes
will run by
default:

:priority=0:\

The priority of a process can be modified with commands such as nice(1),
rtprio(1) and
idprio(1).

The last line sets the umask for all users in the login class:

:umask=022:

In short, the umask is the inverse of the default permissions that will be used for all newly created files by the users. That is, subtracting the umask from 777 will result in the permissions for default created files. 022 is the standard umask, but adjust this as
need be.

Note: shell init files may - and probably will - reset this value.

2.2. Additional Useful Capabilities

There are many additional login class capabilities to the ones covered above. Let us cover a number of these additional ones in three groups: Environment Capabilities, Authentication Capabilities, and Accounting Capabilities. There is one more group, the Resource Capabilities, whose members, however, have already been covered, and comprise of the following capabilities: cputime, filesize, datasize, stacksize, coredumsize, memoryuse, memorylocked, maxproc, and openfiles.

2.2.1. Environment Capabilities

In review, the capabilities covered above that fall into this category are:
path,
priority, setenv, nologin, and umask.

Because the PATH and MANPATH environment variables are invariably set in shell init scripts, thus overriding any possible settings for them in any login class, it is usually superfluous to specify PATH and MANTPATH environment variables in a login class. We have already covered the PATH environment variable in the previous section ("path"). For the curious, the name of the MANPATH capability is quite intuitive: "manpath".

There are, however, several useful environment capabilities in addition to the umask, priority, and setenv capabilities that have been covered above. The first is the capability "requirehome." Hence if found thusly in a login class it will require all users covered by that login class to have a valid home directory to log into:

:requirehome:\

Because "requirehome" is a boolean capability, it does not require an '=' to set a value for it, but simply its presence sets it to TRUE.

Another important environment capability is "shell." This is a powerful capability as it will override the login shell specified in the master.passwd file, however, it will not set the SHELL environment variable. The SHELL environment variable will be dependent upon the login shell entry in master.passwd, which can make for a confusing situation when the shell specified in the login class does not match that within master.passwd.

If we wanted to set the login shell of every user within a particular login class to bash, the following line would accomplish it:

:shell=/usr/local/bin/bash:\

Every user within the login shell would be forced to use bash as the login shell no matter what they changed their system password on master.passwd (via chpass(1)/chsh(1)) or what the administrator may've set with vipw(8).

Because the following environment variables are less likely to be used, they only warrant a cursory mention, as they are mentioned in the man page for
login.conf(5):


Name Type Notes Description
---- ---- ----- -----------

charset string Set $MM_CHARSET
environment
variable to the
specified value.
hushlogin bool false Same as having a
~/.hushlogin
file.
ignorenologin bool false Login not prevented
by
nologin.
lang string Set $LANG
environment
variable to the
specified value.
term string su Default terminal
type
if not able to
determine from
other means.
timezone string Default value of $TZ
environment
variable.

2.2.2. Authentication Capabilities


In section 2.1., when we dissected the "default" login class, only one of
the
capabilities that was covered there belonged to the group of authentication
capabilities: "copyright". The remainder of the authentication capabilities
are all
relatively important, so they will all be covered in some depth here.

Perhaps the most important authentication capability is "minpasswordlen" which specifies the minimum password length that a user can have when setting a new password. The default is 6 characters. For FreeBSD 3.x systems, the maximum is 16 characters, andfor FreeBSD 2.2.x and prior systems the maximum is 8 characters. An example of restricting all users within a particular login class to only be able to set passwords with 10 characters or
more would go thusly:

:minpasswordlen=10:\

The "host.allow" and "host.deny" capabilities define hosts from which logins are allowed or denied, respectively. The format is in the form of hostnames and/or IP addresses separated by commas. For instance, the following capability entry would allow logins only from the remote host special.domain.com and super.domain.com for all users within that particular login class:

:host.allow=special.domain.com,super.domain.com:\

The obvious shortcoming to this method of allowing or blocking hosts is the resrtriction in space, however, these capabilities are convenient if ony one or two hosts are to be permanently blocked from the users in the login class, or, if only one or two hosts are to be allowed through. If there are one or more host entries in the host.allow then only those hosts will be allowed to login, denying all overs. if, however, the hosts.allow capability is empty, then everyone is allowed to log into the system, save for any blocked hosts/IPs with tcp wrappers (tcpd(8)).

As another example, if one wanted to block all login attempts from the domain linux.org for all users within a particular login class, the following capability entry would accomplish this:

:host.deny=*.linux.org:\

A point to note is that the "host.allow" and "host.deny" capabilities make use of standard wild card methods such as '*' and '?'.

Next we come to the powerful authentication capabilities of "times.allow" and "times.deny" which allow an administrator to limit the times at which users within the respective login class are able to log into their accounts. The periods of time are separated by comma, just as with "host.allow" and "host.deny," and are formatted with the following syntax:

a) <Day Code(s)...><Start Time>-<End Time>

b) The day codes are as follows: Mo, Tu, We, Th, Fr, Sa, Su.

c) The start and end times are expressed in 24 hour format (00:00-39:59).

For example, let is presume one wanted users within a particular login class to only have login access to their accounts between 9 AM and 9 PM Monday through Wednesday. The following times.allow entry would accomplish this:

:times.allow=MoTuWeThFr0900-2100:\

Furthermore, let us assume that every sunday, between 10 AM and noon, several users needed access to their accounts for special projects:

:times.allow=MoTuWeThFr0900-2100,Su0900-1200:\

When there are one or more time entries in a "times.allow" capability, then only those periods will allow a login. If there is at least one entry in a "times.deny" capability and the "times.allow" capability is not entered or empty, then login will be denied only during the periods specified in "times.deny."

Finally, we come to the last of the "allow/deny" trio: "ttys.allow" and
"ttys.deny".

Once again, these capabilities employ comma separated access and deny lists like the previous capabilities. Here, the list contains valid ttys on which users can log in. This can be useful in limiting the number of users that can be logged into the system at any one time. A shortcoming is that if a user maintains multiple simultaneous logins, accessible ttys may be "hogged." Fortunately, e will be able to solve the "hogging" problem with a capability from the next section.

Both virtual (ttyv?) and pseudo (ttyp?) can be specified in the lists. The former are for console logins, whereas the latter are for remote logins, such as with ssh(1) or telnet(1). For instance, let us assume one wants to limit logins for a particular login class to the pseudo ttys ttyp0, ttyp1, and ttyp2. The following capability entry would accomplish this:

:ttys.allow=ttyp0,ttyp1,ttyp2:\

Note: ttys are served on a smallest-number-first basis. If you only allow high ttys, such as, ttyp5-10 for a login class, and ttyp0-4 are not be utilized, then no users within the login class will be able log in as they will be constantly served the low-end ttys.


2.2.3. Accounting Capabilities

The accounting capabilities comprise the largest group of capabilities for login classes. We will attempt to cover the most useful of these.

The first accounting capability that we will cover will be that which solves the "tty hogging" problem described in the previous section with the "ttys.allow" and "ttys.deny" capabilities. To limit each user to a specific number of ttys with which they can simultaneously log in, one uses the "sessionlimit" capability. The syntax is simply as illustrated in the following example which limits each user within the login class to 2 simultaneous login sessions:

:sessionlimit=2:\

On a similar note, if an administrator desires to limit the maximum time which any login session may take place, the "sessiontime" capability can be used. The
"sessiontime" capability uses the following semantics for time expression:

y indicates the number of 365 day years,
w indicates the number of weeks,
d the number of days,
h the number of hours,
m the number of minutes, and
s the number of seconds.

If no modifier (y,w,d,h,m) is specified and only a lone number is indicated, the time unit defaults to seconds. To illustrate the flexibilty of the above semantics for time expression, examine each of the following examples, all of which specify the same length of time (1 hour and 30 minutes):

:sessiontime=1h30m:\
:sessiontime=90m:\
:sessiontime=1h1800s:\
:sessiontime=5400:\

In addition to individual session time control, the amount of time that a user can be logged in during a day and a week can also be defined with the "daytime" and "weektime" capabilities. They use the same syntax as does the "sessiontime" capability.

To warn the user that he/she is running close to the session/day/week login time limit, the "warntime" capability can be used, which just as the others, uses the same time experession syntax. For instance, to warn the user 30 minutes prior to session timeout, the following capability entry can be used:

:warntime=30m:\

Finally, an adminstrator can allow a grace period for session timeouts with the "gracetime" capability to allow users to squeak by the session limit by a defined time. For instance, to allow a grace period of 10 minutes, the following line would suffice:

:gracetime=10m:\

Next we come to the topic of password expiration. Login classes offer a powerful method for managing password expiration with the "warnpassword" and "passwordtime." The former sets the time before expiration that notices will be sent to the user that the password will expire, and the latter will actually set the interval at which passwords will expire. Both use the time expression semantics as outlined previously for use with the "sessiontime," "daytime" and "weektime" capabilities.

For instance, to specify a expiration interval for passwords of 60 days, and a warning period of 2 weeks, then the following lines would be used:

:passwordtime=60d:\
:warnpassword=2w:\

In addition to password expiration control, login classes allow a powerful method for controlling account expiration with the "expireperiod," "warnexpire,"
"autodelete," and "graceexpire" capabilities.

The first capability defines a period upon which, when terminated, it will expire the user's account. The countdown for expiration will begin with each user individually following the user's account creation. Account expiration will disable the user from logging back in, however, will not delete the user record from master.passwd. The second capability will, just like the "warntime" and "warnpassword" capabilities, warn the user prior to expiration, in this case, of the account. The third mentioned capability will automatically delete the account record [from master.passwd] upon a specified time following account expiration. Finally, the last capability will specify a grace period before account expiration, just like the "gracetime" capabiltiy does for session imits. All of these capabilities uses the same time expression semantics as have been previously covered.

To illustrate the usage of these capabilities, let us presume an administrator desires to set the expiration period for all accounts in a login class to 1 year. In addition, he wishes to warn them 1 month prior to expiration, allow them a 1 week grace period, and delete the account record 2 weeks after expiration. The following capability lines would
handle this:

:expireperiod=1y:\
:warnexpire=1m:\
:graceexpire=1w:\
:autodelete=2w:\

Next we come to the issue of session accounting. Session accounting allows a system to record the behaviour of each user insofar as what commands the user issues at the command prompt and what commands are issued by their scripts run in the background. In short, it will log every command issued by any process owned by the user whose login sessions are being "accounted." Session accounting can be configured outside of login classes, however, login classes offer a simple way to setup accounting for all users within an entire login class, for particular hosts or for particular ttys. If one wishes to explore session accounting configuration outside of login classes, see accton(8), sa(8), and ac(8), and lastcomm(1).

If session accounting is configured within a login class, only lastcomm(1) need be used, which will allow the administrator to examine commands issued by any user on the system. For more details on the log files and how session accounting is done by the system, please see the man pages for the aforementioned commands.

To quickly enable session accounting for all users within a login class, enter the following capability in the login class entry:

:accounted:\

To quickly enable session accounting for ttyv0, ttyv1, and ttyp0, use the "ttys.accounted" capability thusly:

:ttys.accounted=ttyv0,ttyv1,ttyp0:\

To quickly enable session accounting for a particular host, such as boff.domain.com, use the host.accounted capability thusly:

:host.accounted=boff.domain.com:\

Just like in all previous instances where more than one parameter needed to be specified, when multiple ttys or hosts are specifed to be logged, use commas to separate them.

If there are special hosts or ttys that one desires specifically not to log, while logging everything else, either "host.exempt" or "ttys.exempt" can be used in conjunction with "accounted" to exempt a list of hosts or ttys. For instance, if we wish to exempt ttyv1 from logging, while logging everything else, the following capability entries would accomplish this:

:accounted:\
:ttys.exempt=ttyv1:\

Finally, an important capability when it comes to configuring a chroot(8) environment for user ftp is "ftp-chroot." It is, like "accounted," a boolean capability, so simply naming it in the login class will enable it. Note: to use a chroot(8)'ed environment, it is recommended that the ls(1) command be compiled into ftpd. This can simply be accomplished by setting the FTPD_INTERNAL_LS environment variable to "yes" and then rebuilding ftpd.

2.3. The "tc" Capability

Having covered the four general groups of capabilities: Resource Capabilities, Environment Capabilities, Authentication Capabilities, and Accounting capabilities, we have a good grasp of the power of login classes. One special capability not mentioned earlier will now be covered. It allows one to include one login class within another. For instance, if one has a general login class which enforces general resource and authentication aspects that one wants all users to obide by, but has still needs to differentiate groups of users based on a number of other criteria, one can create separate login classes to address these differences between groups, and then have each login class _include_ the basic generic one that contains the generic authentication and resource limits. The special capability that allowed the inclusion of another login class
is "tc".

For example, the "loose" and "restricted" login classes below both include
the
"auth-basic" login class:

loose|Loose Login Class:\
:cputime=unlimited:\
:datasize=unlimited:\
:stacksize=unlimited:\
:memorylocked=unlimited:\
:memoryuse=unlimited:\
:filesize=unlimited:\
:tc=auth-basic:

restricted|Restricted Login Class:\
:cputime=1w:\
:datasize=10m:\
:stacksize=5m:\
:memorylocked=1m:\
:memoryuse=1m:\
:filesize=5m:\
:tc=auth-basic:

auth-basic|Basic Authentication Include:\
:accounted:\
:ttys.allow=ttyp0,ttyp1,ttyp2,ttyp3:\
:sessionlimit=1:\
:ftp-chroot:\
:warntime=5m:

2.4. Current and Maximum Capabilities

Now we come to the final aspect of login classes: the differentation between current and maximum limits. Many of the capabilities already mentioned can have a suffix added, either "-cur" or "-max" indicating separate current and maximum values for the capability. Current values can be overridden by a personalized ~/.login_conf, however, the override can not exceed the maximum specified in the system login.conf(5). Here follows an example of a login class, "restricted" (modelled off of the previous one), specifying both current and maximum limits for some of its capabilities:

restricted|Restricted Login Class:\
:cputime-cur=1w:\
:cputime-max=1w:\
:datasize-cur=10m:\
:datasize-max=15m:\
:stacksize=5m:\
:memorylocked=1m:\
:memoryuse=1m:\
:filesize-cur=5m:\
:filesize-max=5m:\
:tc=auth-basic:


3. Sample Login Class

To illustrate everything that has been overviewed in login class structure and construction, we will now implement a simple login class geared toward a restrictive stance, dealing with real-world issues.

The scenario we will use is that of a shell provider wanting to tighten security over his users, while at the same time not obstructing the daily activities of those who do not have a malicious bent.

The first consideration is ftp. To lesson the ease with which a user can extract important files off of the system, the ftp logins of regular users wil be run in a chrooted environment. Naming the login class, "basic," it starts off thusly:

basic|basic account|Basic Shell Account-20s25h:\
:ftp-chroot:\

The full name of the login class quickly indicates that the basic shell account has a 20M soft quota, and 25M hard quota. This is not necessary for login class syntax, but simply as a visual aid to allow the administrator quickly know what accounts the "basic" login class covers, especially if there are numerous account types. Try to be as descriptive for the full login class names as possible if there are more than a handful of login classes to manage.

The next consideration that the admin deals with is user processes. The admin does not want the users to be able to run so many processes that it can cripple the the system. Namely, the admin is concered about fork() Denial of Service attacks. As such, he implements a strict "maxproc" capability setting:

basic|basic account|Basic Shell Account-20s25h:\
:ftp-chroot:\
:maxproc=14:\

He surmises that on the condition that a user needs to compile something, such as a bot, which can take roughly 6-10 processes at any one time building the program, enough processes should be allowed to conduct this activity. In addition, the user may be running another bot in the background or perhaps a screen(4)'ed IRC client or suspended vi(1) session from when he was editing a configuration file, so an additional 2 processes must be allowed for this, bringing the total to 12. In addition, the user's login shell ust be accounted for, and the possibility that he is running another shell on top of this, because of personal preference, so 2 more processes must be accounted for, bringing the total to 14.

Next, the admin realizes that choking the cputime for running processes will defeat the purpose of a bot, so he sets the "cputime" capability to unlimited. He does, however, not wish for the user to be able to monopolize system memory, either by accident, disregard for other users, or as an attempt to cause a Denial of Service attack, so he cutails the maximum memory usable by the user to a reasonable max of 5M:


basic|basic account|Basic Shell Account-20s25h:\
:ftp-chroot:\
:maxproc=14:\
:cputime=unlimited:\
:memorylocked=5m:\
:memoryuse=5m:\

To avoid the user from mismanaging his shell init files and suddenly finding he has no PATH or MANPATH set, causing him to panic, the admin sets those in the login class as a precaution. In addition, on the ocassion that the user mismanages his shell init files and does not set a reasonable umask, the admin sets one for the login class:

basic|basic account|Basic Shell Account-20s25h:\
:ftp-chroot:\
:maxproc=14:\
:cputime=unlimited:\
:memorylocked=5m:\
:memoryuse=5m:\
:path=/bin /usr/bin /usr/local/bin /usr/X11R6/bin:\
:manpath=/usr/share/man /usr/local/man:\
:umask=022:\

To avoid a user from attempting to cause a Denial of Service attack by monopolizing all pseudo-ttys, the admin limits the amount of simultaneous login sessions to 3, allowing some flexibility, however, denying the chance for malicious activity. The admin does not, however, desire to limit what ttys users can log into, or at what times. Being a shell provider, he endeavours to allow the users manage their accounts whenever they are able to, which defeats the thought of limiting login times to certain times of the day.

basic|basic account|Basic Shell Account-20s25h:\
:ftp-chroot:\
:maxproc=14:\
:cputime=unlimited:\
:memorylocked=5m:\
:memoryuse=5m:\
:path=/bin /usr/bin /usr/local/bin /usr/X11R6/bin:\
:manpath=/usr/share/man /usr/local/man:\
:umask=022:\
:sessionlimit=3:\

Next, the admin has a concern over passwords. Firstly, he wants users to ave sufficiently long passwords, and secondly, to change them ocassionally to thwart anyone who may have acquired a user password somehow. As such, he limits the minimum password length to 8 characters, and enforces a password expiration every 3 months, with a 2 week warning period:

basic|basic account|Basic Shell Account-20s25h:\
:ftp-chroot:\
:maxproc=14:\
:cputime=unlimited:\
:memorylocked=5m:\
:memoryuse=5m:\
:path=/bin /usr/bin /usr/local/bin /usr/X11R6/bin:\
:manpath=/usr/share/man /usr/local/man:\
:umask=022:\
:sessionlimit=3:\
:minpasswordlen=8:\
:passwordtime=90d:\
:warnpassword=2w:\

Last, but not least, the admin wants to enable session accounting so he has a clear record of all user acitivty. This is simply done by adding the "accounted" boolean capability:

basic|basic account|Basic Shell Account-20s25h:\
:ftp-chroot:\
:maxproc=14:\
:cputime=unlimited:\
:memorylocked=5m:\
:memoryuse=5m:\
:path=/bin /usr/bin /usr/local/bin /usr/X11R6/bin:\
:manpath=/usr/share/man /usr/local/man:\
:umask=022:\
:sessionlimit=3:\
:minpasswordlen=8:\
:passwordtime=90d:\
:warnpassword=2w:\
:accounted:

The sample login class is complete.


4. Appendix.

Referenced man pages:

login.conf(5)
getcap(3)


(3)


ylocked=5m:\
:memoryuse=5m:\
:path=/bin /usr/bin /usr/local/bin /usr/X11R6/bin:\
:manpath=/usr/share/man /usr/local/man:\
:umask=022:\
:sessionlimit=3:\
:minpasswordlen=8:\
:passwordtime=90d:\
:warnpassword=2w:\
:accounted:

The sample login class is complete.


4. Appendix.

Referenced man pages:

login.conf(5)
getcap(3)


Various security based tools
Windows 2000 NSA Security files mirrored here
Make IOS/IPF/IPChains/IPTables rules via a CGI script here
Hardening Linux
Linux Encryption How-To
Hardening BSD
Linux IP Tables How To
IPF How To
Linux IP Chains How To
Intrusion Detection Systems and BSD or Linux (coming this week)


Credits



reported by: sil
Last Modified On: Sun May 20 13:36:04 EDT 2001