Linux servers.

Upgrading Red Hat Enterprise Linux / CentOS / Oracle Linux

RHEL/CentOS/Oracle Linux Migration:
Users and Groups — Identity Management

Identity management, the configuration of users and groups, is one of the few things that hasn't changed very much in the recent evolution of Linux. The most significant changes are in the collection of available PAM modules. Integration with Active Directory and Kerberos has improved. There have also been changes in the default password hashing algorithm and the ultimately meaningless change in the default ranges of numeric user and group IDs.

Previous: Logging

The previous page described the changes in logging in the migration from classic Syslog to Rsyslog and then the much bigger step to journalctl.

4 — User / Group Administration

Password Hashing

RHEL 6 SHA-512

The hash stored in /etc/shadow changed with RHEL 6. $1 indicates an MD5 hash, $2a indicates a Blowfish-based hash, $5 indicates SHA-2-256, and $6 indicates SHA-2-512. RHEL 5 and earlier had used MD5. RHEL 6 went to SHA-2-512 hashes of passwords with 516 bits of salt (86 base-64 encoded characters at 6 bits per character).

The hash choice is set in /etc/libuser.conf, in the [defaults] section with crypt_style. The same choice should be configured in /etc/pam.d/system-auth in the line in the password service section.

The files /etc/login.defs and /etc/sysconfig/authconfig and some of the files in /etc/security/ also set some of these values.

This is a mess: The same settings can be configured with different syntax within several different files. I wouldn't care to guess what would happen if they conflict with each other.

User Creation

See the complaints in the Installation section of the first page about the installer's insistence on creating a user but not allowing you to fully control all its attributes. That has been the case in both RHEL 6 and RHEL 7. It is much smoother in RHEL 8.

Slight changes in /etc/login.defs mean that users got UID/GID starting at 500 by default up through RHEL 6, changing to 1000 at RHEL 7. RHEL 7 and later create some system accounts with UIDs in the 990s: unbound/994, chrony/995, pcp/996, libstoragemgmt/997, colord/998, and polkit/999. Other than those, all system account UIDs are below 200.

Password Quality Control

Password quality control, to the limited extent that it really matters, is now best done with and

Be careful. Use of means that you now must also protect /etc/security/opasswd as that contains information on users' old passwords which could provide very useful hints as to what their later passwords will look like. can be configured with parameters within the PAM files, but a better approach would be to customize it within /etc/security/pwquality.conf so that every program handling password changes uses the same rules. Or follow the lead of most distributions in having one shared file that individual service files use with include or substack, such as system-auth on Red Hat and similar or common-auth on Debian and derivatives like Ubuntu. Put password quality control in the shared file to make everything impose the same requirements.

In the past, was the only thing you could count on being there in any distribution. Then came along. They are still available, although is now the best tool. However, people used to setting up password policies on Windows will be unhappy with all of them as none allow you to rigidly enforce a password policy exactly the same way you can in Windows. Just set something and move forward as password security is largely an illusion.


PAM files now contain substack in addition to include in the control field, the 2nd column. It works like include but with different logic for done and die actions, see the pam.conf(5) man page for the details.

RHEL 7 /etc/pam.d/system-auth warned that it was automatically modified by authconfig. That program still exists on RHEL 8, but now the warning in the PAM file says that authselect automatically modifies it.

With RHEL 8, the /etc/securetty mechanism and the module disappear. As Red Hat's documentation explains, the range of possible TTY device names is too hard to keep track of. See the enormous securetty file on Debian or Ubuntu to see what happens when you try to do that, and realize that there are even more.

Also with RHEL 8, the Coolkey package disappears. Use OpenSC to work with smart cards.

YubiKey support has changed:

See my page on YubiKey authentication for details on how to set it up.

Active Directory Integration

As you move to RHEL 7 the integration with Active Directory improves. With 7.1 NFSv4.1 finally interoperates, including with Kerberos.

Using Linux as an Active Directory Server

"Active Directory" is really a Microsoft product name, their branding for the combination of the DNS, LDAP, and Kerberos network services, plus centralized policy management, plus a public-key CA or Certificate Authority.

Starting at least by RHEL 7 you could do everything but the policy management with the Samba package. However...

Use FreeIPA.

Preventing Unprivileged Users from Rebooting or Shutting Down

Up through RHEL 6 there were files named halt, poweroff, reboot, and shutdown in /etc/pam.d allowing unprivileged users to run those commands, at least when you installed the desktop version. Disabling these in an easily reversible way was easy:

# cd /etc/pam.d
# for file in halt poweroff reboot shutdown
> do
>    mv $file DISABLED-$file
> done 

Because these are all done through systemd starting with RHEL 7, those PAM files aren't there.

