User, Group and Password Management on Linux and Solaris

This article will cover the user, group and password management tools available on the Linux and Solaris Operating Systems. The specific versions covered here are CentOS 6.4 and Solaris 11.1, though the commands will transfer to many other distributions without modifications (especially RHEL and its clones), or with slight alterations to command options. Check your system documentation and manual pages for further information.

Knowing how to manage users effectively and securely is a requirement of financial standards such as PCI-DSS, and information security management systems such as ISO 27001.

In this article, I will consider local users and groups - coverage of naming services such as NIS and LDAP is beyond its scope but may be covered in a future article. This article also presumes some prior basic system administration exposure with a UNIX-like operating system.

Users and Groups

Users and groups make up a fundamental part of any multi-user operating system. On UNIX and Linux systems, every user has a UID (User ID) and a primary GID (Group ID). Users can own files, use resources and execute processes. The System Administrator can grant access to resources and data based upon the UID of the user, and the groups a user is a member of. Some additional features such as RBAC in Solaris take things a step further and allow very fine-grained control of what a user can and cannot do/access.

The OS takes care of mapping usernames and group names to UIDs and GIDs and vice versa by using a naming service, such as file-based (described next), LDAP or NIS.

Using the standard file-based naming service, the main user database is /etc/passwd. The group database is at /etc/group, and the shadow password file at /etc/shadow. Linux systems also have a group shadow database at /etc/gshadow.

Why do we need a shadow password file? /etc/passwd needs to be readable by every user on the system, as some applications depend on being able to map UIDs to usernames (ls, for example) and thus need to be able to read the password database. Therefore, the encoded password is moved to the /etc/shadow file, which need only be readable by root. Commands such as /usr/bin/passwd are SUID (Set UID) root so they can be executed by normal users with root privileges, thus being able to update the shadow file.

UIDs and GIDs can be duplicated, but it is bad practice as it makes auditing harder, and could lead to data being revealed inadvertently.

Let’s start by taking a look at the format of the various password database files.

/etc/passwd

The format of this file is:

username:x:uid:gid:GECOS:home:shell

The first field contains the user’s username. The second field contains an “x” which indicates that the shadow password suite is in use. The third is the UID, which as discussed should be unique. The fourth is the users primary group’s GID. The fifth field is known as the GECOS field after the GE operating system of the same name, and typically contains the user’s full name, and perhaps other identifying information; this is the only field in the file that may contain a space. The sixth field is the user’s home directory - an absolute path. The final field is the absolute path to the user’s login shell - which should be specified in /etc/shells on a Linux system. Solaris doesn’t use /etc/shells.

Let’s look at a sample entry from /etc/passwd:

Here, we can see that my username is toki, shadow password is in use, UID is 333, GID is 333, my GECOS information is my full name, my home directory is /home/toki and my login shell is /bin/bash.

/etc/shadow

The format of this file is:

username:encoded_password:last_changed:mindays:maxdays:warn:inactive:expire:reserved

The first field is the username and should correspond to an entry in /etc/passwd. The encoded password comes next. last_changed is the number of days after Jan 1, 1970 that the password was last changed - set to 0 it will force a user to change their password upon next login. mindays is the minimum password age, which is the number of days the user will have to wait before they will be allowed to change their password again. maxdays is the maximum password age, which is the number of days after which the user will have to change their password. warn is the password warning period, which is the number of days before a password is going to expire during which the user should be warned. inactive is the password inactivity period - the number of days after a password has expired during which the password will still be accepted. expire is the account expiration date - the date of expiration of the account, expressed as the number of days since Jan 1, 1970. The final field is reserved for future use.

On an out-of-the-box CentOS install, many fields are empty when users are added via useradd without additional password ageing options:

The minimum password age above is 0, which means there are no restrictions in place.

On a Solaris system, even more fields are empty:

Again, this is default behaviour that we will learn to configure over the course of this article.

/etc/group

