user administration commands

Now that we have seen all the relevant files involved in user administration, we can proceed to learn how to create, modify and drop both users and groups. We shall start with the command line (the most flexible way of doing things) and we shall leave for the end the direct modification of the configuration files.

Let's create a user with all default values:

# useradd marc

The command above would create the username “marc” with...

- an automatically chosen UID higher than 1000 or the value stated in /etc/logins.defs→UID_MIN

- a primary group called by the same name if /etc/login.defs→USERGROUPS_ENAB is set to yes (by default it is) or the group with the GID specified in /etc/default/useradd→GROUP

- the /bin/bash shell as default or the shell specified in /etc/default/useradd→SHELL

- it would create its home folder in /home/marc and give it ownership

- the account would be locked, its password unset and the contents of /etc/skel copied onto marc's HOME folder.

As seen above the default values for the useradd command can be modified by changing the contents of /etc/default/useradd.

root:/etc> cat /etc/default/useradd
# useradd defaults file

We can create a user with customised settings using the following options.

-b --­­base­dir <BASE_DIR> → specifies the parent folder in which to create the user's home folder by concatenating it. For example using “-­b /home” in the command above would create the home folder as /home/marc.

-d --­­home­dir <HOME_DIR> → same as “-­b” but it specifies the full path. For example using “-­d /home/marc” will have the same result as the option above.

-m --­­create-­home → if the parameter /etc/login.defs → CREATE_HOME is set to “no” the user's HOME folder won't be created unless “-­m” flag is used in the useradd.

-M --no-­create-­home → this does the opposite of “­-m”: it skips HOME folder creation even if CREATE_HOME is set to “yes”.

-c --­­comment <COMMENT> → used to add extra information about the user to be created (intended use, contact details, etc)

-e --expiredate <YYYY­MM­DD> → date in which the user account will be disabled

-f --inactive <DAYS> → days after password expiration when the account is locked. A value of 0 locks the account as soon as its password expires. A value of ­1 maintains the account accessible even after password expiration.

-g --­­gid <GROUP> → main group the user belongs to. The group must exist before it is assigned to a user unless USERGROUPS_ENAB=yes in /etc/login.defs or the option “-­U” or “­­--user-group” is used. If that's the case, a new group will be created with the same name as the user.

-G --groups GROUP1,GROUP2,etc → secondary groups the user belongs to.

-k --skel <SKEL_DIR> → overrides the SKEL parameter in /etc/default/useradd and points elsewhere.

-N --no­-user-­group → do not create a personal group. Instead use the primary group provided with the “-­g” option or the default in  /etc/default/useradd → GROUP.

-U --user-­group → creates the personal group irrespective of defaults or “­-g”.

-o --­­non-­unique → used to create a user with the same UID as an existing user.

-p ­­--password <PASSWORD> → password encrypted with crypt. Not a good idea as it could be seen by users listing processes.

-s --­­shell <SHELL> → default shell the user will have.

-u --­­uid <UID> → numeric user ID explicitly chosen for the user­name

-r --­­system → create system account with no password aging, lower UID and no default HOME directory (“­-m” is a must if it needs to be created!).

Let's create another user ...

# groupadd -­g 5000 dba
# useradd -­b /home ­-u 5000 -­g dba -­c “Oracle” -­e 2016­12­31 -­f 7 ­-G staff -­s /bin/bash oracle

The command above will create the user “oracle” and its home folder in /home/oracle (this folder will obviously belong to oracle). The UID, initial group, additional groups, shell, expiration date and grace period after password expiration and before lock-down are explicitly set. Any parameter not explicitly set will be determined by the settings in /etc/login.defs and /etc/default/useradd.

The user oracle is created but the account is locked and the password not set. So we need to set it.

# passwd oracle
Changing password for user oracle.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.

If any of the parameters in /etc/security/pwquality.conf is enabled (not commented out), then those restrictions are enforced every time a user chooses a new password.

With the passwd binary we can not only set and reset a new password for a user. We also can show the status of the password for an account.

# passwd -­S oracle
oracle PS 2015­03­26 0 99999 7 ­1 (Password set, SHA512 crypt.)

The info shown would be:

1. user

2. PS for password-is-set (or “LK” for locked, or “NP” for no password)

3. date of last password change

4. minimum days before modification

5. maximum days before modification