But it's actually far worse...

This is now controlled with the polkit package, the PolicyKit Authorization Framework. So now "all you have to do" is first create a file with a name like:
Make it owned by root.root, mode 644, and contain the following. Yes, polkit assumes that you are a careful Java programmer. Now the only way to reboot or shut down is to provide the root password:

polkit.addRule(function(action, subject) {
    if ( == "org.freedesktop.login1.reboot" || == "org.freedesktop.login1.reboot-ignore-inhibit" || == "org.freedesktop.login1.reboot-multiple-sessions" || == "org.freedesktop.login1.power-off" || == "org.freedesktop.login1.power-off-ignore-inhibit" || == "org.freedesktop.login1.power-off-multiple-sessions") {
		return polkit.Result.AUTH_ADMIN;

That also handles those actions in the situations where some application has asked for shutdown or reboot to be inhibited, or where others are logged in.

Or maybe you would like to allow all members of group wheel to shut down or reboot without further authentication, but everyone else will be asked for the root password. Use this:

polkit.addRule(function(action, subject) {
    if ( == "org.freedesktop.login1.reboot" || == "org.freedesktop.login1.reboot-ignore-inhibit" || == "org.freedesktop.login1.reboot-multiple-sessions" || == "org.freedesktop.login1.power-off" || == "org.freedesktop.login1.power-off-ignore-inhibit" || == "org.freedesktop.login1.power-off-multiple-sessions") {
		if (subject.isInGroup("wheel")) {
			return polkit.Result.YES;
		} else {
			return polkit.Result.AUTH_ADMIN;

Background on polkit

Look around the PolicyKit Authorization Framework site for full details. Briefly:

polkit is an authorization API for mechanisms (privileged programs such as reboot or mount) to allow subjects (unprivileged programs such as a user's shell) to run them. The decision on every request is handed off to a trusted party, the polkit authority. Users authenticate to polkit as either root or the owner of the client session.

The polkitd daemon does the work. It has little privilege on its own, it runs as the polkitd user, but privileged programs trust its decisions.

Mechanisms define the set of possible actions in XML files stored in /usr/share/polkit-1/actions/*.policy. You could edit those policy files directly, but that would be a bad idea as an update to the polkit package will overwrite your changes.

What is the set of possible polkit actions? And which of them have to do with rebooting and shutting down?

# pkaction | less
  [... lots of output ...]
# pkaction | egrep 'power|shutdown|reboot|halt'

We were guessing as to their names, the six in bold are the ones we're interested in. They're in the file org.freedesktop.login1.policy. These file names are entirely arbitrary, this is where Red Hat put those action definitions.

You could look at the set of files /usr/share/polkit-1/actions/*.policy, and examine the contents of org.freedesktop.login1.policy.

Do that, and find this block:
<action id="org.freedesktop.login1.reboot">
Notice that three defaults are defined:

This means that any client can do this if they can provide the root password, and if they have done this recently (e.g., 5 minutes but this of course is also configurable), authentication doesn't have to be re-done.

This means the same thing for a client in an inactive session on a local console.

This means that a client in an active session on a local console can simply do this without any authentication. This is the line that allows random users to reboot. However, do not edit this file because future updates to the polkit package would overwrite your changes! You make changes with rules.

Rules applying to those policies about actions and the authentication methods are written in Java and are stored in /usr/share/polkit-1/rules.d/*.rules and /etc/polkit-1/rules.d/*.rules. The polkitd daemon watches both directories so it should notice your changes. Packages may put rule files into either location. Make your changes by adding new files /etc/polkit-1/rules.d/*.rules.

Rules are sorted into lexical order by the file names. Files in /etc are used before those in /usr if you have two with identical names. This means that you should start them with 2-digit numbers as that's the environment already in place when you begin. To use the example from the polkit(8) manual page or the online version with fancy graphics, the following order would be used for these four files:

  1. /etc/polkit-1/rules.d/10-auth.rules
  2. /usr/share/polkit-1/rules.d/10-auth.rules
  3. /etc/polkit-1/rules.d/15-auth.rules
  4. /usr/share/polkit-1/rules.d/20-auth.rules

You have to get the Java syntax correct. But it may not be obvious that your problem is a missing or extra parenthesis or curly bracket. You might wonder why your nice new rule file doesn't do what you expect, so try this:

# grep polkit /var/log/messages | tail 

Finally, if you're not happy using something like subject.isInGroup("wheel") in your rules files, you can create files written in a Windows .INI style in /var/lib/polkit-1/localauthority/50-local.d/10-whatever.pkla to define just what you mean by "administrator" in terms of users and groups for different actions.

Next ❯ Storage