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.
|
1 2 3 4 5 6 |
# ls -l /etc/passwd /etc/shadow -rw-r--r--. 1 root root 958 Dec 3 01:29 /etc/passwd ----------. 1 root root 736 Dec 3 01:29 /etc/shadow # ls -l /etc/group /etc/gshadow -rw-r--r--. 1 root root 471 Dec 3 01:29 /etc/group ----------. 1 root root 383 Dec 3 01:29 /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.
|
1 2 |
# ls -l /usr/bin/passwd -rwsr-xr-x. 1 root root 30768 Feb 22 2012 /usr/bin/passwd |
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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# cat /etc/redhat-release CentOS release 6.4 (Final) # cat /etc/shells /bin/sh /bin/bash /sbin/nologin /bin/dash # cat /etc/release Oracle Solaris 11.1 X86 Copyright (c) 1983, 2012, Oracle and/or its affiliates. All rights reserved. Assembled 19 September 2012 # cat /etc/shells cat: cannot open /etc/shells: No such file or directory |
Let’s look at a sample entry from /etc/passwd:
|
1 2 |
# fgrep "toki" /etc/passwd toki:x:333:333:Toki Winter:/home/toki:/bin/bash |
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:
|
1 2 |
# fgrep toki /etc/shadow toki:encoded_password_here:16041:0:99999:7::: |
The minimum password age above is 0, which means there are no restrictions in place.
On a Solaris system, even more fields are empty:
|
1 2 |
# fgrep toki /etc/shadow toki:encoded_password_here::::::: |
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:
|
1 2 3 |
# fgrep "toki" /etc/group wheel:x:10:toki toki:x:333: |
and here are two from a Solaris 11 machine:
|
1 2 3 |
# fgrep "sys" /etc/group sys::3:root,bin,adm sysadmin::14: |
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:
|
1 2 3 |
# fgrep toki /etc/gshadow wheel:::toki toki:!:: |
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:
|
1 2 3 4 5 |
# useradd testuser1 # fgrep testuser1: /etc/passwd testuser1:x:334:334::/home/testuser1:/bin/bash # fgrep testuser1: /etc/group testuser1:x:334: |
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:
|
1 2 3 4 |
# useradd tstusr01 # fgrep tstusr01 /etc/passwd tstusr01:x:102:10::/export/home/tstusr01:/usr/bin/bash # fgrep tstusr01 /etc/group |
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:
|
1 2 |
# awk -F: '$3 == 10 { print $0 }' /etc/group staff::10: |
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:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# ls -lA /etc/skel total 12 -rw-r--r--. 1 root root 18 Feb 22 2013 .bash_logout -rw-r--r--. 1 root root 176 Feb 22 2013 .bash_profile -rw-r--r--. 1 root root 124 Feb 22 2013 .bashrc # ls -lA /home/testuser1 total 12 -rw-r--r--. 1 testuser1 testuser1 18 Feb 22 2013 .bash_logout -rw-r--r--. 1 testuser1 testuser1 176 Feb 22 2013 .bash_profile -rw-r--r--. 1 testuser1 testuser1 124 Feb 22 2013 .bashrc # ls -ld /home/testuser1 drwx------. 2 testuser1 testuser1 4096 Dec 4 05:39 /home/testuser1 # ls -l /var/spool/mail/testuser1 -rw-rw----. 1 testuser1 mail 0 Dec 4 05:39 /var/spool/mail/testuser1 |
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:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# useradd -m -d /export/home/tstusr02 tstusr02 80 blocks # ls -lA /export/home/tstusr02 total 11 -r--r--r-- 1 tstusr02 staff 159 Nov 25 11:09 .bashrc -rw-r--r-- 1 tstusr02 staff 568 Nov 25 11:09 .profile -rw-r--r-- 1 tstusr02 staff 166 Nov 25 11:09 local.cshrc -rw-r--r-- 1 tstusr02 staff 170 Nov 25 11:09 local.login -rw-r--r-- 1 tstusr02 staff 131 Nov 25 11:09 local.profile # ls -lA /etc/skel total 11 -r--r--r-- 1 root bin 159 Sep 20 2012 .bashrc -rw-r--r-- 1 root other 568 Sep 20 2012 .profile -rw-r--r-- 1 root sys 166 Sep 20 2012 local.cshrc -rw-r--r-- 1 root sys 170 Sep 20 2012 local.login -rw-r--r-- 1 root sys 131 Sep 20 2012 local.profile |
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:
|
1 2 |
# useradd -m -d /users/jsmith -u 450 \ > -g wheel -c "John Smith" -s /bin/zsh jsmith |
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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# grep '^[^#]' /etc/login.defs MAIL_DIR /var/spool/mail PASS_MAX_DAYS 99999 PASS_MIN_DAYS 0 PASS_MIN_LEN 5 PASS_WARN_AGE 7 UID_MIN 500 UID_MAX 60000 GID_MIN 500 GID_MAX 60000 CREATE_HOME yes UMASK 077 USERGROUPS_ENAB yes ENCRYPT_METHOD SHA512 |
Other defaults can be viewed with useradd -D:
|
1 2 3 4 5 6 7 8 |
# useradd -D GROUP=100 HOME=/home INACTIVE=-1 EXPIRE= SHELL=/bin/bash SKEL=/etc/skel CREATE_MAIL_SPOOL=yes |
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:
|
1 |
# usermod -m -d /users/tstusr02 tstusr02 |
To change the UID for the sometest user to 1234 we’d issue:
|
1 |
# usermod -u 1234 sometest |
Add the user toki to an additional secondary group (-a for “append” - not available on Solaris):
|
1 |
# usermod -a -G sysadmin toki |
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:
|
1 |
# userdel -r toki |
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:
|
1 |
# groupadd -g 250 tstgrp |
To change the name of tstgrp to testgrp:
|
1 |
# groupmod -n testgrp tstgrp |
To remove a group:
|
1 |
# groupdel testgrp |
Password Management
Passwords are managed with the passwd command. An initial password can be set for a user (or a password reset) via:
|
1 |
# passwd <username> |
A user may reset their own password with a simple:
|
1 |
$ passwd |
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:
|
1 2 3 4 |
# grep '^[^#]' /etc/default/passwd MAXWEEKS= MINWEEKS= PASSLENGTH=6 |
And the following commented variables:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# grep '^#[A-Z]' /etc/default/passwd #NAMECHECK=NO #HISTORY=0 #MINDIFF=3 #MINALPHA=2 #MINNONALPHA=1 #MINUPPER=0 #MINLOWER=0 #MAXREPEATS=0 #MINSPECIAL=0 #MINDIGIT=0 #WHITESPACE=YES #DICTIONLIST= #DICTIONDBDIR=/var/passwd |
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:
|
1 2 |
# passwd -l tstusr01 Password information changed for tstusr01 |
Looking at /etc/shadow, you’ll see that the string *LK* has been prepended to the encrypted password field in the second field:
|
1 2 |
# fgrep tstusr01 /etc/shadow tstusr01:*LK*<encrypted password>:16034::::::4320 |
Doing the same on CentOS 6.4 for user testuser1:
|
1 2 3 4 5 |
# passwd -l testuser1 Locking password for user testuser1. passwd: Success # fgrep testuser1 /etc/shadow testuser1:!!<encrypted password>:16043:0:99999:7::: |
You can see that !! has been prepended.
To unlock the account on Solaris, use passwd -u:
|
1 2 3 4 |
# passwd -u tstusr01 passwd: password information changed for tstusr01 # fgrep tstusr01 /etc/shadow tstusr01:<encrypted password>:16034::::::4768 |
The same applies to Linux:
|
1 2 3 4 5 |
# passwd -u testuser1 Unlocking password for user testuser1. passwd: Success # fgrep testuser1 /etc/shadow testuser1:<encrypted password>:16043:0:99999:7::: |
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:
|
1 2 3 4 5 6 7 |
# groupadd -g 1010 testgrp # useradd -m -d /export/home/test01 -s /bin/bash \ > -c "Test User 01" -u 1010 -g testgrp test01 80 blocks # useradd -m -d /export/home/test02 -s /bin/bash \ > -c "Test User 02" -u 1011 -g testgrp test02 80 blocks |
Set an initial password on the two accounts:
|
1 2 3 4 5 6 7 8 |
# passwd test01 New Password: Re-enter new Password: passwd: password successfully changed for test01 # passwd test02 New Password: Re-enter new Password: passwd: password successfully changed for test02 |
Next, use passwd -f to force the users to change their passwords at login time:
|
1 2 |
# passwd -f test01 # passwd -f test02 |
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:
|
1 2 3 4 5 6 |
# vi /etc/default/password # grep '^[^#]' /etc/default/passwd MAXWEEKS=1 MINWEEKS=4 PASSLENGTH=8 HISTORY=5 |
And update any already existing user accounts:
|
1 2 |
# passwd -n 7 -x 28 -w 7 test01 passwd: password information changed for test01 |
|
1 2 |
# passwd -n 7 -x 28 -w 7 test02 passwd: password information changed for test02 |
Looking at /etc/shadow we can see the password ageing fields updated:
|
1 2 3 |
# grep '^test0[12]:' /etc/shadow test01:<encrypted password>:16034:7:28:7:::4976 test02:<encrypted password>:16034:7:28:7:::4976 |
Let’s perform the same steps on a CentOS system. Start with the group and user creation:
|
1 2 3 4 5 |
# groupadd -g 1010 testgrp # useradd -m -d /home/test01 -s /bin/bash \ > -c "Test User 01" -u 1010 -g testgrp test01 # useradd -m -d /home/test02 -s /bin/bash \ > -c "Test User 02" -u 1011 -g testgrp test02 |
Set the initial passwords:
|
1 2 3 4 5 6 7 8 9 10 |
# passwd test01 Changing password for user test01. New password: Retype new password: passwd: all authentication tokens updated successfully. # passwd test02 Changing password for user test02. New password: Retype new password: passwd: all authentication tokens updated successfully. |
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.
|
1 2 |
# chage -d 0 test01 # chage -d 0 test02 |
To configure the same password ageing policy as the Solaris example, use chage as follows:
|
1 2 3 4 5 |
# chage -m 7 -M 28 -W 7 test01 # chage -m 7 -M 28 -W 7 test02 # grep '^test0[12]:' /etc/shadow test01:<encrypted password>:0:7:28:7::: test02:<encrypted password>:0:7:28:7::: |
The defaults for new user accounts can be changed in /etc/login.defs:
|
1 2 3 4 |
PASS_MAX_DAYS 28 PASS_MIN_DAYS 7 PASS_MIN_LEN 8 PASS_WARN_AGE 7 |
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:
|
1 |
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok |
Append remember=5 to the line:
|
1 |
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=5 |
Now, if a user attempts to reuse a recent password, they’ll see a message such as the following:
|
1 2 3 4 5 6 7 8 |
$ passwd Changing password for user toki. Changing password for toki. (current) UNIX password: New password: Retype new password: Password has been already used. Choose another. passwd: Authentication token manipulation error |
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.
|
1 2 3 |
# fgrep pam_cracklib /etc/pam.d/system-auth-ac password requisite pam_cracklib.so try_first_pass retry=3 type= # man 8 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:
|
1 2 3 4 5 6 7 8 9 10 11 |
Dec 4 16:13:39 centosb groupadd[8177]: group added to /etc/group: name=testgrp, GID=1010 Dec 4 16:13:39 centosb groupadd[8177]: group added to /etc/gshadow: name=testgrp Dec 4 16:13:39 centosb groupadd[8177]: new group: name=testgrp, GID=1010 Dec 4 16:13:55 centosb useradd[8183]: new user: name=test01, UID=1010, GID=1010, home=/home/test01, shell=/bin/bash Dec 4 16:14:05 centosb useradd[8189]: new user: name=test02, UID=1011, GID=1010, home=/home/test02, shell=/bin/bash Dec 4 16:14:42 centosb passwd: pam_unix(passwd:chauthtok): password changed for test01 Dec 4 16:14:49 centosb passwd: pam_unix(passwd:chauthtok): password changed for test02 Dec 4 16:17:50 centosb chage[8255]: changed password expiry for test01 Dec 4 16:17:51 centosb chage[8258]: changed password expiry for test02 Dec 4 16:30:38 centosb chage[8282]: changed password expiry for test01 Dec 4 16:30:39 centosb chage[8285]: changed password expiry for test02 |
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:
|
1 2 3 4 5 6 7 8 9 10 |
# logins -xo root:0:root:0:Super-User:/root:/usr/bin/bash:PS:112413:-1:-1:-1 daemon:1:other:1::/:/usr/sbin/sh:NL:082587:-1:-1:-1 bin:2:bin:2::/usr/bin:/usr/sbin/sh:NL:082587:-1:-1:-1 sys:3:sys:3::/:/usr/sbin/sh:NL:082587:-1:-1:-1 adm:4:adm:4:Admin:/var/adm:/usr/sbin/sh:NL:082587:-1:-1:-1 uucp:5:uucp:5:uucp Admin:/usr/lib/uucp:/usr/sbin/sh:NL:082587:-1:-1:-1 nuucp:9:nuucp:9:uucp Admin:/var/spool/uucppublic:/usr/lib/uucp/uucico:NL:082587:-1:-1:-1 dladm:15:netadm:65:Datalink Admin:/:/usr/sbin/sh:LK:000000:-1:-1:-1 netadm:16:netadm:65:Network Admin:/:/usr/sbin/sh:LK:000000:-1:-1:-1 |
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:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# logins -m -l root root 0 root 0 Super-User other 1 bin 2 sys 3 adm 4 uucp 5 mail 6 tty 7 lp 8 nuucp 9 daemon 12 |
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:
|
1 2 3 4 5 |
# User "john" should get access from ipv6 net/mask #+ : john : 2001:4ca0:0:101::/64 # # All other users should be denied to get access from all sources. #- : ALL : ALL |
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:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# - core - limits the core file size (KB) # - data - max data size (KB) # - fsize - maximum filesize (KB) # - memlock - max locked-in-memory address space (KB) # - nofile - max number of open files # - rss - max resident set size (KB) # - stack - max stack size (KB) # - cpu - max CPU time (MIN) # - nproc - max number of processes # - as - address space limit (KB) # - maxlogins - max number of logins for this user # - maxsyslogins - max number of logins on the system # - priority - the priority to run user process with # - locks - max number of file locks the user can hold # - sigpending - max number of pending signals # - msgqueue - max memory used by POSIX message queues (bytes) # - nice - max nice priority allowed to raise to values: [-20, 19] # - rtprio - max realtime priority |
The format of entries in this file are:
|
1 2 3 4 5 6 7 8 9 |
#<domain> <type> <item> <value> # #* soft core 0 #* hard rss 10000 #@student hard nproc 20 #@faculty soft nproc 20 #@faculty hard nproc 50 #ftp hard nproc 0 #@student - maxlogins 4 |
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):
|
1 2 |
test01 soft nproc 20 test01 hard nproc 30 |
As test01, we can see the new restrictions in place:
|
1 2 3 4 |
[test01@centoshost ~]$ ulimit -Su 20 [test01@centoshost ~]$ ulimit -Hu 30 |
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
|
1 |
auth required pam_tally2.so deny=4 unlock_time=1200 |
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:
|
1 2 3 |
# pam_tally2 --user toki Login Failures Latest failure From toki 7 12/04/13 18:25:36 localhost |
Once verified that these failures are not caused by malicious means, unlock the account by resetting the tally:
|
1 2 3 4 5 6 |
# pam_tally2 --user toki --reset Login Failures Latest failure From toki 7 12/04/13 18:25:36 localhost # pam_tally2 --user toki Login Failures Latest failure From toki 0 |
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:
|
1 2 3 4 5 6 7 8 9 |
## Allows people in group wheel to run all commands # %wheel ALL=(ALL) ALL ## Same thing without a password # %wheel ALL=(ALL) NOPASSWD: ALL ## Allows members of the users group to mount and unmount the ## cdrom as root # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom ## Allows members of the users group to shutdown this system # %users localhost=/sbin/shutdown -h now |
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.