The format of the file is:

group_name:passwd:GID:user_list

group_name is the name of the group. passwd is the encoded group password. The Solaris manual page for group(4) states “Group passwords are antiquated and not often used.”. The GID is the numerical group ID, and the user_list is a comma-separated list of group members. There could also be users having this group as their primary GID (i.e. the GID specified in /etc/passwd), in which case they wouldn’t need to appear in user_list.

Here are two entries from /etc/group on a CentOS machine:

and here are two from a Solaris 11 machine:

On a Solaris machine, the passwd field is empty for all groups out-of-the-box. On a Linux machine, it contains an “x” indicating that the group shadow file is in use. See man 5 gshadow for more information on the group shadow file (/etc/gshadow), but its format is:

username:encoded_password:administrators:members

As you can see, I’m a member of the wheel group on this machine:

The user administration tools and group administration tools will take care of updating these files for us, and keeping /etc/shadow in sync with /etc/passwd, and /etc/gshadow with /etc/group.

Adding Users

Let’s start by taking a look at how the two OSes create users using all default and no additional arguments other than the required username. On CentOS:

It took the next available UID on my system, and applied sensible defaults to the other parameters (a home of /home/<username>, shell of /bin/bash). It also created a group, and set it to be the primary group of the new user. This new-group-per-user policy can be found on all RHEL-derivatives.

On Solaris, the behaviour is slightly different:

As you can see, the home directories and shell path are different (and are appropriate for this OS) but the account is just added to a group called staff:

On CentOS, you will note that the user’s home directory has been created, the contents of /etc/skel copied in, and then appropriate ownership and permissions configured. /etc/skel is a good way to push site-wide configuration files out to all new accounts.

As an example, here are the contents of /etc/skel on a CentOS system. A mail spool file has also been created:

On Solaris, by default, the user’s home directory is not created, and the contents of /etc/skel are not, therefore, copied in. We can either do this manually after running useradd, or instead use options available to the useradd command to create the user. We can use the -m option to cause the home directory to be created, and the -d option to explicitly define the home directory location. We then observe the files being copied in from /etc/skel:

The useradd command is very rich in terms of options and customisation. The following command adds a user jsmith with UID 450, a primary group of wheel, a home directory of /users/jsmith, and a login shell of zsh:

These options can be used to override defaults.

All user additions should be logged, and whether that is by using the auditing features available with your operating system, or some other logging process, will be dependant on your needs.

Defaults

When configuring new user accounts with useradd, there are some defaults that are used. On a CentOS system, these are by default read from /etc/login.defs.

Here are the variables in use on a default CentOS 6.4 installation, which will need to be tuned according to the needs of your site or organisation, and any security policies in effect. There are other variables in the file, and the manual page should be consulted for further information. The file itself is also very well commented.

Other defaults can be viewed with useradd -D:

The defined variables are as follows:

MAIL_DIR - The directory where mailboxes reside.

PASS_MAX_DAYS - Maximum number of days a password may be used.

PASS_MIN_DAYS - Minimum number of days allowed between password changes (0 to disable).

PASS_MIN_LEN - Minimum acceptable password length.

PASS_WARN_AGE - Number of days warning given before a password expires.

UID_MIN/MAX - Min/max values for automatic UID selection in useradd.

GID_MIN/MAX - Min/max values for automatic GID selection in groupadd.

USERDEL_CMD - Commented by default. Can be used to set up a customised local userdel, to remove at/cron/print jobs, etc.

CREATE_HOME - Set to yes if useradd should create home directories for users by default.

UMASK - Permission mask to be used.

USERGROUPS_ENAB - This enables userdel to remove user groups if no members exist.

ENCRYPT_METHOD - Encryption method used to encrypt passwords - we use SHA512.

User Modification

The usermod command is used to modify user accounts. The options are similar to those supplied by the useradd command. For example, to move the home directory for user tstusr02 from /export/home/tstusr02 to /users/tstusr02, we could issue the following command:

