Example for etcpasswd etcshadow and etcgroup

Paolo Predonzani edited this page Dec 27, 2017 · 2 revisions

/etc/passwd /etc/shadow and /etc/group make up the core of user and group management on a Linux/*nix system. On systems with many users (think of company or department servers) they are probably complemented by a directory service. But on standalone servers these three files are all there is, so their content is very important.

Testing these files is useful for a number of reasons:

  • to know if a certain user or group exists
  • to make sure a certain user can login (i.e. is enabled)
  • to verify that a group has certain member users

These reasons are valuable also in their negative form. In security, it is as important to know that a user is in a group, as to know that a user is NOT in group.

Looking at these files manually is tedious and error-prone. So we're going to use Tstconfig to automate this task.

Testing /etc/passwd

Create a file called users.tstconfig and start the test with the following content:

# Configuration file
file /etc/passwd

# The syntax to use
syntax etc_passwd

/etc/passwd is made of lines, one per user. Each line is made of seven fields:

  • username
  • password
  • user id
  • primary group id
  • user info
  • home directory
  • login shell

For this tutorial, we're interested in the username and the login shell. The other fields can be ignored. Going back to the users.tstconfig file we can express this as follows:

columns 0 6

Counting from zero, '0' is the username, '6' is the login shell. Now we can write a test for user 'myuser':

property myuser
assert_eq /bin/bash

We could repeat this operation for each user but it would be time-consuming. Instead, we could reverse the order of the columns and treat the shell as the property name, and the user as the property value.

columns 6 0

# '/usr/sbin/nologin' means the user cannot login 
property /usr/sbin/nologin
assert_contains daemon bin sys games man lp mail news uucp proxy www-data backup list irc gnats nobody sshd

# /bin/false serves a similar puprose
property /bin/false
assert_contains syslog messagebus mysql colord

With just four lines, we have tested that about 20 key system users cannot login to a shell.

Finally, save users.tstconfig and run the following command:

$ tstconfig users.tstconfig 
Tstconfig 0.2

Reading definition file: users.tstconfig

Assertions tested: 3
Assertions passed: 3
Assertions failed: 0
Errors: 0

The report shows that all tests passed.

Testing /etc/shadow

For security reasons, /etc/shadow can only be read by root. To read it in our tests, we have to use a different approach. In users.tstconfig add these lines:

# Read /etc/shadow as sudo
command sudo cat /etc/shadow
syntax etc_passwd

/etc/shadow is organised in lines and fields, similarly to /etc/passwd. There are eight fields:

  • username
  • encrypted password
  • last password change
  • minimum number of days before change allowed
  • maximum number of days before expiry
  • number of warning days before expiry
  • number of days after expiry before account is disabled
  • fixed date at which account is disabled

Of all these fields, we're going to use the first two:

# Consider username and password only
columns 0 1

Testing the password is not useful in itself, as passwords are encrypted. However there is a rule whereby if a password starts with symbols '!' or '*' then the username is considered disabled.

To test if the root account is disabled we could write:

property root
assert_eq !

Save users.tstconfig and launch the tests:

$ tstconfig users.tstconfig 
Tstconfig 0.2

Reading definition file: users.tstconfig
 Command:   sudo cat /etc/shadow
 Property:  root
 Value:     $6$ehdtSs2J$kGzf8ZDmOMJlZHgDjxbTJpvXXDyW2wy34zCuBn3FypStNkCOjWoRnIc5pY1BGqnoihk7XmCs4lfDCYoS78QR3.
 Assertion: assert_eq !

Assertions tested: 4
Assertions passed: 3
Assertions failed: 1
Errors: 0

The report failed and shows that, on the system where the test was performed, account root is not disabled. Disabling root and re-running the test will make all tests pass.

Testing /etc/group

The /etc/group file is made of lines organised in four fields:

  • the group name
  • a password (not really used)
  • the gid or group id
  • the member users

To test it, add the following lines to users.tstconfig:

file /etc/group
syntax etc_group

Here the useful fields are the group name (0) and the members (3):

columns 0 3

Meaningful tests are to check the members of privileged groups:

# Check that nobody is in the root group
property root

# The adm group grants access, e.g., to certain logs
property adm
assert_eq syslog,myuser

# The sudoers
property sudo
assert_eq myuser

# Access to web server files
property www-data
assert_eq myuser

You may wonder why the root group is tested to be empty, while we know that the root user does belong to the root group. The reason lies in the difference between primary and secondary group membership. Primary group membership is defined in /etc/passwd, while secondary group membership is defined in /etc/group. Going back to the example, the root user has root as the primary group, which justifies the possibility for the group to have no members as far as /etc/group is concerned.

Testing a user's groups

In the previous section we asked the question 'What users are members of group X?'. It would make sense to ask another question: 'What groups does user Y belong to?'. This would mean querying /etc/group by user instead of by group. Unfortunately this is not possible given the syntax of /etc/group and the way Tstconfig works.

As a workaround, we can use the Linux command called groups. Let's give it a try:

$ groups myuser
myuser : myuser adm cdrom sudo dip www-data plugdev lpadmin sambashare

The output is a key-values map that Tstconfig can handle easy. Edit users.tstconfig and add these few lines:

# Test a single user's group membership
command groups myuser
parse_mode keyvalue
key_separator :

# expect a single line, with the given user as the key
property myuser
assert_contains adm www-data
assert_not_contains root

The usual contains/not_contains/eq assertions are possible.


On a Linux system there are many configuration files that are essentially tables. Tstconfig has the following commands to 'query' their contents:

  • file: to read a configuration file
  • command: to execute a Linux command and parse its output
  • syntax/parse_mode/key_separator/...: to specify the format for parsing
  • columns: to focus only on certain columns and ignore the others
  • property: to select a certain row
  • assert_*: to check the values of a row

This page has shown how with these simple commands you can perform a variety of tests and enforce security and good configuration on your systems.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.