6. days of warning before expiration

7. grace period in days after password expiration and account lock-down (“-1” means just warning but no lock-down ever)

With the "-l" flag we can lock the account:

# passwd -­l oracle
Locking password for user oracle.
passwd: Success
# passwd ­-S oracle
oracle LK 2015­03­26 0 99999 7 ­1 (Password locked.)

Beware though of locking accounts this way because the lock-down can be overcome with authentication procedures that do not use the password, for example, SSH public keys!

We can unlock an account with the “-u” flag provided it has some password assigned to it. If it does not, we can either give it one and then unlock it, or use the “-f” flag and unlock it passwordless.

We can remove a password for an account by editing /etc/shadow or by using the “-d” flag. The account will become passwordless.

With the “-e” flag we can expire a password and force the user to choose a new password at next login.

The “-n” flag sets the minimum lifetime in days for a password. If set to 0 it is disabled.

The “-x” flag sets the maximum lifetime in days for a password.

The “-w” flag sets the days of warning before the password expires.

The “-i” flag sets the days after password expiration that the account remains accessible.

We can achieve the same effect with the chage command as with passwd:

flags with passwd        flags with chage
-i or --inactive         -I or --inactive
-w or --warning          -W or --warndays
-n or --mindays          -m or --mindays
-x or --maxdays          -M or --maxdays

But the output of the “-l” flag is slightly different:

# chage -­l oracle
Last password change                               : Mar 27, 2015
Password expires                                   : never
Password inactive                                  : never
Account expires                                    : never
Minimum number of days between password change     : 0
Maximum number of days between password change     : 99999
Number of days of warning before password expires  : 7

We can also expire a password in a slightly different manner: “chage ­-d 0 oracle”.

The “-d” (or --lastday) flag changes the last day the password was changed. But if set to 0 it expires the password immediately.

The “-E” (or --expire) flag can be used to expire an account so that it can't be used at all (unlike passwd -l).

We can do that with the “chage ­-E 0” or “chage ­-E YYYY­MM­DD ” with a date that is past.

Now that we have created the users we need, we need to know how to modify them whenever required. We can do that with the usermod command in a variety of ways.

# usermod ­-g oinstall oracle        → changes the main group for oracle to oinstall
# usermod ­-g dba ­-G oinstall oracle → main group to oracle and secondary to oinstall
# usermod ­-a -­G staff oracle        → adds staff as a group keeping the current additional groups
# usermod ­-d /u01/oracle -­m oracle   → moves the HOME folder for oracle to /u01/oracle, creating it if necessary
                                      and moves the contents from old to new HOME
# usermod ­-e “” oracle              → sets the account expiration date to null, effectively
                                      disabling expiration
# usermod -­e 0 oracle               → expires the account by setting expiration date to 01­01­1970
# usermod -­f 7 oracle               → sets to 7 the number of days between password expiration and
                                      account disabling
# usermod ­-l oinstall oracle        → changes the name of the UID called oracle to oinstall.
                                      Nothing else is changed so it generally advised to
                                      also change the HOME folder to have the same name.
# usermod -­s /bin/ksh oracle        → changes the default shell for oracle to ksh
# usermod ­-U oracle                 → unlocks the oracle account
# usermod -­Z system_u oracle        → changes the SELinux content for oracle to system administrator
# usermod -­c “Oracle” oracle        → changes the comment field
# usermod ­-p “$6$LRlFH9WKVMak0zQ6$Ri7fjYpG6TXtg2OeaMgA” oracle   → changes the password hash

If a user wants to change its default shell, it can do so modifying the environment files in its own HOME folder. As a normal user can't run the usermod command, the chsh command is provided to do just that:

$ chsh -­l
$ chsh ­-s /bin/bash

Whenever we need to delete a local user (not one in NIS, NIS+ or LDAP), we can do so with the userdel command.

# userdel oracle

The command above will delete any entries in /etc/passwd and /etc/shadow. It will also delete the group of the user as long as it was a personal group (USERGROUPS_ENAB=yes in /etc/login.defs). However ...

1- its HOME directory

2- any file owned by the user

3- the mail spool

4- the cron jobs

5- and at jobs

... will be left untouched. By running userdel with the “-r” flag we can remove the HOME folder for the user and its contents as well as the mail spool. But files located elsewhere and cron/at jobs will still be there.

