Custom password complexity in OpenBSD
In OpenBSD it might not be obvious how to modify the default required password complexity and what the default requirements are. Most people probably use SSH keys instead of password login, but you should have a good password policy to fall back on if needed (or for the sake of an audit). There are a few hints here and there, but the best one is probably the obvious one in passwd(1)
The new password should be at least six characters long and not purely alphabetic. A mixture of both lower and uppercase letters, numbers, and meta-characters is encouraged.
The quality of the password can be enforced by specifying an external checking program via the “passwordcheck” variable in login.conf(5).
So the complexity is hard coded. If we look at the source code for passwd it leads us to pwd_check.c
min_len = (int)login_getcapnum(lc, "minpasswordlen", 6, 6);
if (min_len > 0 && strlen(password) < min_len) {
fprintf(stderr, "Please enter a longer password.\n");
return (0);
}
At least 6 characters long (max is 72 bytes), UTF-8 characters can be 1 to 4 bytes long.
The remaining default requirements are defined using regex.
struct pattern patterns[] = {
{
"^[0-9]*$",
REG_EXTENDED|REG_NOSUB,
"Please don't use all-digit passwords."
},
{
"^[a-z]{1,9}$",
REG_EXTENDED|REG_NOSUB,
"Please don't use an all-lower case password."
},
{
"^[a-z]{1,6}[0-9]+$",
REG_EXTENDED|REG_NOSUB|REG_ICASE,
"Please use a more complicated password."
},
{
"^([a-z][0-9]){1,4}$",
REG_EXTENDED|REG_NOSUB|REG_ICASE,
"Please use a more complicated password."
},
{
"^([0-9][a-z]){1,4}$",
REG_EXTENDED|REG_NOSUB|REG_ICASE,
"Please use a more complicated password."
}
};
Setup custom password quality checker
In order to provide our own password requirements for local accounts, we need to use an external tool. In ports there is a suitable application for this called passwdqc.
# pkg_info -q passwdqc
complexity checker for passwd(1) and password generator
passwdqc is a simple password strength checking module for password
changing programs, such as passwd(1). In addition to checking regular
passwords, it offers support for passphrases and can provide randomly
generated ones. All features are optional and can be (re-)configured
without rebuilding.
Maintainer: The OpenBSD ports mailing-list <ports@openbsd.org>
WWW: https://www.openwall.com/passwdqc/
To enable passphrase quality checking using pwqcheck(1) globally, add
the following lines at the end the "default" class in login.conf(5).
:passwordcheck=/usr/local/bin/pwqcheck -1:\
:passwordtries=0:
Install it with pkg_add passwdqc
and follow the instructions and don’t forget to run cap_mkdb /etc/login.conf afterwards.
Adapt /etc/passwdqc.conf if needed and update login.conf and add this to the default login class:
:passwordcheck=/usr/local/bin/pwqcheck -1 config=/etc/passwdqc.conf:\
The options can be supplied on the command line as well.
The rules can easily be verified by running the command manually and then type in a password to verify the settings:
/usr/local/bin/pwqcheck -1 config=/etc/passwdqc.conf
Check passwdqc.conf(5) for more details.
Tweaking password policies in passwdqc.conf
There are four character classes that can be tweaked using the min parameter:
- digits
- lower-case letters
- upper-case letters, and other characters
- non-ascii, such as ® etc
The number specified for each position is minimium length of the password.
Example:
N0
Passwords such as abc or 123 which consists of single character class are okay, which is really crappy so this is disabled.
N1
Passwords such as abc123 which consists of two character classes are okay.
N2
Password is for passphrase, silly thing.
N3
Passwords such as aB3^ which consists of three character classes are okay.
N4
Passwords such as aB3^© which consists of four character classes are okay.
So lets disable all but the fourth and set it to 72:
min=disabled,disabled,disabled,disabled,72
max=72
NOTE
The password length is max 72 bytes. UTF-8 characters can be 1-4 bytes long, so if you have smörgåsbord as password, it will be 11 characters long but occupy 13 bytes. It is a deep rabbit hole…but if you just skip non-ascii characters you can probably safely count on that 1 character equals 1 byte and therefore can use 72 characters password as minimium and max.
Configure password expiry defaults
Create a new account and expire immediately, forcing user to set a new password at first login
Expire existing account
Make sure the users login class has
:password-dead=2w:\
:password-warn=2w:
Explaination from login.conf (5)
password-dead time 0 Length of time a password may
be expired but not quite dead
yet. When set (for both the
client and remote server
machine when doing remote
authentication), a user is
allowed to log in just one more
time after their password (but
not account) has expired. This
allows a grace period for
updating their password.
password-warn time 2w If the user's password will
expire within this length of
time then warn the user of
this.
When logging in using SSH, the password warning will look like this:
Your password will expire in 5 days.
Set the expiry to yesterday force the user to change password at next login
sh usermod -f "Mar 14 2024" muppet
This is what the SSH Prompt will look like:
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for muppet.
Old password:
Locking an account
Lock account for login (works for SSH too):
usermod -Z eris
SSH Login with a locked account will behave like wrong password and log like this in /var/log/authlog
sshd[4993]: User eris not allowed because shell /bin/ksh- does not exist
sshd[4993]: Failed password for invalid user eris from <ip> port 52309 ssh2
Logins from console will log you in and immediately kick you out because of a non-existent shell.
Unlock account
usermod -U eris