To change the UID for the sometest user to 1234 we’d issue:

Add the user toki to an additional secondary group (-a for “append” - not available on Solaris):

User Deletion

Users can be deleted using the userdel command. There is a -r option that will remove the user’s home directory. It is advised that accounts are not deleted, rather just locked (see the Locking Accounts section of this article). This provides auditing capabilities, and stops UID reuse (and inadvertently giving access to an old user’s files to a new user). To delete user toki from the system, including removal of the user’s home directory:

Group Administration

Groups are administered with the groupadd, groupmod and groupdel commands. To add a new group tstgrp to the system, with GID 250, issue:

To change the name of tstgrp to testgrp:

To remove a group:

Password Management

Passwords are managed with the passwd command. An initial password can be set for a user (or a password reset) via:

A user may reset their own password with a simple:

which will then prompt them for the old password, followed by the new password, followed by the new password again to verify. root can change passwords without being prompted for the old password.

The passwd command can also be used to lock accounts (see the Locking Accounts section below).

Password Defaults

On Solaris, /etc/default/passwd can be used to configure password-complexity enforcement. Out of the box, the /etc/default/passwd file contains the following defined variables:

And the following commented variables:

These values can be modified according to your site’s security policy and affect the way that the passwd command works, and how it enforces password complexity and reuse. Again, the /etc/default/passwd file is well commented and the variable names themselves are self-explanatory.

Locking Accounts

The passwd command is used to lock accounts on both Linux and Solaris. To lock the password for tstusr01 on Solaris:

Looking at /etc/shadow, you’ll see that the string *LK* has been prepended to the encrypted password field in the second field:

Doing the same on CentOS 6.4 for user testuser1:

You can see that !! has been prepended.

To unlock the account on Solaris, use passwd -u:

The same applies to Linux:

Configuring Password Ageing

In the following example, I’ll bring everything together. A group called testusrs with members test01 and test02 will be created, and various operations performed with respect to password configuration.

We’ll start with Solaris.

Create the group, followed by the two users:

Set an initial password on the two accounts:

Next, use passwd -f to force the users to change their passwords at login time:

Let’s implement some password ageing controls. Suppose the site-wide password policy is as follows:

  • The minimum number of days required between password changes is 7
  • The maximum number of days the password is valid for is 28
  • The user will receive warnings 7 days before expiry
  • Passwords will be 8 characters or more long
  • A history of 5 passwords will be kept and prevented from reuse

To do this, edit /etc/default/password and update the following variables:

And update any already existing user accounts:

Looking at /etc/shadow we can see the password ageing fields updated:

Let’s perform the same steps on a CentOS system. Start with the group and user creation:

Set the initial passwords:

On Linux, password ageing is the domain of the chage command. Setting the number of days since January 1st, 1970 when the password was last changed to 0 has the same effect as passwd -f on Solaris.

To configure the same password ageing policy as the Solaris example, use chage as follows:

The defaults for new user accounts can be changed in /etc/login.defs:

Here we also see the PASS_MIN_LEN option, which has been increased to 8 as per the Solaris example.

To implement the equivalent of HISTORY=5 on Solaris, PAM (Pluggable Authentication Module) configuration must take place.

Edit /etc/pam.d/system-auth-ac and update the following line:

Append remember=5 to the line:

Now, if a user attempts to reuse a recent password, they’ll see a message such as the following:

This will create the file /etc/security/opasswd to track the password history of all system users.

Further configuration akin to /etc/default/passwd on Solaris can be configured via pam_cracklib.

You can read more via the section 8 manual page on pam_cracklib.

Logging

Linux does a very good job at logging via the authpriv syslog facility - for example, there will be messages in /var/log/secure such as:

This makes for an excellent audit trail (as long as logs are regularly rotated and backed up, of course).

The Solaris audit tool does not currently log these actions (even via the audit daemon, but it will log password changes), but simple wrapper scripts could be written around the existing tools to perform appropriate logging.

