Win $20,000. Help build the future of education. Answer the call. Learn more

Learn Linux 101: Perform security administration tasks

Overview

In this tutorial, learn to review security on your Linux system. Learn to:

  • Audit a system to find files with the suid/sgid bit set.
  • Set or change user passwords and password aging information.
  • Use nmap and netstat to discover open ports on a system.
  • Set up limits on user login events, processes, and memory usage.
  • Determine which users have logged in to the system or are currently logged in.
  • Use and configure sudo.

Basic security in Linux

Your Linux system requires protection from malicious outsiders and also abuse from legitimate users. Learn the basics of protecting your Linux system.

This tutorial helps you prepare for Objective 110.1 in Topic 110 of the Linux Administrator (LPIC-1) exam 101. The objective has a weight of 3. This tutorial reflects the Version 5.0 objectives as updated on October 29, 2018.

Prerequisites

To get the most from the tutorials in this series, you need a basic knowledge of Linux and a working Linux system on which you can practice the commands that are covered in this tutorial. You should also be familiar with material covered in our tutorials Learn Linux, 101: File and directory management,Learn Linux, 101: Manage file permissions and ownership, and Learn Linux, 101: Manage user and group accounts and related system files. Sometimes, different versions of a program format output differently, so your results might not always look exactly like the listings and figures that are shown here.

The examples in this tutorial come from Fedora 33, Slackware 14.2, and Ubuntu 20.04.1 LTS.

Find files with the suid/sgid bit set

Recall that the passwd command saves your updated password in an encrypted form in /etc/shadow. If you look at the permissions on /etc/shadow, it has no permissions, meaning that only the owner (root) can read or update it. You probably wouldn’t want other people to read even an encrypted password, let alone change it. So, this behavior is reasonable. How does the passwd command manage to update /etc/shadow? The answer is the suid permission bit in the file attributes for the passwd command. Listing 1 shows the file permissions on the three basic files related to passwords. I have used the stat command to show both the usual and the octal file permissions. The more usual ls command cannot display octal permissions. Make a note of the '%#a formatting option to add a leading 0 to the octal permissions.

[ian@attic5-f33 ~]$ stat -c '%A %#a %U %G %n' /etc/shadow /etc/passwd /usr/bin/passwd
---------- 0 root root /etc/shadow
-rw-r--r-- 0644 root root /etc/passwd
-rwsr-xr-x 04755 root root /usr/bin/passwd

The -rwsr-xr-x permission bits include ‘s’ in the user section, or equivalently 4000 in the octal form. This tells you that the program is run with permissions as if the root user had invoked it. That is how it is allowed to access /etc/shadow. Obviously any executable that can access any part of the file system with root authority is a potential security exposure. How many such files are there? Use the find command with the -perm option to locate files with specific permission bits set. Listing 2 shows how to find the total number of files with the suid bit set starting at the root of the file system. You will need to run this command with root authority. For this section of the tutorial, I use a terminal session with the root login environment on my Fedora 33 system. For many systems, particularly Debian-based systems such as Ubuntu, it is more normal to use these commands using the sudo command. I will cover sudo and its configuration later in this tutorial. If you are not already familiar with using sudo, you can skip ahead to that section and then return here.

Listing 2. How many files have suid set?
[root@attic5-f33 ~]# find / -perm -4000|wc
find: ‘/run/user/1000/gvfs’: Permission denied
find: ‘/proc/49464/task/49464/fd/5’: No such file or directory
find: ‘/proc/49464/task/49464/fdinfo/5’: No such file or directory
find: ‘/proc/49464/fd/6’: No such file or directory
find: ‘/proc/49464/fdinfo/6’: No such file or directory
     26      26     618

So I have 26 files on my system with the suid bit set. Not too many to check. Notice the specification of the permission bits to match as -4000. The leading hyphen ‘-‘ tells find to match any file that has all the specified bits set. If you want to look for files with multiple bits all set this is fine and in this case, there is only one bit to check. If you want to find files that have either suid or sgid bits set you should use the ‘/’ prefix, which matches any permission setting with at least one of the specified bits set.

There are several lines of output on stderr. If you are performing a security audit, you should at least review these to be sure that there are no surprises.

