|
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:\
|