A user’s shell can be used to limit what a user can do, but OpenBSD provides very specific access controls with login classes. Login classes, set in /etc/login.conf, define the resources and information accessible to users. Login classes also let you control password length and expiration times, as well as external authentication mechanisms.
Each user is assigned to a class, and each class places limits on available resources. When you change the limits on a class, the new limits are applied to each user the next time the user logs in. Define a user’s class when creating the account, or change it with chpass
.
By default, login.conf offers two classes for users, one class for daemons, and a few special-case classes. The default
user class gives the user wide-ranging access to system resources and is suitable for machines with a limited number of shell users. The staff
user class gives the user no restrictions on memory use, sets very high limits on the number of processes a user can run concurrently, and allows the user to log in even when logins are forbidden.
If these two classes meet your needs, and if you won’t be using an alternative authentication protocol like Remote Authentication Dial In User Service (RADIUS) or Kerberos, you can skip this section. If not, read on.
Each class definition consists of a series of variable assignments describing the class’s resource limits, authentication, and environment. Each variable assignment in the class definition begins and ends with a colon. The backslash character indicates that the class continues on the next line, which makes the file more readable.
Here’s the definition of the default
class:
default: 1 :path=/usr/bin /bin /usr/sbin /sbin /usr/X11R6/bin /usr/local/bin /usr/local/sbin: 2 :umask=022: 3 :datasize-max=512M: :datasize-cur=512M: :maxproc-max=256: :maxproc-cur=128: :openfiles-cur=512: :stacksize-cur=4M: :localcipher=blowfish,6: :ypcipher=old: 4 :tc=auth-defaults: :tc=auth-ftp-defaults:
The default
class has several variables. Some of these have fairly obvious interpretations. For example, the path
variable at 1 assigns a default command search path to the user’s shell, usually visible to the user as $PATH
. The umask
setting at 2 assigns a default umask to the user’s shell. The user can override both of these.
Other settings, such as datasize-max
and maxproc-max
at 3, are harder to define by guesswork. We’ll go through some of the more commonly used values in the next section.
Similar in behavior to the termcap
tc
variables at 4 used to configure serial console clients in Chapter 5, the default
class copies settings from the entries auth-defaults
and auth-ftp-defaults
elsewhere in login.conf.
Some variables don’t require a value to trigger behavior; these values trigger a specified behavior simply by adding them to login.conf. For example, the presence of requirehome
means that the user must have a valid home directory to log in.
On many BSD systems, you must transform the login.conf file to a program-friendly database file, login.conf.db, with cap_mkdb(8)
. OpenBSD doesn’t require this. Programs that check login classes first look for the login class database, and if they don’t find it, they directly parse login.conf. You can use cap_mkdb
to create such a database, which will very slightly improve the performance of software that checks login.conf.
# cap_mkdb /etc/login.conf
Note that once you create this database, you must rebuild it every time you edit login.conf. Database values in login.conf.db will always override your login.conf settings. Alternatively, you can remove login.conf.db and force programs to always parse login.conf.
I recommend skipping cap_mkdb
on modern hardware.
The login.conf variables accept only very specific values, including the following:
A full path to a text file or a program
A comma-separated list of environment variables
A comma-separated list of values
A number (put a 0x in front of the number for hexadecimal, or a 0 in front for octal)
A space-separated list of pathnames
A size, in bytes (default), kilobytes (K), megabytes (M), gigabytes (G), or 512-byte blocks (T)
A time in some combination of seconds (assumed if no unit is given), minutes (m), hours (h), days (d), weeks (w), or years (y)
Variables that use pathnames accept the special symbols tilde (~
) and dollar sign ($
). A tilde followed by a slash or the user’s login name, or at the end of a pathname represents the user’s home directory. You can use ~/bin
to represent a bin
directory in the user’s home directory. The dollar sign represents the username. For example, you might use /var/mail/$
to represent the user’s incoming mail file.
Some variables require particular types of values. A path to the user’s home directory must be a full path, while the amount of memory a user can allocate must be a size. In most cases, legitimate answers are fairly obvious, but check login.conf(5)
for a full listing of acceptable values.
Resource limits allow you to control the amount of system resources any one user can monopolize at any one time. If several hundred users are logged in to one machine, and one user decides to compile LibreOffice, that person will consume far more than his fair share of processor time, memory, and I/O. By limiting the resources any one user can use, you can make the system more responsive for all users.
Resource limits were more commonly used back when computing facilities were very expensive and departments received bills for the amount of computing time they used. These days, utilization accounting isn’t so important. It’s generally cheaper to buy more computing power than it is to configure accounting or resource limits. That said, if you have a buggy daemon that sometimes leaks and starts to soak up CPU time or memory, giving it a login class can prevent it from devouring the system.
Table 6-1 lists some resource-limiting login.conf variables.
Variable |
Description |
|
Maximum size of a core dump file |
|
Maximum CPU time any one process can use |
|
Maximum data size per process |
|
Maximum size of any one file |
|
Maximum number of processes |
|
Maximum locked-in core memory use per process |
|
Maximum core memory use per process |
|
Maximum open file descriptors per process |
|
Maximum stack size per process |
|
Maximum virtual memory use per process |
Resource limits are generally set per process. If you permit each process 200MB of RAM and allow 40 processes per user, you’ve just allocated each user 8GB of memory. Perhaps your system has a lot of memory, but does it really have that much?
All resource-limiting variables except vmemoryuse
support maximum and current (advisory) limits. Users are warned by the system when they exceed current limits and cannot exceed the maximum limits. This works well on a cooperative system, where multiple users share resources but need to be notified when they are approaching their limit.
To specify a current limit, add -cur
to the variable name. To make a maximum limit, add -max
. For example, to set a current and maximum limit on the number of processes a user can have, use this definition in the class:
… :maxproc-cur: 50: :maxproc-max: 60: …
A user in this class will receive a warning when he uses more than 50 processes and will not be able to use more than 60 processes. If you do not specify a limit as current or maximum, it acts as both.
You can define environment settings in a user class. This can work better than setting them in the default shell profile, because changes affect all users immediately upon their next login. This setting will impact all user shells, even those that don’t read .profile or .cshrc.
Table 6-2 lists popular user class variables that affect the user environment.
Variable |
Description |
|
If present, no system information is given out during login. |
|
User can log in even when /etc/nologin file is present. |
|
Path to a file. If the file exists, when a user tries to log in, the file contents are displayed and login is denied. |
|
Default command search path. |
|
User’s priority (nice) level. See |
|
If present, user must have valid home directory to log in. |
|
A comma-separated list of environment variables and values. |
|
User shell. Overrides user shell selection in /etc/passwd. The user’s |
|
Default terminal type, if environment can’t figure out terminal type. |
|
Initial umask. Should always start with a 0. |
|
Path to a file containing the login message. |
Unlike the user environment, which can be configured in several different places, many password controls can be configured only via the user class. The password controls affect only the local password database, not Lightweight Directory Access Protocol (LDAP), Kerberos, RADIUS, or other remote password databases.
Let’s have a look at some commonly used password controls.
localcipher
This controls the password hashing method used in /etc/master.passwd. The default is Blowfish. Don’t change the password hashing method unless you’re trying to be compatible with a specific foreign Unix-like operating system. See
login.conf(5)
for the list of supported hashing algorithms.
login-backoff
This controls how quickly a user can struggle to remember his password. After this many unsuccessful login attempts,
login(1)
slows down how quickly it offers a new username and password prompt.
passwordcheck
This gives the full path to an external program that checks new passwords for quality. OpenBSD passes the password to the program on standard input. The program is expected to return a 0 if the password is adequate and a 1 if the password is inadequate. OpenBSD includes a very simple and limited password-quality checker; if you need a password-quality checker, check out
passwdqc
(/usr/ports/security/passwdqc).
passwordtries
This is the number of times
passwd(1)
uses the password-quality checker. If the user cannot come up with a sufficiently complicated password in this many tries, the new password is accepted anyway. If this is set to 0, a new password is accepted only when it passes the quality check.
minpasswordlen
This is the minimum length of a new password. Password length is not a measure of quality—a stream of 128
A
characters is still a lousy password, but it might help you meet site requirements.
passwordtime
This is the maximum age of a password, in seconds. Use this to require regular password changes.
password-warn
This is the length of time, in seconds, before
login(1)
begins warning the user of an expiring password.
password-dead
This is the length of time, in seconds, after password expiration when the user may log in one last time, just to reset his own password. If the user does not reset his password, he cannot log in. This is a last-chance grace period; if the user blows this chance, sysadmin intervention is required to reset the password.
OpenBSD supports many different authentication mechanisms, such as the local password file, Kerberos, S/Key, RADIUS, and so on. Specify the authentication method desired in the user class definition, and OpenBSD will use it. This system behind this is called BSD Authentication.
Setting an authentication mechanism does not configure the authentication mechanism. For example, configuring a login class to authenticate via Kerberos doesn’t magically establish a Kerberos domain. If the specified authentication method is unavailable, classes configured to use that method will be unable to log in.
Not all authentication methods interoperate with all protocols. For example, while SSH works with physical tokens, it doesn’t work with the lchpass
authentication protocol, which allows users to change their password but disallows logins. Review the man page for each authentication method for details.
Some authentication methods require additional configuration. For example, if you want to use RADIUS authentication, you must tell your system where to find your RADIUS server. The special login.conf variables and their use are documented in the authentication method’s man page.
Table 6-3 lists the authentication methods supported by OpenBSD’s built-in BSD Authentication.
Method |
Man Page |
Description |
|
|
Authenticate via ActivCard token |
|
|
Change password, no shell |
|
|
Authenticate via CRYPTOCard token |
|
|
Authenticate via Kerberos |
|
|
Try Kerberos, then local password database |
|
|
Change local password |
|
|
Authenticate against local password file |
|
|
Authenticate against RADIUS server |
|
|
Request a password, then deny the login |
|
|
Authenticate via S/Key |
|
|
Authenticate via SecureNet token |
|
|
Authenticate via X9.9 token |
|
|
Authenticate via Yubico YubiKey token |
The ports collection (discussed in Chapter 13) contains a few additional login methods, such as fingerprint scanners (sysutils/login_fingerprint), OATH one-time passwords (sysutils/login_oath), and LDAP integration (sysutils/login_ldap). You can also create your own custom authentication methods; see login.conf(5)
for details.
Set the authentication method using the auth
variable in login.conf:
:auth=token,passwd:
Users in a class with this set try to authenticate via an X9.9 token. If that’s not possible, the system falls back on the local password database.
BSD Authentication supports different authentication methods for different daemons. You can specify a service name after the auth
keyword, indicating that this set of authentication methods applies to only that particular service. You’ll frequently see login classes like auth-ssh
and auth-su
.
Here are a couple of sample entries from the default login.conf file:
# Default allowed authentication styles auth-defaults:auth=passwd,skey: # Default allowed authentication styles for authentication type ftp auth-ftp-defaults:auth-ftp=passwd:
This defines the class auth-defaults
, with only one entry. By default, users in this class first use password authentication, and then S/Key authentication. The auth-ftp-defaults
class defines auth-ftp
as using the password database, and only the password database.
Earlier in this chapter, I mentioned that the default class included two other classes. These are the auth-defaults
and auth-ftp-defaults
classes. Every other login class in the default login.conf file includes them by reference. If you change the authentication methods used by the auth-defaults
class, that change will apply to every other login class.
I have a long-running love/hate relationship with RADIUS. It’s the lowest common denominator of authentication protocols. Just about every operating system and hardware device supports it, but it’s a finicky protocol with innumerable edge cases. Luckily, configuring OpenBSD as a RADIUS client is simple. Any RADIUS server can provide authentication services for OpenBSD.
I encourage you to use another login service, such as LDAP or Kerberos, rather than RADIUS. But in certain cases, for certain users, RADIUS is adequate. RADIUS combined with Microsoft’s Internet Authentication Service gives you easy password synchronization with the local Windows domain and reduces your support load.
First, read login_radius(8)
, and then configure your RADIUS server to permit access from your OpenBSD host. To configure RADIUS authentication, you need the RADIUS server’s IP address, the port RADIUS runs on, and a shared secret. (For historical reasons, it’s best to specify the RADIUS port explicitly rather than relying on /etc/services.) In our example, the RADIUS server is 192.0.2.2, the port is 1812, and the secret is the string Insubordination88
.
First, create a directory to hold the server configuration file and set its permissions appropriately, as per login_radius(8)
.
# mkdir /etc/raddb # chgrp _radius /etc/raddb/ # chmod 755 /etc/raddb/
Now create the file /etc/raddb/servers. This file should contain a server and its secret, each on one line. Our servers file has only one line:
192.0.2.2 Insubordination88
Now change login.conf to use RADIUS by default.
auth-defaults: :auth=radius: :radius-port=1812: :radius-server=192.0.2.2:
The auth-defaults
class is OpenBSD’s default authentication class. If we change it, we change how every other class authenticates. We set the auth
type to radius
, and set the port and the server.
Immediately upon saving the file, OpenBSD will try to authenticate all user accounts against the RADIUS server. You might want to change the auth-ftp
class to match.[14]
Until you confirm everything is working, keep an SSH session logged in as root so you can change login.conf. Otherwise, you might lock yourself out of the system, or at least out of the root account. If you can’t get into the system, you’ll need to reboot into single-user mode and edit login.conf.
Changing the authentication scheme for all users might not be desirable, either. You might want authpf(8)
users to authenticate against RADIUS, but have users in the staff
class authenticate against the local password database. Perhaps you don’t want your root account to authenticate via RADIUS, so you need an auth-su
login class that points at the local password database. Using login classes, you can configure user authentication to fit your specific needs.