Other Tools

Solaris provides the logins command which displays a variety of information on currently configured user accounts. An example:

More information (including password expiration fields) can be added with -a. Other reports can also be generated, such as logins with duplicate UIDs (the -d option). Another very useful option is the -m option which acts like the groups command and displays all groups that the user (specified with the -l option) is a member of:

Security Considerations

User access should also be limited with regards to system access and service availability. For example, we can limit access to cron and at by using /etc/{cron,at}.{allow,deny} files. By default, all users have access to cron and at. This may or may not be what you want. From a security standpoint, all users should be denied access by default. Therefore, have an empty /etc/cron.deny and /etc/at.deny, and a single line in /etc/cron.allow and /etc/at.allow of “root“. Then, grant access as necessary by appending usernames to the files. For example, if you enable system profiling via sa1 and sa2 on Solaris, you’ll need to add “sys” to the *.allow files.

Remote SSH access to the system can be managed via the AllowUsers parameter, amongst others. From sshd_config(5):

AllowUsers

This keyword can be followed by a list of user name patterns, sepa-

rated by spaces. If specified, login is allowed only for user names

that match one of the patterns. Only user names are valid; a numer-

ical user ID is not recognized. By default, login is allowed for

all users. If the pattern takes the form USER@HOST then USER and

HOST are separately checked, restricting logins to particular users

from particular hosts. The allow/deny directives are processed in

the following order: DenyUsers, AllowUsers, DenyGroups, and finally

AllowGroups.

/etc/security/access.conf is another access control mechanism on RHEL-derivatives and other distributions. An excerpt from the well-commented example:

Simple <flag>:<username or groupname>:<ip_address> ACLs can be defined in this way, although it could become cumbersome to manage for large sites. Remember that you’ll need to ensure that pam_access.so is “required” in any files under /etc/pam.d as appropriate if you do decide to use pam_access.

On CentOS, we can also configure /etc/security/limits.conf, and limit the following resources to specific users or groups:

The format of entries in this file are:

These restrictions will also effect what users can do with invocations of ulimit, when hard limits are imposed.

For example, to limit test01 to having a soft limit of 20 processes, and a hard limit of 30, we can add the following to limits.conf (or a separate file under /etc/security/limits.d):

As test01, we can see the new restrictions in place:

pam_tally2.so can be used to keep a tally of failed logins per-account, and deny access once the number reaches a certain value.

Add the following to /etc/pam.d/login and /etc/pam.d/sshd

This would deny access to an account after 4 bad attempts, but will allow access again after 1200 seconds. The tally information is written to /var/log/tallylog. The pam_tally2 command is used to administer the tallied accounts. For example, suppose user toki was denied access. First, check the tally:

Once verified that these failures are not caused by malicious means, unlock the account by resetting the tally:

pam_faillock.so also provides similar functionality.

Privileges

Rather than giving everyone the root password, which is obviously an extremely poor security practice, if elevated privileges are required, sudo should be configured. Sudo is installed by default on both CentOS 6.4 and Solaris 11.1 and provides a mechanism to define ACLs as to which users and groups can perform privileged actions on a server, with or without passwords. Again, the default file is very well commented, for example from /etc/sudoers:

You should use the visudo command to edit the /etc/sudoers file, as it performs sanity checks before saving the file and possibly corrupting the live sudoers file if there are errors in your syntax.

If there is an insistence on sharing a root password, then the number of people knowing that password should be limited. All access to the root account should be made via su and not via direct root login, which should be limited to the system console only. This will provide logging and an audit trail.

Conclusion

This article has described some of the major aspects of user, group and password management on the CentOS 6.4 and Solaris 11.1 Operating Systems. User account management is a complex subject, so only the core aspects have been covered. The manual pages and system documentation should be consulted for further information.

This article was previously published in Pentest Magazine.

Pentest Magazine