There are two ways around this problem. In /etc/login.defs there is an option that is commented out by default called:


We can create/edit the userdel_local script (or whatever its name we want it to be) so that it deletes cronjobs, atjobs and printjobs for the user about to be deleted:

#! /bin/sh

# Check for the required argument.
if [ $# != 1 ]; then
echo "Usage: $0 username"
exit 1

# Remove cron jobs.
crontab ­-r -­u $1

# Remove at jobs. Note that it will remove any jobs owned by the same UID,
# even if it was shared by a different user name.
find $AT_SPOOL_DIR ­-name "[^.]*" -­type f -­user $1 -­delete ;

# Remove print jobs.
lprm $1
exit 0

If we comment-in this setting and delete a user afterwards, the script above will be called with the username as the first and only parameter. This would get rid of print, cron and at jobs. Any files outside the HOME folder though would still have to be dealt with manually.

If we do not use this option in login.defs, we would have to do everything above manually every time a user account needs to be deleted.

If we need to create a large number of users in one go we can use the newusers command. This command executes user creation in batch and the only parameter is a file with the format:


# cat /tmp/newusers.txt
# newusers /tmp/newusers.txt

If we cannot or do not want to set the passwords at this stage, we can leave the 2nd field of the password set to some value that will render the account inaccessible (i.e. “LK” or “*”). Once the newusers command has successfully completed the batch creation of users, we can proceed to reset the passwords with the chpasswd command:

# cat /tmp/batch_passwd_reset.txt
# cat /tmp/batch_passwd_reset.txt | chpasswd

Bear in mind that the passwords are clear text (so set file permissions accordingly and then scrub it!) and then encrypted (MD5, DES, SHA256, SHA512) by chpasswd and persisted to disk. If there was any error running newusers or chpasswd the whole batch of changes is rolled back as this is an all or nothing operation.

The groupadd, groupdel, groupmod and gpasswd work in a very similar fashion to the commands seen before so we shall skip any further explanation on them.

However 2 more group related commands deserve a bit more commenting: newgrp & groupmems.

$ id john
uid=1000(john) gid=1000(john) groups=1000(john),10(wheel)
$ newgrp marketing
$ id john
uid=1000(john) gid=1010(marketing) groups=1000(john),10(wheel),1010(marketing)

When a user invokes the newgrp command it is in fact requesting to switch its primary group to a new one that might be password protected. The password though is only required when the user does not belong to the group (primary or secondary) as we can see below:

$ newgrp wheel
uid=1000(john) gid=10(wheel) groups=1000(marc),10(wheel),1010(marketing)

The usual way to add or remove users from groups is to edit the /etc/passwd and /etc/group, or to use the usermod command. But we can also do that with the groupmems command in ways that might be more flexible.

# grep accountancy /etc/group
# groupmems -­l -­g accountancy
marc john
# groupmems ­-d john -­g accountancy
# groupmems ­-l -­g accountancy

Only in very rare circumstances (e.g. corruption) will we need to manually edit the user configuration files. But to know how to deal with those cases we are going to create a new user called jack by editing the files directly:

# vipw                           → edit /etc/passwd with “vipw” and add the line with “*” as the locked password
# vigr                           → edit /etc/group with “vigr” and add the line
# mkdir /home/jack               → create HOME directory
# cp /etc/skel/.* /home/jack     → copy skeleton files
# chown -­R jack.jack /home/jack  → give ownership of HOME
# chmod 750 /home/jack           → reset the permissions to HOME
# chmod 600 /home/jack/.*        → reset the permissions for files
# pwconv                         → check that /etc/passwd is OK
# grpconv                        → check that /etc/group is OK
# passwd jack                    → reset jack's password and /etc/shadow will be refreshed automatically
New password:
Retype new password:
passwd: all authentication tokens updated successfully.

The account for jack should be ready for use!

If we need user accounts that should not have access to the shell, we can achieve that by assigning them the shell /sbin/nologin. But we should make sure the accounts are locked...

root:/sbin> passwd ­-S ntp
ntp LK 2015­09­13 ­1 ­1 ­1 ­1 (Password locked.)

If we do not lock the accounts an intruder that knew the password would still be able to access the system (e.g. “SSH + port forwards” or “SSH + commands + without pty).


<< configuration files             setuid, setgid & sticky bit>>