The find command normally prints output to stdout. Use the -printf option to format it, for example to include specific output fields. Use -fprintf to print output to a file. Listing 3 shows how to generate a list of files in the file system with the suid bit set. I format the output to include the octal permission with a leading 0 (%#m), the owning user (%u) and the file name relative the the starting point (%p).

Listing 3. Generating a list of files with suid set
[root@attic5-f33 ~]# find / -perm /4000 -fprintf /root/suid.txt '%#m %u %p\n' 2>/dev/null
[root@attic5-f33 ~]# ls -l /root/suid.txt
-rw-r--r--. 1 root root 904 Dec  4 17:25 /root/suid.txt
[root@attic5-f33 ~]# wc /root/suid.txt
 26  78 904 /root/suid.txt
[root@attic5-f33 ~]# head -n 3 /root/suid.txt
04755 root /usr/bin/newgrp
04755 root /usr/bin/vmware-user-suid-wrapper
04755 root /usr/bin/chage

The find command supports multiple output expressions separated by the ‘,’ operator. Listing 4 shows how to generate two file lists, one with the suid set and another with the sgid set. For this example in Listing 4, I use symbolic permissions for both search and output.

Listing 4. Generating suid and sgid lists in a single traversal
[root@attic5-f33 ~]# find / \
> \( -perm /4000 -fprintf /root/suid.txt '%#m %u %p\n'   \) , \
> \( -perm -g=s -fprintf /root/sgid.txt '%#M %u %p\n' \) 2>/dev/nnull
[root@attic5-f33 ~]# head -n 3 /root/sgid.txt
drwxrwsr-x tss /run/tpm2-tss/eventlog
drwxr-sr-x root /run/log/journal
-rwxr-sr-x root /usr/bin/write

Set or change user passwords and password aging

Most users authenticate with a password when logging in to a system. Use the passwd command to change your password. You must know your current password in order to change it to something else. A system administrator can also use the passwd command to reset a forgotten password, set a temporary password that must be changed by a user during next login, specify the maximum number of days that a password can be used before it must be changed, lock a user out of the system, and other related tasks. The system administrator does not need to know a user’s current password. The passwords are actually stored in /etc/shadow in an encrypted form, so not even root can extract them.

If a user forgets his or her password, the system administrator will usually generate a temporary password that is not too complex and communicate this temporary password to the user in some fashion that doesn’t require logging into the account, perhaps face-to-face, telephone, text or email to some account not associated with the lost password. In most such case the administrator will generate a password that includes some random elements. In Listing 5, I show one simple example to generate a partially random password using the mktemp command, and then set it for user brendan who has lost his password. I use the --stdin option to read the password from stdin rather than typing it and then retyping it.

Listing 5. Resetting a user password
[root@attic5-f33 ~]# mktemp -u Pass0-XXX
Pass0-2Pr
[root@attic5-f33 ~]# echo Pass0-n0R | passwd --stdin brendan
Changing password for user brendan.
passwd: all authentication tokens updated successfully.

If you want a user to change the password before further using the system, use the -e or the --expire option to expire the password as shown in Listing 6.

Listing 6. Expiring a password
[root@attic5-f33 ~]# info passwd
[root@attic5-f33 ~]# passwd -e brendan
Expiring password for user brendan.
passwd: Success

Listing 7 shows what user brendan’s next login might look like.

Listing 7. Logging in when your password is expired
[ian@attic5-f33 l-lpic1-110-1]$ ssh brendan@attic5-f33
brendan@attic5-f33's password:
You are required to change your password immediately (administrator enforced).
You are required to change your password immediately (administrator enforced).
Last login: Mon Dec  7 22:49:43 2020 from 192.168.1.25
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user brendan.
Current password:
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
Connection to attic5-f33 closed.

You can set the maximum number of days a user is allowed to use a password before changing it, as well as the number of days in advance to issue a warning and the number of days (grace period) before the account is locked. You can also set the minimum number of days between password changes. You might want to do this if your system uses Pluggable Authentication Modules (PAMs) and you have set up rules that require a password not to match any of say the last twelve passwords. With this example requirement in place, a minimum password change period of 1 day ensures that a user cannot go back to a previously used password for at least 12 days. You can also display the current values for each duration. Either the passwd or chage command will do these tasks for you, although the parameter names differ between them. You can use chage interactively if you prefer. Listing 8 shows some examples of each command. Consult the man or info pages for full details on all parameters.

Listing 8. Using passwd and chage to set password duration
[root@attic5-f33 ~]# # Set brendan's minimum and maximum password lifetime
[root@attic5-f33 ~]# passwd -n 1 -x 90 brendan
Adjusting aging data for user brendan.
passwd: Success
[root@attic5-f33 ~]# # Set a 7 day warning period and a 14 day grace period
[root@attic5-f33 ~]# chage -W 8 -I 14 brendan
[root@attic5-f33 ~]# # Compare the settings for brendan and ian
[root@attic5-f33 ~]# passwd -S brendan
brendan PS 2020-12-07 1 90 8 14 (Password set, SHA512 crypt.)
[root@attic5-f33 ~]# passwd -S ian
ian PS 2020-12-01 0 99999 7 -1 (Password set, SHA512 crypt.)
[root@attic5-f33 ~]# # list settings using chage
[root@attic5-f33 ~]# chage -l brendan
Last password change          : Dec 08, 2020
Password expires              : Mar 08, 2021
Password inactive             : Mar 22, 2021
Account expires               : never
Minimum number of days between password change      : 1
Maximum number of days between password change      : 90
Number of days of warning before password expires   : 8

Are you surprised that the output for chage -l shows that brendan’s account never expires? The grace (or inactivity) period is the number of days after the password expires and before the password can no longer be used. The -l and -u options of passwd respectively lock or unlock the password. Password locking is accomplished by prepending the encrypted password in /etc/shadow with a ‘!’ character, which renders it invalid but can be easily reversed. The second output field in passwd -S changes to LK to indicate a locked password. Because the encrypted password is invalid, the user will see a message such as “Permission denied, please try again.” when attempting to log in. Listing 9 shows some examples.

Listing 9. Locking and unlocking a password
[root@attic5-f33 ~]# passwd -l brendan
Locking password for user brendan.
passwd: Success
[root@attic5-f33 ~]# passwd -S brendan
brendan LK 2020-11-17 1 90 8 14 (Password locked.)
[root@attic5-f33 ~]# grep brendan /etc/shadow
brendan:!!$6$Pjwv1j/M63 ... iOOQ/ct/:18584:1:90:8:14::
[root@attic5-f33 ~]# passwd -u brendan
Unlocking password for user brendan.
passwd: Success

If a user has other means of logging in such as Secure Shell (SSH) authentication tokens, these can still be used to access the account. The -E option of chage is used to either set an expiration date after which the account can no longer be used, or reinstate it (using a value of -1). Finally, the -d option of chage allows you to set the date that a user last changed a password. Listing 10 shows how to set the last password change date and also disable the account. The second part of the listing shows what happens when brendan attempts to log in.

Listing 10. Disabling an account using chage
[root@attic5-f33 ~]# date +%F
2020-12-08
[root@attic5-f33 ~]# chage -d $(date -d '20 days ago' +%F) brendan
[root@attic5-f33 ~]# chage -E $(date -d '2 days ago' +%F) brendan
[root@attic5-f33 ~]# chage -l brendan
Last password change         : Nov 18, 2020
Password expires             : Feb 16, 2021
Password inactive            : Mar 02, 2021
Account expires              : Dec 06, 2020
Minimum number of days between password change      : 1
Maximum number of days between password change      : 90
Number of days of warning before password expires   : 8

[ian@attic5-f33 l-lpic1-110-1]$ ssh brendan@attic5-f33
brendan@attic5-f33's password:
Your account has expired; please contact your system administrator.
Connection closed by 192.168.1.25 port 22

The passwd and chage commands listed above require root authority. Unprivileged users can use passwd to change their own passwords and chage with the -l option to display their password status. So they can find out when their password expires without having to wait for a warning.

Some of these functions can also be done with the usermod command. The -L and -U options lock and unlock a password by prepending a ‘!’ in /etc/shadow similar to the -l and -u options of the passwd command. Check the man or info pages for more information and note, in particular, the -e (expire date), -f (inactive days), and -p (password – not recommended) options.

Discover open ports on your system

Open ports on a system are ports that have some application listening. For example, web servers will usually have ports open for HTTP and HTTPS protocols and I have an SSH port open for administrative purposes. Use the nmap command to probe open ports on a system. Some functions of nmap work with non-root access, but many will require you to have root access. I use root access in these examples whether it is actually needed or not. Listing 11 shows the result of using nmap on the local address and the Ethernet address for my Fedora 33 system. Use either a host name or an IP address for the system to scan.

Listing 11.Basic nmap examples
[root@attic5-f33 ~]# nmap localhost
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-10 18:59 EST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000015s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 998 closed ports
PORT    STATE SERVICE
22/tcp  open  ssh
631/tcp open  ipp

Nmap done: 1 IP address (1 host up) scanned in 0.12 seconds
[root@attic5-f33 ~]#
[root@attic5-f33 ~]# nmap 192.168.1.25
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-10 18:59 EST
Nmap scan report for attic5-f33 (192.168.1.25)
Host is up (0.000011s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE
22/tcp open  ssh

Nmap done: 1 IP address (1 host up) scanned in 0.17 seconds

If you don’t recognize a port number, try using the grep command with /etc/services as shown in Listing 12.

Listing 12. What port is that?
[root@attic5-f33 ~]# grep '[[:blank:]]22\/'  /etc/services
ssh             22/tcp                          # The Secure Shell (SSH) Protocol
ssh             22/udp                          # The Secure Shell (SSH) Protocol
ssh             22/sctp                 # SSH
[root@attic5-f33 ~]# grep '[[:blank:]]631\/'  /etc/services
ipp             631/tcp                         # Internet Printing Protocol
ipp             631/udp                         # Internet Printing Protocol

These examples show that local users on my system can use ssh, scp, or sftp over port 22 and connect a web browser to port 631 to manage printers using the CUPS graphical interface. From outside ,you can only access my system using ssh.

Listing 13 shows some additional examples; first my local Slackware system and then two well-known web servers.

Listing 13. Mapping additional systems
[root@attic5-f33 ~]# # Check my Slackware system
[root@attic5-f33 ~]# nmap attic4
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-10 18:49 EST
Nmap scan report for attic4 (192.168.1.24)
Host is up (0.000041s latency).
Not shown: 997 closed ports
PORT    STATE SERVICE
22/tcp  open  ssh
37/tcp  open  time
113/tcp open  ident
MAC Address: 84:16:F9:04:7A:2A (Tp-link Technologies)

Nmap done: 1 IP address (1 host up) scanned in 0.16 seconds
[root@attic5-f33 ~]# # check a couple of web servers
[root@attic5-f33 ~]# nmap www.ibm.com
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-10 18:50 EST
Nmap scan report for www.ibm.com (104.102.193.57)
Host is up (0.020s latency).
Other addresses for www.ibm.com (not scanned): 2600:1408:5c00:3a2::b3a 2600:1408:5c00:384::b3a
rDNS record for 104.102.193.57: a104-102-193-57.deploy.static.akamaitechnologies.com
Not shown: 998 filtered ports
PORT    STATE SERVICE
80/tcp  open  http
443/tcp open  https

Nmap done: 1 IP address (1 host up) scanned in 4.62 seconds
[root@attic5-f33 ~]# nmap www.lpi.org
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-10 18:50 EST
Nmap scan report for www.lpi.org (65.39.134.146)
Host is up (0.035s latency).
Not shown: 997 filtered ports
PORT    STATE SERVICE
22/tcp  open  ssh
80/tcp  open  http
443/tcp open  https

Nmap done: 1 IP address (1 host up) scanned in 5.19 seconds

You may have noticed in these examples messages such as “Not shown: 998 filtered ports” or “Not shown: 997 closed ports”. By default, nmap scans 1000 or the most commonly used ports and displays only the open ones. A port is reported as closed if the host responds with a TCP reset message, while a port is reported as filtered if there is no response (for example, when a firewall simply drops packets). Most systems today disallow Telnet connections as these are very insecure. You can check a specific port using the -p option with either the port number or the port’s common name. This option supports a single port, a range or ports (such as 21-25, or a comma separated list, where list members may be individual ports or ranges. Use ‘*’ for a wildcard specification such as ‘http*’. Escape or quote the wildcard character to avoid shell interpretation of it. Listing 14 shows an example.

Listing 14. Checking specific ports
[root@attic5-f33 ~]#
[root@attic5-f33 ~]# nmap -p 22-25,ntp,'http*' lpi.org
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-11 21:47 EST
Nmap scan report for lpi.org (65.39.134.146)
Host is up (0.039s latency).

PORT     STATE    SERVICE
22/tcp   open     ssh
23/tcp   filtered telnet
24/tcp   filtered priv-mail
25/tcp   filtered smtp
80/tcp   open     http
123/tcp  filtered ntp
280/tcp  filtered http-mgmt
443/tcp  open     https
591/tcp  filtered http-alt
593/tcp  filtered http-rpc-epmap
4180/tcp filtered httpx
8000/tcp filtered http-alt
8008/tcp filtered http
8080/tcp filtered http-proxy
8443/tcp filtered https-alt
8990/tcp filtered http-wmap
8991/tcp filtered https-wmap

Nmap done: 1 IP address (1 host up) scanned in 1.59 seconds

If you wish to limit the scan to only UDP or only TCP, prefix a port or port range with U: or T: as appropriate, for example -p U:53,111,137,T:21-25,80.

If you want to see more detail use the -d option. Use it two times if you want to see even more verbose detail. Listing 15 shows comparison output for an open port and a filtered port.

Listing 15. Using the -d option with nmap
[root@attic5-f33 ~]# nmap -p 22-23 -d lpi.org
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-11 21:51 EST
--------------- Timing report ---------------
  hostgroups: min 1, max 100000
  rtt-timeouts: init 1000, min 100, max 10000
  max-scan-delay: TCP 1000, UDP 1000, SCTP 1000
  parallelism: min 0, max 0
  max-retries: 10, host-timeout: 0
  min-rate: 0, max-rate: 0
---------------------------------------------
Initiating Ping Scan at 21:51
Scanning lpi.org (65.39.134.146) [4 ports]
Packet capture filter (device enp9s0): dst host 192.168.1.25 and (icmp or icmp6 or ((tcp or udp or sctp) and (src host 65.39.134.146)))
We got a TCP ping packet back from 65.39.134.146 port 443 (trynum = 0)
Completed Ping Scan at 21:51, 0.07s elapsed (1 total hosts)
Overall sending rates: 60.82 packets / s, 2311.29 bytes / s.
mass_rdns: Using DNS server 127.0.0.53
Initiating Parallel DNS resolution of 1 host. at 21:51
mass_rdns: 0.00s 0/1 [#: 1, OK: 0, NX: 0, DR: 0, SF: 0, TR: 1]
Completed Parallel DNS resolution of 1 host. at 21:51, 0.00s elapsed
DNS resolution of 1 IPs took 0.00s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 21:51
Scanning lpi.org (65.39.134.146) [2 ports]
Packet capture filter (device enp9s0): dst host 192.168.1.25 and (icmp or icmp6 or ((tcp or udp or sctp) and (src host 65.39.134.146)))
Discovered open port 22/tcp on 65.39.134.146
Completed SYN Stealth Scan at 21:51, 1.32s elapsed (2 total ports)
Overall sending rates: 2.27 packets / s, 99.90 bytes / s.
Nmap scan report for lpi.org (65.39.134.146)
Host is up, received syn-ack ttl 52 (0.036s latency).
Scanned at 2020-12-11 21:51:56 EST for 1s

PORT   STATE    SERVICE REASON
22/tcp open     ssh     syn-ack ttl 52
23/tcp filtered telnet  no-response
Final times for host: srtt: 36474 rttvar: 28663  to: 151126

Read from /usr/bin/../share/nmap: nmap-payloads nmap-services.
Nmap done: 1 IP address (1 host up) scanned in 1.50 seconds
           Raw packets sent: 7 (284B) | Rcvd: 2 (88B)

The nmap command first attempts to ping the target system. Some systems, including my Microsoft® Windows® 10 system do not respond to a ping (ICMP ECHO). The -Pm option allows you to suppress the ping and continue with the scan anyway.

The nmap command has a vast array of other options, including options to attempt detection of the operating system type of the target system and the level of software listening on the port. Consult the man or info pages for more details or refer to the online documentation listed in the Resources section for this tutorial.

You can find additional information about ports on your own system using the netstat command. If you run it without any parameters, you will find a large number of UNIX® domain sockets within your system that are connected. Because you will most likely be interested in TCP or UDP connections to or from the outside world, you will generally want to use parameters such as -t for TCP connections, -u for UDP connections, or -l for ports that are listening but not connected. By default, the report uses the service name, if known. Use the -n option if you want numeric port numbers such as 22 instead of ssh. Listing 16 shows an example on my Fedora 33 system.

Listing 16. Basic use of netstat
[root@attic5-f33 ~]# netstat -t
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 attic5-f33:47540        attic4:ssh              ESTABLISHED
tcp        0      0 attic5-f33:39120        ec2-54-173-95-250:https ESTABLISHED
tcp        0      0 attic5-f33:37244        stackoverflow.com:https ESTABLISHED
tcp        0      0 attic5-f33:50860        ec2-52-37-190-150:https ESTABLISHED
tcp        1      0 attic5-f33:35326        ec2-3-211-216-81.:https CLOSE_WAIT
tcp        0      0 attic5-f33:40864        server-99-86-230-:https ESTABLISHED
tcp        0      0 attic5-f33:ssh          attic4:38340            ESTABLISHED
tcp        0      0 attic5-f33:45014        ec2-54-158-98-5.c:https ESTABLISHED
tcp6       1      0 2603-6081-1902-7d:50684 iad23s87-in-x03.1:https CLOSE_WAIT
tcp6       1      0 2603-6081-1902-7d:43824 2606:4700::6812:1:https CLOSE_WAIT
tcp6       1      0 2603-6081-1902-7d:50336 2600:9000:2191:a0:https CLOSE_WAIT
tcp6       1      0 2603-6081-1902-7d:43728 2606:4700:10::681:https CLOSE_WAIT
[root@attic5-f33 ~]# netstat -tn
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 192.168.1.25:47540      192.168.1.24:22         ESTABLISHED
tcp        0      0 192.168.1.25:39120      54.173.95.250:443       ESTABLISHED
tcp        0      0 192.168.1.25:37244      198.252.206.25:443      ESTABLISHED
tcp        0      0 192.168.1.25:50860      52.37.190.150:443       ESTABLISHED
tcp        1      0 192.168.1.25:35326      3.211.216.81:443        CLOSE_WAIT
tcp        0      0 192.168.1.25:40864      99.86.230.113:443       ESTABLISHED
tcp        0      0 192.168.1.25:22         192.168.1.24:38340      ESTABLISHED
tcp        0      0 192.168.1.25:45014      54.158.98.5:443         ESTABLISHED
tcp6       1      0 2603:6081:1902:7d:50684 2607:f8b0:4004:829::443 CLOSE_WAIT
tcp6       1      0 2603:6081:1902:7d:43824 2606:4700::6812:173:443 CLOSE_WAIT
tcp6       1      0 2603:6081:1902:7d:50336 2600:9000:2191:a00::443 CLOSE_WAIT
tcp6       1      0 2603:6081:1902:7d:43728 2606:4700:10::6814::443 CLOSE_WAIT
[root@attic5-f33 ~]# netstat -u
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
udp        0      0 attic5-f33:bootpc       _gateway:bootps         ESTABLISHED
udp        0      0 attic5-f33:bootpc       _gateway:bootps         ESTABLISHED
[root@attic5-f33 ~]# netstat -l |wc
     96     769    8200

In this example, you see several HTTPS connections from my browser as well as two SSH connections, one into my Slackware system, 192.168.1.24, and one out. In both cases the other end is my Fedora 33 system, 192.168.1.25.

Notice that there a few tcp6 entries signifying IPv6. Specify the -4 or -6 options if you want to see only IPv4 or IPv6 information. Listing 17 shows an example for IPv6 connections on the same system.

Listing 17. Displaying IPv6 connections using netstat
[root@attic5-f33 ~]# netstat -t -6
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp6       1      0 2603-6081-1902-7d:50684 iad23s87-in-x03.1:https CLOSE_WAIT
tcp6       1      0 2603-6081-1902-7d:43824 2606:4700::6812:1:https CLOSE_WAIT
tcp6       1      0 2603-6081-1902-7d:50336 2600:9000:2191:a0:https CLOSE_WAIT
tcp6       1      0 2603-6081-1902-7d:43728 2606:4700:10::681:https CLOSE_WAIT
[root@attic5-f33 ~]# netstat -u -6
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
[root@attic5-f33 ~]# netstat -l -6
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp6       0      0 [::]:hostmon            [::]:*                  LISTEN
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN
tcp6       0      0 localhost:ipp           [::]:*                  LISTEN
udp6       0      0 localhost:323           [::]:*
udp6       0      0 attic5-f3:dhcpv6-client [::]:*
udp6       0      0 [::]:60698              [::]:*
udp6       0      0 [::]:mdns               [::]:*
udp6       0      0 [::]:hostmon            [::]:*
raw6       0      0 [::]:ipv6-icmp          [::]:*                  7
raw6       0      0 [::]:ipv6-icmp          [::]:*                  7

By now you know to use the man or info pages to find more information and additional parameters that you can use.

Limit user login events, processes, and memory usage

A very long time ago in the early 1970s, I was writing Fortran code to design shock tunnel nozzles for supersonic gas flow experiments at the Australian National University. I would often work at nights during which time I discovered that my jobs would work for a while and then I could no longer start them. Somebody doing math algorithms was able to expand the memory available to his program until there was not enough memory left in the system for any other user to launch a job. Can you stop such a behavior on a multiuser Linux system? The answer is yes, using the ulimit command. Perhaps the simplest way to introduce ulimit is to use the command with the -a option to list all the limits you have for your own account. Listing 18 shows an example from my Slackware system.

Listing 18. Showing various limits with ulimit
ian@attic4-sl42:~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31590
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31590
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

User limits fall into two categories: Soft limits and hard limits. A soft limit allow users to increase or decrease their own limit up to the hard limit. A hard limit is exactly that limit beyond which non-system users cannot raise their own limits.

As an example of ulimit in action, I will set the maximum soft and hard files sizes. The sizes are specified in blocks which are 1024 bytes each on my Slackware system. Listing 19 shows how to check the block size and then set the soft limit to 10,000 blocks and the hard limit to 25,000 blocks.

Listing 19. Setting soft and hard limits with ulimit
root@attic4-sl42:~# df /home
Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/root       70425980 10505884  56319616  16% /
root@attic4-sl42:~# ulimit -Sf 10000
root@attic4-sl42:~# ulimit -Hf 25000
root@attic4-sl42:~# ulimit -Sa
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) 10000
pending signals                 (-i) 31590
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31590
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
root@attic4-sl42:~# ulimit -Hf
25000

Now consider what happens if user joe tries to create a 30 MB file filled with random data as shown in Listing 20.

Listing 20. How ulimit affects a user
joe@attic4-sl42:~$ head -c 30M </dev/urandom >testfile
File size limit exceeded
joe@attic4-sl42:~$ ls -l testfile
-rw-r--r-- 1 joe users 10240000 Dec 14 13:44 testfile
joe@attic4-sl42:~$ ulimit -Sf 40000
-su: ulimit: file size: cannot modify limit: Invalid argument
joe@attic4-sl42:~$ ulimit -Hf
25000
joe@attic4-sl42:~$ ulimit -Sf $(ulimit -Hf) # Set to maximum allowed
joe@attic4-sl42:~$ head -c 30M </dev/urandom >testfile
File size limit exceeded
joe@attic4-sl42:~$ ls -l testfile
-rw-r--r-- 1 joe users 25600000 Dec 14 13:46 testfile
joe@attic4-sl42:~$ echo $(( 25000 * 1024 )) # 25000 blocks of 1K
25600000

The limits you set using ulimit apply to all non-system users. If your system uses PAM authentication you also have some finer control over limits. Look at the file /etc/security/limits.conf or see the man or info pages for limits.conf.

Who has logged in and who is currently logged in

Often you want to know who all are using your system and what they are using. Linux usually maintains two files that contain information about logged-in users. The utmp file is often located in /var/run/utmp. It contains information about users who are currently using the system. There may also be other users as some programs do not use utmp logging. The wtmp file is usually located at /var/log/wtmp. The wtmp file records all login and logout activities as well as recording system reboots with a pseudo user of ‘~’. Both utmp and wtmp contain binary records in an identical format. A third file, btmp, if it exists, records failed login attempts. It is usually located at /var/log/btmp. Listing 21 shows these files on my Fedora 33 system.

Listing 21. Login recording files
[root@attic5-f33 ~]# ls -l /var/log/*tmp /var/run/utmp
-rw-rw----. 1 root utmp   4992 Dec 14 15:12 /var/log/btmp
-rw-rw-r--. 1 root utmp 134016 Dec 15 12:05 /var/log/wtmp
-rw-rw-r--. 1 root utmp   2688 Dec 15 12:05 /var/run/utmp

Four commands are commonly used to display information from these files.

  • The who command by default displays information from the utmp file about currently logged-in users. A non-option parameter may specify another file such as wtmp.
  • The w command combines information from the utmp file and the /proc file system to display more information about logged in users.
  • The last command displays data about a current or a previous login activity from the wtmp file.
  • The lasstb command displays information about failed login attempts from the btmp file (if this file exists).

Listing 22 shows basic usage of the who and w commands. Add the -a option to who to see additional information, including system reboot time. Add the -H option to display column headings.

Listing 22. Using who and w
[root@attic5-f33 ~]# who
ian      tty2         2020-11-29 16:44 (tty2)
ian      pts/2        2020-12-08 19:19 (192.168.1.24)
brendan  pts/4        2020-12-15 12:04 (192.168.1.25)
brendan  tty4         2020-12-15 12:05
[root@attic5-f33 ~]# who -a
           system boot  2020-11-29 14:40
           run-level 5  2020-11-29 14:40
ian      + tty2         2020-11-29 16:44  old         1810 (tty2)
ian      + pts/2        2020-12-08 19:19 00:53      118838 (192.168.1.24)
           pts/3        2020-12-10 17:36            144621 id=ts/3  term=0 exit=0
brendan  + pts/4        2020-12-15 12:04 00:53      215341 (192.168.1.25)
brendan  + tty4         2020-12-15 12:05 00:05      215433
[root@attic5-f33 ~]# who -a -H
NAME       LINE         TIME             IDLE          PID COMMENT  EXIT
           system boot  2020-11-29 14:40
           run-level 5  2020-11-29 14:40
ian      + tty2         2020-11-29 16:44  old         1810 (tty2)
ian      + pts/2        2020-12-08 19:19 00:56      118838 (192.168.1.24)
           pts/3        2020-12-10 17:36            144621 id=ts/3  term=0 exit=0
brendan  + pts/4        2020-12-15 12:04 00:56      215341 (192.168.1.25)
brendan  + tty4         2020-12-15 12:05 00:08      215433
[root@attic5-f33 ~]# w
 13:00:29 up 15 days, 22:20,  4 users,  load average: 0.25, 0.36, 0.35
USER     TTY        LOGIN@   IDLE   JCPU   PCPU WHAT
ian      tty2      29Nov20 15days  0.04s  0.04s /usr/libexec/gnome-session-binary
ian      pts/2     08Dec20 56:30   0.07s  0.01s ssh brendan@192.168.1.25
brendan  pts/4     12:04   56:21   0.04s  0.04s -bash
brendan  tty4      12:05    8:29   0.04s  0.00s cat

Both commands have several options that are further described in the man or info pages. One useful variant for who is who am i to find out who is using a terminal or terminal session. The -m option does the same thing.

The last command formats data from the wtmp file or another file such as utmp if the -f option is specified. This can be a lot of output, so you can limit it to a specified number or the most recent entries using the -n (or -num) option. Listing 23 shows an example.

Listing 23. Basic use of the last command
ian@attic4-sl42:~$ last -n 10
ian      pts/3        192.168.1.25     Sat Dec 12 21:05   still logged in
ian      pts/4        :0               Sat Dec 12 21:02 - 21:04  (00:01)
ian      pts/3        192.168.1.25     Thu Dec 10 16:52 - 21:05 (2+04:12)
ian      pts/2        :0               Tue Dec  8 18:26   still logged in
ian      pts/2        192.168.1.25     Wed Dec  2 12:58 - 12:58  (00:00)
ian      pts/3        192.168.1.25     Tue Nov 24 17:50 - 17:54  (00:03)
ian      pts/2        192.168.1.25     Tue Nov 24 13:50 - 13:50 (5+00:00)
ian      pts/2        127.0.0.1        Tue Nov 24 13:15 - 13:16  (00:00)
ian      pts/1        :0               Tue Nov 24 13:15   still logged in
ian      pts/0        :0               Tue Nov 24 13:15   still logged in

wtmp begins Sun Nov 19 15:48:30 2017

Use the -t (until time) option of the last command to see who all logged in at a specific time. The time is specified as YYYYMMDDHHMMSS, although some newer systems allow more general time formats such as ‘yesterday’ or ‘3 days ago’. Users logged in at that time show as ‘still logged in’. Some versions of last also have a -s (since time) option to list users logged in since the specified time. In such cases, the -p option combines the effect of -s and -t to display users logged in at the specific time. Some examples from Fedora 33 are shown in Listing 24.

Listing 24. Using times with last
[root@attic5-f33 ~]# last -t 20200525150000
ian      tty2         tty2             Mon May 25 14:32 - down   (00:17)
reboot   system boot  5.6.13-300.fc32. Mon May 25 14:31 - 14:49  (00:17)
ian      tty2         tty2             Fri May 22 18:29 - down  (2+18:53)
ian      tty2         tty2             Fri May 22 18:24 - 18:29  (00:04)
reboot   system boot  5.6.13-300.fc32. Fri May 22 18:24 - 13:22 (2+18:58)
ian      tty2         tty2             Fri May 22 18:21 - down   (00:02)
reboot   system boot  5.6.13-300.fc32. Fri May 22 18:21 - 18:23  (00:02)
ian      tty2         tty2             Fri May 22 17:39 - down   (00:41)
reboot   system boot  5.6.13-300.fc32. Fri May 22 17:39 - 18:20  (00:41)
ian      tty2         tty2             Fri May 22 16:54 - down   (00:40)
reboot   system boot  5.6.6-300.fc32.x Fri May 22 16:54 - 17:35  (00:41)
ian      tty2         tty2             Fri May 22 10:45 - down   (00:30)
reboot   system boot  5.6.13-300.fc32. Fri May 22 10:44 - 11:15  (00:30)
ian      tty2         tty2             Thu May 21 19:05 - down   (15:38)
reboot   system boot  5.6.6-300.fc32.x Thu May 21 19:03 - 10:44  (15:40)

wtmp begins Thu May 21 19:03:56 2020
[root@attic5-f33 ~]# last -s '7 days ago'
brendan  tty4                          Tue Dec 15 12:05   still logged in
brendan  pts/4        192.168.1.25     Tue Dec 15 12:04   still logged in
brendan  pts/4        192.168.1.25     Mon Dec 14 15:16 - 16:38  (01:22)
ian      pts/4        192.168.1.28     Sat Dec 12 08:51 - 08:51  (00:00)
ian      pts/4        192.168.1.25     Thu Dec 10 13:45 - 13:45  (00:00)
ian      pts/3        192.168.3.22     Thu Dec 10 13:41 - 17:36  (03:54)
ian      pts/2        192.168.1.24     Tue Dec  8 19:19   still logged in

wtmp begins Thu May 21 19:03:56 2020
[root@attic5-f33 ~]# last -p '7 days ago'
ian      tty2         tty2             Sun Nov 29 16:44   still logged in
reboot   system boot  5.8.17-200.fc32. Sun Nov 29 14:40   still running

wtmp begins Thu May 21 19:03:56 2020

The lastb command has the same options as the last command. It is not part of this set of objectives but I mention it for completeness. It requires the /var/log/btmp file to exist and to not be writable by others. If you have an SSH port open, or forwarded through your router to your system, you can use lastb to see how many people are trying to hack into your system using brute-force attacks. Check out an intrusion prevention system, such as fail2ban, to help block some of these attacks.

Who is using files

Sometimes you need to know who is using a file and keeping it open such that you cannot cleanly do something such as unmount a file system. The lsof command can list every open file on your system. This includes sockets and can include a large amount of data. So you generally want to have a specific purpose in mind when using lsof. You can restrict output by user using the file, by name of the command using the file, and by port, among many other possibilities. Listing 25 shows how many lines of output the lsof command produces on my system with no options.

Listing 25. How much lsof output?
[root@attic5-f33 ~]# lsof | wc
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
      Output information may be incomplete.
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1001/gvfs
      Output information may be incomplete.
 311816 3392503 43770989

You can exclude the error messages caused by the permission settings for the gvfs file systems using the -e option Listing 26 shows how to list the open connections on port 22, the files open that are associated with a user running the cat command, and the status of a specific file.

Listing 26. Using lsof
[root@attic5-f33 ~]# lsof -e /run/user/1000/gvfs -e /run/user/1001/gvfs -i TCP:22
COMMAND    PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
sshd       916 root    5u  IPv4   37936      0t0  TCP *:ssh (LISTEN)
sshd       916 root    6u  IPv6   37944      0t0  TCP *:ssh (LISTEN)
sshd    223142 root    5u  IPv4 3212396      0t0  TCP attic5-f33:ssh->attic4:40920 (ESTABLISHED)
sshd    223147  ian    5u  IPv4 3212396      0t0  TCP attic5-f33:ssh->attic4:40920 (ESTABLISHED)
[root@attic5-f33 ~]# lsof -e /run/user/1000/gvfs -e /run/user/1001/gvfs -c cat
COMMAND    PID    USER   FD   TYPE DEVICE  SIZE/OFF    NODE NAME
cat     218180 brendan  cwd    DIR    8,9      4096 2878760 /home/brendan
cat     218180 brendan  rtd    DIR    8,9      4096       2 /
cat     218180 brendan  txt    REG    8,9     37000  392787 /usr/bin/cat
cat     218180 brendan  mem    REG    8,9 223542144  392527 /usr/lib/locale/locale-archive
cat     218180 brendan  mem    REG    8,9   3222128  392896 /usr/lib64/libc-2.32.so
cat     218180 brendan  mem    REG    8,9    264360  392801 /usr/lib64/ld-2.32.so
cat     218180 brendan    0u   CHR    4,4       0t0    2070 /dev/tty4
cat     218180 brendan    1w   REG    8,9         0 2878082 /home/brendan/test-data
cat     218180 brendan    2u   CHR    4,4       0t0    2070 /dev/tty4
[root@attic5-f33 ~]# lsof -e /run/user/1000/gvfs -e /run/user/1001/gvfs ~brendan/test-data
COMMAND    PID    USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
cat     218180 brendan    1w   REG    8,9        0 2878082 /home/brendan/test-data

Another common use of lsof is to find out which user or process might be stopping you from unmounting a file system. I keep all my LPIC-1 tutorials and research data on a separate file system that I can mount across several different systems as I work. Suppose I decide to unmount that file system mounted at ~ian/data. Listing 27 shows one way I might do it and how to use lsof to find out who is stopping me.

Listing 27. Who is stopping umount?
[root@attic5-f33 ~]# df ~ian/data
Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/sdb2      128491172 72405540  49515648  60% /home/ian/data
[root@attic5-f33 ~]# umount /dev/sdb2
umount: /home/ian/data: target is busy.
[root@attic5-f33 ~]# lsof -e /run/user/1000/gvfs -e /run/user/1001/gvfs /dev/sdb2
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
oosplash  3204  ian  cwd    DIR   8,18     4096 4591924 /home/ian/data/lpic-1/l-lpic1-110-1
soffice.b 3239  ian  cwd    DIR   8,18     4096 4591924 /home/ian/data/lpic-1/l-lpic1-110-1
soffice.b 3239  ian   31uW  REG   8,18    40186 4591941 /home/ian/data/lpic-1/l-lpic1-110-1/l-lpic1-110-1.odt

Not surprisingly, it is I who have an open document as I write this tutorial!

The lsof package comes with a file called 00QUICKSTART with a large number of useful examples. It is probably located at /usr/share/doc/lsof/00QUICKSTART. If not, try running the locate 00QUICKSTART command to find it.

Note: You may need to install the mlocate package to run the locate command.

Use the fuser command to find the process that is using one or more particular files. Use the -a option if you want the output for all the files in your list, even if nobody is using any of them. Use the -k option if you want to kill the process. Use the -u option to see the username associated with the process ID. Figure 28 shows some basic examples. As usual, consult the man or info pages for additional information on other options.

Listing 28. Using fuser
[root@attic5-f33 ~]# fuser -a ~ian/bashrc ~brendan/test-data
Specified filename /home/ian/bashrc does not exist.
/home/ian/bashrc:
/home/brendan/test-data: 218180
[root@attic5-f33 ~]# fuser -u ~brendan/test-data
/home/brendan/test-data: 218180(brendan)
[root@attic5-f33 ~]# fuser -uk ~brendan/test-data
/home/brendan/test-data: 218180(brendan)
[root@attic5-f33 ~]# fuser -a ~brendan/test-data
/home/brendan/test-data:

Use and configure sudo

When you need to administer a system you usually need to run some commands with root authority. You already saw that the suid permission would allow you to do this, but there are only a limited number of special purpose commands that have this permission set. So your choices are to log in as root, become root temporarily, or gain root access for a single command. You may absolutely need to log in as the root user to fix problems, such as the one I had tonight when one of my hard drives failed. The system would not boot into graphical mode until I took that mount out of /etc/fstab. However, logging in as the root user, particularly with a graphical desktop, is not a great idea if you don’t need to do it. And if you connect to a system using SSH, you should generally not allow root login. Most SSH server installations today disallow this by default.

After you have logged in as a regular user, you can use the su command to temporarily become another user, or the sudo command to run a command as another user. These are rather loose descriptions of the differences between the commands, but many old system admins see them that way. In fact, either allow you to run a single command as another user or become another user for a series of commands. One major difference between the su and sudo commands is that you need the password of the user you want to become in order to use su while you use your own password to authenticate using sudo. When you use the su command, provide a user name as a parameter. If no user name is provided, you are assumed to be a root user.. If no command is provided, you enter an interactive shell. If you use the -, -l or --login options, the shell will be started as a login shell with an environment similar to a real login. Use the -c option if you want to run a single command or script. Look at how some of the environment variables and the current working directory change in the examples in Listing 29.

Listing 29. Basic use of su
mian@attic5-u20:~$ su mary -c 'echo $HOME;pwd'
Password:
/home/mary
/home/ian
ian@attic5-u20:~$ su - mary -c 'echo $HOME;pwd'
Password:
/home/mary
/home/mary
ian@attic5-u20:~$ su - mary
Password:
mary@attic5-u20:~$ echo $HOME;pwd
/home/mary
/home/mary
mary@attic5-u20:~$ # Use ctrl-d or logout to exit
mary@attic5-u20:~$ logout

Debian-based systems use the ‘!’ password in /etc/shadow for the root user as I described when discussing about locking passwords in the section, Set or change user passwords and password aging. So it is not possible to become root on such a system using su. You will see an authentication failure as shown in Listing 30 on my Ubuntu 20.04 LTS system.

Listing 30. Using su – on Debina-based systems
ian@attic5-u20:~$ su - -c 'echo $HOME;pwd'
Password:
su: Authentication failure
ian@attic5-u20:~$ su -
Password:
su: Authentication failure

For such systems you must use sudo to do administrative tasks that you might otherwise do by logging in or becoming the root user. Other than having different parameters, there are some subtle differences between su and sudo. In particular, all environment variables may not be set as you might expect, even if you use the -i or --login option to run the shell specified by the target user’s /etc/passwd entry as a login shell. Consider the differences between running a single command and launching an interactive shell for another user as shown in Listing 31.

Listing 31. Using sudo
ian@attic5-u20:~$ sudo -u mary echo '$HOME';pwd
[sudo] password for ian:
$HOME
/home/ian
ian@attic5-u20:~$ sudo -i -u mary echo '$HOME';pwd
/home/mary
/home/ian
ian@attic5-u20:~$ sudo -i -u mary
mary@attic5-u20:~$ echo $HOME;pwd
/home/mary
/home/mary
mary@attic5-u20:~$ logout

Notice that I only entered my password once for all three invocations of sudo as compared to having to enter it for each invocation of su. Credentials are usually cached for a configurable amount of time, usually a few minutes. That makes it easier to run several commands in succession using sudo.

Another difference between su and sudo is that it is configurable and commands that run using sudo can be logged. Default installations often set up an initial user as a member of the admin group or the wheel group. These groups are often configured to give members full root authority. Other users, say database administrators or web server operators, may be limited in the commands they are allowed to run. Some users (such as mary in my examples) may have no authority at all as I show in Listing 32.

Listing 32. User mary trying to use sudo
mary@attic5-u20:~$ sudo -u ian ls
[sudo] password for mary:
mary is not in the sudoers file.  This incident will be reported.

The configuration for sudo is usually in /etc/sudoers with additional files possibly included from the /etc/sudoers.d directory. The permission bits on these files should be 0440 (ug=r) as shown in Listing 33.

Listing 33. Sudoers files and their permissions
ian@attic5-u20:~$ ls -l /etc/sudoers*
-r--r----- 1 root root  755 Feb  3  2020 /etc/sudoers

/etc/sudoers.d:
total 8
-r--r----- 1 root root  91 Jul 10 09:59 99-snapd.conf
-r--r----- 1 root root 958 Feb  3  2020 README

These files are read-only and need to be edited using the visudo command. Traditionally, this used the vi editor, but today other editors,such as nano, may be the default. A plug-in model is used for sudo. The plug-in configuration is either defaulted or found in sudo.conf.

The info pages for sudo run to nearly 3000 lines on my Ubuntu 20.04 LTS system. Much of the specification is in Extended Backus-Naur Form (EBNF) which is briefly explained within the pages. The main components of the sudoers file are aliases and user specifications. Aliases are essentially variables that can be combined in various ways to create user specifications. User specifications say who can do what and where. The file also contains some default values and specifications if logging is enabled.

There are four kinds of aliases: User_Alias, Runas_Alias, Host_Alias, and Cmnd_Alias. User aliases and runas aliases include user names, user numbers, groups and group IDs. Host aliases include host names and IP addresses. Cmnd (command) aliases are lists of commands that a user may run. The alias ALL for any of these matches all instances. A user specification is a line of the form: who where = (as_whom) what. The default sudoers entries on my Ubuntu 20.04 LTS system look as shown in Listing 34.

Listing 34. Typical default sudoers user specifications
# User privilege specification
root    ALL=(ALL:ALL) ALL

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

For a brief introduction to explain how all this works together, I will create a rather trivial file /etc/sudoers/88-lpic-1 which will allow user mary to run the apt command to install packages. This file illustrates the use of aliases and how to set up logging so that all sudo commands and sessions are logged, except those for the reboot or sudoreplay commands. The visudo command will check the syntax of your sudoers files on exit, but you can also check it with the -c option. The example file and a check are shown in Listing 35. Note that alias names allow only upper case letters, numbers, and underscores. It must start with an uppercase letter.

Listing 35. Adding sudoer definitions and logging
ian@attic5-u20:~$ sudo cat /etc/sudoers.d/88-lpic-1
## Simple example for tutorial for LPIC-1 topic 110.1
User_Alias      INSTALLERS = ian,mary
Cmnd_Alias      PKGMGR = /usr/bin/apt
INSTALLERS     ALL = (ALL) PKGMGR

## Enable logging
Defaults     log_output
Defaults! /usr/bin/sudoreplay !log_output
Defaults! /sbin/reboot !log_output  
##

ian@attic5-u20:~$ sudo visudo -c
/etc/sudoers: parsed OK
/etc/sudoers.d/88-lpic-1: parsed OK
/etc/sudoers.d/README: parsed OK

If other specifications are absent, sudo input or output is logged in the /var/log/sudo-io/ directory.

Users can run the sudoreplay command to list all available sessions and to replay them. The list may be long so you can filter by command name, username, from date or to date, and other criteria. Listing 36 shows some examples.

Listing 36. Using sudoreplay
an@attic5-u20:~$ sudo sudoreplay -l todate "Dec 16 17:51:27"
Dec 16 17:40:56 2020 : ian : TTY=/dev/pts/0 ; CWD=/home/ian ; USER=root ; TSID=000001 ; COMMAND=/usr/sbin/visudo -c
Dec 16 17:41:15 2020 : mary : TTY=/dev/pts/1 ; CWD=/home/mary ; USER=root ; TSID=000002 ; COMMAND=/usr/bin/apt install mlocate
Dec 16 17:42:33 2020 : ian : TTY=/dev/pts/0 ; CWD=/home/ian ; USER=root ; TSID=000003 ; COMMAND=/usr/bin/ls /var/log/sudo-io
Dec 16 17:51:04 2020 : ian : TTY=/dev/pts/0 ; CWD=/home/ian ; USER=root ; TSID=000004 ; COMMAND=/usr/bin/cat /etc/sudoers/88-lpic-1
Dec 16 17:51:27 2020 : ian : TTY=/dev/pts/0 ; CWD=/home/ian ; USER=root ; TSID=000005 ; COMMAND=/usr/bin/cat /etc/sudoers/88-lpic-1
ian@attic5-u20:~$ info sudoreplay
ian@attic5-u20:~$ sudo sudoreplay -l user mary
Dec 16 17:41:15 2020 : mary : TTY=/dev/pts/1 ; CWD=/home/mary ; USER=root ; TSID=000002 ; COMMAND=/usr/bin/apt install mlocate
ian@attic5-u20:~$ sudo sudoreplay 000002
Replaying sudo session: /usr/bin/apt install mlocate
Reading package lists... Done
Building dependency tree
Reading state information... Done
mlocate is already the newest version (0.26-3ubuntu3).
0 upgraded, 0 newly installed, 0 to remove and 6 not upgraded.

The man or info pages for su, sudoers, visudo, and sudoreplay provide much more information than I can include in this tutorial. The Sudo Main Page (see Resources) is also a wealth of information.

Conclusion

This concludes your introduction to Topic 110.1: Perform security administration tasks.