Most users should have already created accounts through a graphical user interface during Linux installation. However, managing accounts through the command-line interface allows for finer adjustments, such as setting the password expiration date, specifying the home directory location, and choosing the default shell. It also provides an opportunity to understand the underlying principles.
Linux is a multi-user and multi-tasking operating system, allowing multiple users and groups to use it simultaneously. Therefore, managing and maintaining user accounts is a fundamental and necessary task for system administrators, especially considering that many Linux servers may not have a graphical user interface and can only be managed through command-line methods.
Now, since "/etc/passwd" no longer contains password information, let's see what it actually stores. We can observe the file by examining the first and last few lines using the head and tail commands, as shown below:
$ head -n3 /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin $ tail -n3 /etc/passwd gdm:x:42:42::/var/gdm:/sbin/nologin aaa:x:500:500::/home/aaa:/bin/bash bbb:x:501:501::/home/bbb:/bin/bash |
User Name: | Password: | UID: | GID: | Remark: | Home Directory: | Shell |
↑ | ↑ | ↑ | ↑ | ↑ | ↑ | ↑ |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
Taking the example of the "aaa" account, the entry in the "/etc/passwd" file "aaa:x:500:500::/home/aaa:/bin/bash" represents the following information from left to right: username ("aaa"), password field ("x" indicating it is stored in the shadow file), UID and GID (both set to 500), home directory ("/home/aaa"), no remark specified, and the default shell upon login ("/bin/bash").
# ls -l /etc/passwd /etc/shadow ←Checking the permissions of these two files -rw-r--r-- 1 root root 1736 2011-11-03 01:47 /etc/passwd -r-------- 1 root root 1147 2011-11-03 01:47 /etc/shadow ↑Both files are owned by "root," but only "root" has read access to "/etc/shadow." # head -n3 /etc/shadow ←Make sure to read this as "root." root:$1$iTcAPoAy$a28ghr3y112Dxtp1AGpzF0:15280:0:99999:7::: bin:*:15280:0:99999:7::: daemon:*:15280:0:99999:7::: # tail -n3 /etc/shadow gdm:!!:15280:0:99999:7::: aaa:$1$01Mc6F6n$09JiVXW1PrT5JANipdaCr/:15280:0:99999:7::: bbb:$1$oXtIbeRn$u92TjWY.Okkr8SQY2kthr1:15280:0:99999:7::: |
User Name: | Password: | Last: | May: | Must: | Warn: | Expire: | Disable: | Reserved: |
↑ | ↑ | ↑ | ↑ | ↑ | ↑ | ↑ | ↑ | ↑ |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
詳細內容如下:
When a password expiration time is set, the system will notify the user with a message like "Your password will expire in N days" when they log in. This serves as a reminder for the user to change their password before it expires.
For example, if an employee's contract is set to expire on December 30, 2012, you can calculate the number of days between that date and the UNIX Epoch Time. To do this, you can use the command "date -d '2012/12/30' +%s" to obtain the number of seconds since the UNIX Epoch Time for the given date. Then, you divide this timestamp by 86400 (the number of seconds in a day), round the result, and take the integer value as the answer.
Setting an expiration date using the "disable" field ensures that an account becomes inactive once the specified period has elapsed. This feature is commonly used for managing time-limited access or temporary user accounts, such as those created for contract employees.[note 1.1]
[aaa@localhost ~]$ passwd ←Changing own password Changing password for user aaa. Changing password for aaa. (current) UNIX password: ←Enter current password New UNIX password:←Enter new password Retype new UNIX password:←Re-enter new password (to avoid typos, it prompts for confirmation) Passwd: all authenticatin tokens updated successfully. |
The passwd command has special permissions with the SUID (Set User ID) permission, which temporarily elevates the user's privileges to root, allowing them to modify "/etc/shadow" (similarly, commands like chfn or chsh have the same special privileges). While it is possible to manually modify "/etc/shadow" as the Superuser to achieve the same result as the passwd command, it involves dealing with the 9 fields, which can be error-prone. Using passwd simplifies the process for you.
The passwd command has additional or advanced options that are typically applicable only to the Superuser. Here is an example of one such option:
Syntax:passwd [-otpiton][--option] [USER_NAME] | |||
Command name/Function/Command user | Options | Function | 註 |
passwd/ change password/ Any |
-d | Deletes the password, equivalent to removing the content in the 5th field of "/etc/shadow" | only applicable for the Superuser |
-l(lowercase L) | Lock account (add "!" or "!!" before the password field in "/etc/shadow") | only applicable for the Superuser | |
-u | Unlock the locked account (remove the "!" or "!!" added before the "/etc/shadow" password column) | only applicable for the Superuser | |
-f | If you have not set a password but used -l to lock the account, if you want to unlock the locked account at this time, you must cooperate with the option -u and use -fu to forcibly unlock the locked account | only applicable for the Superuser | |
-n | Set the number of days that the password cannot be modified, the same as modifying the fourth column in "/etc/shadow" by yourself | only applicable for the Superuser | |
-x | Set the valid number of days for the password, the same as modifying the fifth column in "/etc/shadow" by yourself | only applicable for the Superuser | |
-w | Set the number of days to issue a warning before the password is about to expire, the same as modifying the sixth column in "/etc/shadow" by yourself | only applicable for the Superuser | |
-i | Set the allowable time for password expiration, the same as modifying the seventh column in "/etc/shadow" by yourself | only applicable for the Superuser | |
-S | Simple info for output password | only applicable for the Superuser | |
--stdin | Use Standard Input Redirection to create passwords | only applicable for the Superuser | |
--help | Displays the command's built-in help and usage information |
For regular users, the passwd command can only change their own passwords. To change someone else's password, lock an account, set password expiration, or perform advanced management tasks, Superuser privileges are required. The usage for these cases is passwd username.
For example, if someone is on a leave of absence, the Superuser can use the vipw command to add a "!" or "!!" at the beginning of the password field (second field) in "/etc/shadow" to temporarily lock the account (preventing login). The "!" or "!!" is then removed when the person resumes work. However, it is recommended to use the passwd -l and passwd -u commands to simplify this process without directly editing "/etc/shadow".
Here is an example of using advanced options (applicable only to the Superuser): # useradd guest; passwd –d guest ←Create a temporary guest account without requiring a password # passwd aaa ←Change the password for the "aaa" account # passwd -l aaa ←Lock the "aaa" account (equivalent to adding "!" or "!!" at the beginning of the password field in "/etc/shadow") # passwd -u aaa ←Unlock the "aaa" account (remove the leading "!" or "!!" in the password field) # passwd -S bbb ←Display basic information about the password for the "bbb" account # passwd -x 100 bbb ←Set the password expiration for the "bbb" account to 100 days (equivalent to modifying the 5th field in "/etc/shadow" to 100) |
# echo "123abc" | passwd --stdin aaa ← Sets the password for the "aaa" account to "123abc" |
# useradd mandino ←Create an account named "mandino" # cat /etc/passwd | grep '/home/mandino' | cut -d":" -f1 ← Verify if the "mandino" account has been added to "/etc/passwd" mandino # passwd mandino ←Don't forget to immediately set a password for the newly created account |
After creating an account but before setting a password with passwd, if you observe the "/etc/passwd" file, you will notice that the password field (second field) displays "!!," indicating that the account is locked (since it exists but has no password yet). Therefore, the typical next step is to use passwd to set a password for the new account. Alternatively, you can use passwd -uf USER_NAME to forcibly unlock a locked account. However, since no password is set, this account can be accessed without a password. Although users of this account can set their preferred password after logging in, it is not recommended to rely on this approach.
The useradd command records the relevant information for the newly created account in "/etc/shadow" and "/etc/passwd". Advanced usage is as follows:
Syntax:useradd [-otpiton][--option] [USER_NAME] | ||
Command name/Function/Command user | Options | Function |
useradd/ Add account/ Superuser |
-c | Add a comment to a user account and simultaneously modify the fifth field of the "/etc/passwd" file |
-d PATH | Specify the home directory (PATH is an absolute path) , and modify the sixth column in "/etc/passwd" by yourself | |
-D | Display or change the value of the default account, can accept the following options: [-b]home directory [-e]password expiration date (the format is YYYY-MM-DD) [-f]password expiration time [-g]preset Set group [-G]additional group (supplementary groups) [-s]set the default shell when logging in |
|
-e | Set the password expiration date, the same as modifying the 8th column in " /etc/shadow " by yourself | |
-f | Set the allowable time for password expiration, and modify the seventh column in "/etc/shadow" by yourself (if the value is "-1", the seventh column in "/etc/shadow" will remain blank) |
|
-g | Set default group (group name should exist in /etc/group ) | |
-G | Set an additional group (the additional group name must exist in /etc/group), and the usage of the additional group refers to group management | |
-m | Automatically create a home directory | |
-M | Do not automatically create a home directory | |
-r | Create a system account (the system account rule is that the password field will not expire & no home directory & UID less than 500) | |
-s | Specifies the default shell at login | |
--help | Displays the command's built-in help and usage informationl |
The useradd -D command allows you to query and modify the default settings for creating new user accounts. These settings govern various aspects of account creation and can be adjusted using "useradd -D" followed by the appropriate options.
For example, running useradd -D will display the current default settings as shown below:
# useradd -D GROUP=100 ←Group ID 100 (In some distributions like Fedora, the default group name is the same as the account name, and this setting has no effect) HOME=/home ←Home directory INACTIVE=-1 ←Number of days after the password expires before the account becomes inactive. A value of "-1" means the 7th field in "/etc/shadow" is left blank EXPIRE= ←Expiration date for the password SHELL=/bin/bash ← Default login shell SKEL=/etc/skel ← Files to be copied to the new user's home directory during account creation (usually environment configuration files and hidden files) CREATE_MAIL_SPOOL=yes ←Create an email spool (creates a corresponding file in the "/var/spool/mail" directory)) |
The actual useradd -D command shows the contents of the configuration file "/etc/default/useradd". You can manually edit this file to change the default account creation rules. However, it's recommended to use useradd -D [-option] to modify the settings to avoid potential errors.
For example, let's say during the summer, a company hires temporary workers who will be employed until September 1. You can change the default account creation rules using useradd -D [-option] as follows:# useradd -D -b /home -e 2016-09-01 |
The above command changes the "/etc/default/useradd" configuration file. From now on, when you use "useradd" to create new accounts, the expiration date in the 8th field of "/etc/shadow" will be automatically set to September 1, 2016.
Here are some other examples of using "useradd" with various options:
# useradd -m -s /bin/csh joe ←Specifies that the new account "joe" will use the "C shell" as the login shell # useradd -e 2016-10-30 frank ←Sets the expiration date for the "frank" account to October 30, 2016 # useradd -u 507 phoebe ←Specifies the UID=507 for the "phoebe" account (generally, you don't need to specify the UID explicitly) # useradd -g qa kiwi ← Creates the "kiwi" account and assigns it to the "qa" group (the group name must already exist in "/etc/group") # useradd -g qa kiwi -G factory ← Similar to the previous example, but additionally assigns the "factory" group as a supplementary group (the supplementary group name must already exist in "/etc/group") |
Syntax:userdel [-otpiton][--option] [USER_NAME] | ||
Command name/Function/Command user | Options | Function |
userdel/ delete account/ Superuser |
-r | Together with this account's home directory and email spool are deleted |
--help | Displays the command's built-in help and usage information |
# userdel -r john ←Delete account "john" and its home directory and email spool together |
Since editing "/etc/passwd" and "/etc/shadow" manually can be error-prone due to the numerous fields (and because many people find the "malicious interface" of vi unpleasant), it is recommended to use usermod as introduced next for more secure account management.
usermod : Modifying an account
The usermod command is similar to a combination of useradd and passwd. It allows you to modify various aspects of a user account, such as the account name, primary group, and password expiration date. Only the Superuser has the privilege to execute this command. Here are some examples of how to use it:
Syntax:usermod [-otpiton][--option] [USER_NAME][NEW USER_NAME OLD_USER_NAME] | ||
Command name/Function/Command user | Options | Function |
usermod/ modify account/ Superuser |
-a | -a -G GROUP: Adds supplementary group "GROUP" to the user account. |
-c | Modifies the comment field, similar to manually editing the 5th field in "/etc/passwd" | |
-d PATH | Modifies the home directory to "PATH" (absolute path), similar to manually editing the 6th field in "/etc/passwd." | |
-e | Modifies the password expiration date, similar to manually editing the 8th field in "/etc/shadow" | |
-f | Modifies the password expiration warning period to "DAYS" in the "/etc/shadow" file. If the value is -1, it means the 7th field in "/etc/shadow" will be left blank (no warning will be given). | |
-g GROUP | Modifies the primary group to "GROUP" | |
-G GROUP | Adds the user to a supplementary group "GROUP" | |
-l | Modifies the account name to "NEW_USERNAME," similar to manually editing the 1st field in both "/etc/passwd" and "/etc/shadow" | |
-L | Locks the account (you can add "!" or "!!" in front of the password field in "/etc/shadow" to lock the account). | |
-s | Modifies the default shell for the user at login. | |
-u | Modifies the user's UID (User ID). | |
-U | Unlocks a locked account. | |
--help | Displays the command's built-in help and usage information |
# usermod -l micle micheal ←Changes the account name from "micheal" to "micle." # usermod -e 2016-10-30 micle ←Modifies the account expiration date to "October 30, 2016" # usermod alice -G sales ←Adds the supplementary group "sales" to the "alice" account. (The supplementary group must be created first using the "groupadd" command) # usermod alice -a -G sub_grp ←Appends the supplementary group "sub_grp" to the "alice" account |
The usage of "chfn" is as follows:
Syntax:chfn -otpiton [USER_NAME] | ||
Command name/Function/Command user | Options | Function |
chfn/ change finger information/ Any |
-f | Change the full name |
-o | Change the company name | |
-p | Change the company phone number | |
-h | Change the home phone number | |
--help | Displays the command's built-in help and usage information |
# chfn -f "John Doe" -h "123-456-7890" john ←Sequentially change the full name and home phone of the account "john" |
Syntax:chsh[-otpiton][--option] [USER_NAME] | ||
Command name/Function/Command user | Options | Function |
chsh/ Change login shell/ Any |
-s | Specifies the login shell to be used |
-l | Lists the available shells | |
--help | Displays the command's built-in help and usage information |
$ chsh -l ←Lists the available shells /bin/sh /bin/bash /sbin/nologin /bin/zsh $ chsh -s /bin/zsh ←Sets "Z Shell" as the default shell for this account (effective after logging out and logging in again) |
The chsh -s command directly modifies the "Shell" field (7th field) in "/etc/passwd," while chsh -l reads the valid shells listed in the "/etc/shells" configuration file.
A special shell is "/sbin/nologin," which is used to restrict local logins for certain accounts (e.g., system accounts) by not providing a home directory or loading a shell upon login. It is primarily used for remote logins and system accounts.
If the system is undergoing maintenance and you don't want users to log in, the superuser can create the file "/etc/nologin" using the command echo > /etc/nologin. After creating this file, all users except for the root will be prevented from logging in.
The finger command can search for both local and remote users and displays the following information:
Syntax:finger [-otpiton] [USER_NAME][@HOST] | ||
Command name/Function/Command user | Options | Function |
finger/ query account / Any |
-l | This is the default and displays the user's full name, home directory, login shell, login status, mail status, and the content of the hidden files in the user's home directory (if they exist) 〝~/.plan〞[Note 1.0A]。 〝~/.forward〞 〝~/.project〞 〝~/.pgpkey〞 |
-m | Excludes searching by full name | |
-p | Excludes displaying the content of the hidden files in the user's home directory 〝~/.plan〞 〝~/.project〞 〝~/.pgpkey〞 |
|
-s | Excludes displaying the home directory, login shell, and mail status | |
--help | Displays the command's built-in help and usage information |
The finger command is case-insensitive when searching for accounts, and it searches for both the login name and the first name in the full name.
The finger command can also be used to query remote users by specifying the format "finger user@host" or "finger@host."
Examples:
The id command has various options to provide specific information:
Syntax:id [-otpiton][--option] [USER_NAME] | ||
Command name/Function/Command user | Options | Function |
id/display account ID / Any |
-a | Displays all information about the account (this is the default value) |
-Z | Displays account information related to security context | |
-g | Displays the effective Group ID (GID) | |
-G | Displays the Group IDs of all group members | |
-n |
Displays the account or group name (used in conjunction with -g, -G, or -u options) |
|
-r | Opposite of -n, displays the UID/GID numbers of the account (used in conjunction with -g, -G, or -u options) | |
-u | Displays the effective UID (User ID) of the account | |
--help | Displays the command's built-in help and usage information |
$ id ←Displays all information about the account uid=500(aaa) gid=500(aaa) grpups=500(aaa),502(sub_grp) context=unconfined_u:syst em_r:unconfined_t:s0 $ id -G ←Queries the Group IDs of the user's group members 501 502 $ id -Gn ←ame as above, but displays group names aaa sub_grp $ id austin ←Also displays information for the account "austin" |
Here is the usage of the "who" command:
Syntax:id [-otpiton][--option] | ||
Command name/Function/Command user | Options | Function |
who/ who is logged on / Any |
-a | Display all information about logged-in users |
-b | Display the last system boot time | |
-d | Display dead processes | |
-H | Display the header line with field names. | |
-r |
Display the current runlevel | |
-q | Display the list of logged-in users and the total number of users. | |
-w or -T | Display information about users in a short format | |
i am | Display information about your own login. |
$ who -q ←Display the list of logged-in users and the total number of users root alice frank austin #user=4 $ who -r ←Display the current runlevel run-level 5 2016-06-13 05:20 $ who -b ←Display the last system boot time system boot 2016-06-11 05:20 $ who i am ←Display information about your own login alice pts/0 2016-06-13 05:21 (:0) |
$ w 17:22:40 up 1:16, 5 users, load average: 0.06, 0.12, 0.08 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root tty1 - 16:07 3:59 0.06s 0.00s vi john tty2 - 16:37 38.00s 0.07s 0.01s man consolehelp peter tty4 - 16:37 38.00s 0.07s 0.01s -bash |
Syntax:id [-otpiton][--option] [USER_NAME] | ||
Command name/Function/Command user | Options | Function |
lastlog/account login query/ Any |
-b DAYS | Displays users who last logged in before DAYS ago (from the current time) |
-t DAYS | Displays users who last logged in within the past DAYS days (from the current time) | |
--u USER | Displays the last login time for the specified USER account | |
--help | Displays the command's built-in help and usage information |
$ lastlog -b 30 ←Displays users who last logged in more than 30 days ago $ lastlog -t 7 ←Displays users who last logged in within the past 7 days $ lastlog -u leona ← Displays the last login time for the account "leona" |
If the home directory contains a ".forward" file, "finger" will display the email addresses to which emails should be forwarded. For example, if the account "john" has a ".forward" file with the following content:
$ cat ~john/.forward aaa@localhost ←Forward to the email address 'aaa@localhost' john@localhost ←Forward a copy to oneself (if one wants to keep a copy, as the system won't retain forwarded emails) |
If forwarding is not successful despite having a ".forward" file, ensure that the "other" and "group" permissions do not have the "w" (write) permission. You can use the command "chmod go-w .forward" to remove write permissions, as the system may reject forwarding for security reasons.
Additionally, if you have multiple email accounts and don't want to check each one individually, you can use ".forward" to forward all emails to a single email account, making it more efficient.
Another hidden file, ".pgpkey," is used for "PGP keys."
[Note1.1]:
In practical applications, when setting the Linux system to UTC +8 (for example, Taipei time),'date -d '1970/01/01 08:00:00' +%s will output 0, as the "UNIX epoch" is based on UTC (Coordinated Universal Time) at "January 1, 1970, 00:00." When dealing with UNIX timestamps in different time zones, it is crucial to consider the "time difference" between the local time and UTC.