To be a good in system administration, we have to understand the basics of files, processes and permissions of our Linux/Unix hosts. Therefore, in this article, we will cover the basic stuffs regarding files, processes, permissions, the SUPERUSER “root” account and the sudo program.
Every file and process on a Linux/Unix system is owned by a particular user account. Every file has both an owner and a group owner. What this means is that the owner of the file enjoys one special property that is not shared with everyone on the system. This property is the ability to modify the permissions of the file.
Other users on the system can’t access files belonging to others without the owner’s permission, so this restriction helps protect a user’s files against “malicious” users!
Please note that all credits for this article goes to the authors of the book called “LINUX ADMINISTRATION HANDBOOK”. I recommend this book for all levels of system administrators. It can be accessed from the site http://www.admin.com
Having said that, although the owner of a file can always be a single person, many people can be group owners of the file if they are all part of a single Linux/Unix group. Groups are defined in the /etc/group file.
Ownerships of a file can be shown with the ls -l filename command as shown below:
-bash-3.00$ ls -l /export/home/tek/records
-rw-r–r– 1 tek wheel 869 Jan 4 14:43 /export/home/tek/records
As seen above, the file named records is owned by the user “tek” and the group “wheel”.
Linux/Unix in reality keeps track of owners and groups represented by numbers rather than as text names. User identification numbers (UIDs) are mapped to user names in the /etc/passwd file and Group identification numbers (GIDs) are mapped to group names in the /etc/group file.
The text names that corresponds to UIDs and GIDs are designed only for the convenience of the system’s human users! Next time a command such as ls are issued which displays ownership information, then the files /etc/passwd and /etc/group are queried.
A process is the term used by Linux/Unix to represent a running program through which the running program’s use of memory, processor time, and I/O resources can be managed.
Unlike files, processes have not two but four identities associated with them. They are a real and effective UID and a real and effective GID. The “real” numbers are used for accounting purposes, and the “effective” numbers are used for the determination of access permissions.
Superuser or root privilege UID (SUID) is always equal to 0 (zero).
For example, the Real UID (RUID) is the UID of the process that created the process itself. It can be changed only if the running process has Effective UserID (EUID)=0.
The effective UID (EUID) is used to evaluate privileges of the process to perform a particular action. EUID can be changed either to Real UserID (RUID), or SUID if EUID is not equal to 0. If EUID=0, it can be changed to anything.
Most of the time, the real and effective numbers are the same.
The owner of a process can send the process signals such as kill and can also reduce the process scheduling priority.
Under normal circumstances, it is not possible for a process to change it’s 4 ownership credentials. There is a special situation in which the effective user (EUID) and group ID (EGID) can and needs to be changed.
When a command which has the “setuid” or “setgid” permissions is executed, the effective UID (EUID) or GID (EGID) of the resulting process can be set to the UID or GID of the file containing the program image rather than the UID or GID of the user executing the command.
For example, let us look at the program called “passwd“.
-bash-3.00$ ls -l /usr/bin/passwd
-r-sr-sr-x 1 root sys 22620 Jan 23 2005 /usr/bin/passwd
As you know it, passwd is the command used for changing the passwords for a given user in a Linux/Unix environment.
As can be seen above, the UID and GID permissions are set to root and sys respectively. How is it possible for a normal user to run this program then? Well that’s what we called the “setuid” or “setgid” permissions!
The normal user’s privileges are thus “promoted” for the execution of that specific command only. Hence Linux/Unix’s setuid facility allows programs run by normal users to make use of the root account in a very limited way.
As in the passwd command example below, we can see the “setuid” permissions in action:
-bash-3.00$ /usr/bin/passwd tek
Enter existing login password:
Re-enter new Password:
passwd: password successfully changed for tek
Here we see the passwd command that users run to change their login password is a setuid program. The program passwd modifies the /etc/passwd file in a very well-defined way and then terminates. To prevent abuse, the passwd program requires the users to prove that they know the current password before it agrees to make the requested password change. Nice security!
ROOT: The SUPERUSER
What exactly is the root account? Why does it has a very special place in Linux/Unix systems? Well the main defining characteristic property of the root account is that it’s UID is set to 0 (zero).
Linux/Unix systems permit the superuser (that is root) to perform any valid operation on any file or process. In addition, some process issuing system calls or requests directly to the kernel can only be executed by the superuser.
Below are some restricted operations which can only be performed by the superuser (root):
- Creating device files
- Setting the system’s hostname
- Configuring network interfaces
- Setting the system clock
- Raising resource usage limits and process priorities
- Shutting down the system
An example of superuser powers is the ability of a process owned by root to change it’s UID and GID. The login program and it’s window system equivalents like GDM and KDM are a case in point.
The login program that prompts you for your username and password when you log in to the system initially runs as root. If the username and password matches, the login program changes it’s UID and GID to your UID and GID and starts up your user environment. Once a root process has changed it’s ownerships to become a normal user process, it can never recover it’s former privileged state!
Therefore, it is extremely important for any system administrator to choose a very complex and secure password for the root user! I recommend a minimum of 8 characters with a mixture of Capital letters and numerical numbers! A warning has to be issued here, which is not to make the root’s password so complicated that you can’t remember it!
For remote administration, we obviously use the program called the Secure Shell (SSH) to manage our servers. For that matter, it is advisable to disable direct root access via SSH. To disable SSH to root user and set other security restrictions, at least enable/disable it’s parameters as shown below:
# Listen port (Default is 22, but change is to a higher port above 1025!)
# Only v2 (recommended)
# Port forwarding
# X11 tunneling options
# Ensure secure permissions on users .ssh directory.
# Default is 600 seconds. 0 means no time limit.
# Maximum number of retries for authentication
# Default is 6. Default (if unset) for MaxAuthTriesLog is MaxAuthTries / 2
###End of sshd_config###
A better way to access the root account is to use the su command. If invoked without any arguments, su will prompt for the root password and then start up a root shell. The privileges of this shell remain in effect until the shell terminates (Ctrl+D or the exit command).
su does not record the commands executed as root, but it does create a log entry that states who became root and when.
So we have to extra careful as to whom to give root’s password! It is also a good idea to get in the habit of typing the full pathname to the su command rather than relying on the shell to find the command for you!
-bash-3.00$ whereis su
su: /sbin/su /sbin/su.static /usr/bin/su /usr/man/man1m/su.1m
Note: The exact location of the su command may differ from one system to another.
Next time you want to become root, simply type:
This will give you some protection against programs called su that may have been slipped into your search path with the intention of retrieving passwords.
sudo: a limited su
Since the privileges of the superuser account cannot be subdivided, it is hard to give someone the ability to do one task (backups) without giving that person the root privileges of the root account. Also if the SUPERUSER account is used by several administrators, you will have only a vague idea of who’s using it and doing what?
These types of problems can be resolved to some extent by a program called “sudo“. It is available in Debian, RedHat, SuSE, FreeBSD packages among other distributions.
For installation in Debian, it’s as simple as: apt-get install sudo
For Fedora and Centos, it’s: yum install sudo
For FreeBSD, you just make install in /usr/ports/security/sudo
sudo takes as it’s argument a command line to be executed as root (or as another restricted user). sudo consults the file /etc/sudoers, which lists the people who are authorized to use sudo and the commands they are allowed to run on the system.
If the proposed command is permitted for the user, sudo prompts the user’s own password and executes the command.
For example, suppose we have a normal user called “john” belonging to the “wheel” group. Under normal circumstances, user “john” can’t run the tcpdump command.
To give our normal user “john” the limited sudo access to the tcpdump command, we add the following entry in /etc/sudoers file.
(1.) vi /etc/sudoers
#Add the following
john, %wheel ALL= /sbin/, /usr/sbin, /usr/sbin/tcpdump
(2.) Save and exit.
If user “john” were to run the tcpdump command without sudo, it would resemble as:
tcpdump: no suitable device found
But for user “john” to run the tcpdump command, he simply types the following sudo command:
john@localhost:~$ sudo /usr/sbin/tcpdump
Running tcpdump using sudo
Hence in this way, we can give a normal user some privilege to run a command to which only a superuser is allowed to.
Please note that I have touched only the tip of the sudo program. However below is a summary of what you can achieve using sudo:
- Accountability is much improved because of command logging
- Operators can do chores without unlimited root privileges
- The real root password can only be known to one or few users
- Privileges can be revoked without the need to change the root password
- A single file /etc/sudoers can be used to control access for an entire network.
In the Linux/Unix world, almost everything is represented by the file system. Processes, Serial ports, devices, you name it, is represented and managed via the file system.
In a nutshell, the filesystem can be summarized as:
- A namespace – a way of naming things and organizing them in a hierarchy
- An API – a set of system calls for navigating and manipulating objects
- A security model – a scheme for protecting, hiding, and sharing things
- An implementation – software that ties the logical model to actual hardware
The filesystem is presented as a single unified hierarchy that starts at the directory / and continues downward through an arbitrary number of subdirectories. / is also called the root directory.
The list of directories that must be traversed to locate a particular file, together with it’s filename, form a “pathname”. Pathnames can be either absolute (/tmp/foo) or relative (mydocs/chap4) . Relative pathnames are interpreted starting at the current directory.
The terms file, filename, pathname, and path are more or less interchangeable. Filename and path can be used for both absolute and relative paths; pathnames generally suggests an absolute path.
The filesystem can be arbitrarily deep. However, each component of a pathname must have a name no more than 255 characters long, and a single path may not contain more than 4095 characters. To access a file with a pathname longer than 4095 characters, you must cd to an intermediate directory and use relative pathname.
There are no restrictions on the naming of files and directories, except that the names are limited in length and must not contain the “/” character or nulls. Spaces are permitted but because of UNIX’s long tradition of separating command-line arguments at whitespace, legacy software tends to break when spaces appear within filenames. However, these cases are very rare nowadays.
In shell and in scripts, spaceful filenames just need to be quoted to keep their pieces together. For example, the command:
-bash-3.00$ more “My very long file.txt”
would preserve My very long file.txt as a single argument to more command.
Below is a graphical summary representing the Linux/Unix File System:
MOUNTING AND UNMOUNTING FILESYSTEMS
As seen on the diagram above, the filesystem is composed of smaller chunks – also called filesystems- each of which consists of one directory and it’s subdirectories and files. For clarity, we use the term “file tree” to refer to the overall layout of the filesystem and reserve the word “filesystem” for the chunks attached to the tree!
Most filesystems are disk partitions but they can be anything that obeys the proper API: network file servers, kernel components, memory-based disk emulators, etc.
Filesystems are attached to the tree with the mount command. mount maps a directory within the existing file tree, called the mount point, to the root of the newly attached filesystem.
For example on a Linux host,
root@localhost# mount /dev/hda4 /mbox
The above command will install the filesystem stored on the disk partition represented by /dev/hda4 under the path /mbox. You can then use command “ls /mbox” to see that filesystem’s contents.
On a Solaris host:
# mount /dev/dsk/c2d0s6 /mbox
The above command will mount a secondary hard drive represented by /dev/dsk/c2d0s6 to the path /mbox in Solaris.
A list of the filesystems that are mounted on a particular system is kept in the /etc/fstab file in Linux/FreeBSD machines. On a Solaris machines, it is kept in the /etc/vfstab file.
The information contained in this file allows filesystems to be checked (fsck -A) and mounted (mount -a) automatically at boot time. It also serves as documentation for the layout of the filesystems on disk and enables short commands such as mount /var for which the location of the filesystem to mount is looked up in /etc/fstab or /etc/vfstab.
Filesystems are detached with the umount command. You cannot unmount a filesystem that is “busy” or in use! There must not be any open files or processes whose current directories are located on that filesystem, and if the filesystem contains executable programs, they cannot be running!
When you are trying to umount a filesystem and the kernel complains that the filesystem is busy, you can run fuser to find out why.
For example, running the df -h command below shows:
df -h command
Viewing the contents of /etc/fstab:
If we try to umount /usr :
umount /usr showing as busy!
Running fuser -mv /usr:
“fuser -mv” command showing why /usr can’t be unmounted
File Types and Permissions
Linux/Unix defines seven (7) types of files. They are defined as follows:
- Regular files
- Character device files
- Block device files
- Local domain sockets
- Named pipes (FIFOs)
- Symbolic links
We can determine the type of an existing file with the ls -ld command. The first (1st) character of the ls output encodes the type of file.
# ls -ld /etc/ssh
drwxr-xr-x 2 root sys 512 Nov 21 14:28 /etc/ssh
Remembering that the 1st character determines the type of file, the table below are the codes representing various types of files:
As can be seen from the table above, rm is the universal tool for deleting files you don’t want anymore!
A word of caution: Use rm very carefully. You could mistakenly remove a very important file such needed by your system. If that happens, your system might not boot anymore!
If in doubt, always use the -i option with the rm command.
# rm -i /etc/rmmount.conf
rm: remove /etc/rmmount.conf (yes/no)?
(1.) Regular files
A regular file is just a file containing certain amount of bytes! Linux/Unix imposes no structure on its contents. Text files, data files, executable programs like gcc, shared libraries are all stored as regular files.
A directory contains named references to other files. You can create directories with the mkdir command and delete them with the rmdir command if they are empty. If the directory is not empty, you are wipe it with the rm -r command.
For example, let’s list the contents of the /etc/ssh
# ls -al /etc/ssh
drwxr-xr-x 2 root sys 512 Nov 21 14:28 .
drwxr-xr-x 87 root sys 4608 Jan 7 11:24 ..
-rw-r–r– 1 root sys 88301 Jan 22 2005 moduli
-rw-r–r– 1 root sys 861 Jan 22 2005 ssh_config
-rw——- 1 root root 668 Nov 21 14:28 ssh_host_dsa_key
-rw-r–r– 1 root root 605 Nov 21 14:28 ssh_host_dsa_key.pub
-rw——- 1 root root 883 Nov 21 14:28 ssh_host_rsa_key
-rw-r–r– 1 root root 225 Nov 21 14:28 ssh_host_rsa_key.pub
-rw-r–r– 1 root sys 5215 Jan 7 15:38 sshd_config
If you have noticed, in every directory, there are two (2) special entries “.” and “..”.
They refer to the directory itself and to its parent directory respectively; hence they cannot be removed! Since the root directory has no parent directory, the path “/..” is equivalent to the path “/.” (and both are equivalent to /).
(3.) Character and Block device files
Device files allow programs to communicate with the system’s hardware and peripherals. When the kernel is configured, modules that know how to communicate with each of the system’s devices are linked in. These days, the kernel can also load modules dynamically.
But what exactly is a kernel module? Modules are pieces of code that can be loaded and unloaded into the kernel upon demand. They extend the functionality of the kernel without the need to reboot the system. For example, one type of module is the device driver, which allows the kernel to access hardware connected to the system. Without modules, we would have to build monolithic kernels and add new functionality directly into the kernel image. Besides having larger kernels, this has the disadvantage of requiring us to rebuild and reboot the kernel every time we want new functionality.
Microsoft Windows needs to reboot so often because they lack the support of modules from their NT kernel unlike Linux/Unix!
The module for a particular device, called a device driver, takes care of the messy details of managing the device.
Device drivers present a standard communication interface that looks like a regular file. When the kernel is given a request that refers to a character or block device file, it simply passes the request to the appropriate device driver.
It is important to differentiate between device files and device drivers. The device files are are just ordinary points that are used to communicate with the drivers. They are not the drivers themselves.
But what is the difference between a character device file and a block device file? Character device files allow their associated drivers to do their own input and output (I/O) buffering.
Block device files are used by drivers that handle input and output (I/O) in large chunks and want the kernel to perform the buffering for them.
Simply, a block device would read/write bytes in fixed size blocks, as in disk sectors. Character devices read/write 0 or more bytes, in a stream, such as a TTY or a keyboard.
Device files are characterized by two numbers, called the major and minor device numbers. The major device number tells the kernel which driver the file refers to, and the minor device number tells the driver which physical unit to address.
If we on at the example below,
09:26:57 root@gw-dml-sp:~$ ls -l /dev/lp0
crw-rw—- 1 root lp 6, 0 Jan 4 13:05 /dev/lp0
From above, the major device number is 6 and the minor device number is 0.
We can create device files with the mknod command and remove them with the rm command. Most systems provide a script called /dev/MAKEDEV that creates the appropriate sets of device files for common devices.
(4.) Local domain sockets
Sockets are connections between processes that allow them to communicate in a proper manner. Linux/Unix provides several different kinds of sockets, most of which involve the use of a network. Local domain sockets are accessible only from the local host and are referred to through a filesystem object rather than a network port. They are also known as “UNIX domain sockets“.
Although socket files are visible to other processes as directory entries, they cannot be read from or written to by processes not involved in the connection. Some standard facilities that use local domain sockets are the printing system, the GNOME and KDE Window Systems, and syslog.
Local domain sockets are created with the socket system call and can be removed with the rm command or the unlink system call once they have no more users.
(5.) Named pipes
Like local domain sockets, named pipes allow communication between two processes running on the same host. They are also known as “FIFO files” (FIFO is short form for “First In, First Out”).
You can create named pipes with the mknod command and remove them with rm.
Like local domain sockets, real-world instances of named pipes are very few and rarely need administrative action.
(6.) Symbolic links
Symbolic links consist of a special type of file that serves as a reference to another file or directory. Unix-like operating systems in particular often feature symbolic links. Basically, a symbolic or soft link points to a file by name.
You can think of symbolic links in a similar way when you create “desktop shortcuts” in MS-Windows!
Unlike a hard link, which points directly to data and represents another name for the same file, a symbolic link contains a path which identifies the target of the symbolic link. Thus, when a user removes a symbolic link, the file to which it pointed remains unaffected. Symbolic links may refer to files even on other mounted file systems.
We create symbolic links with the ln -s command and remove them with the rm command.
For example, if we want to make a symbolic link between the file /etc/ssh/sshd_config and /home/tek/myssh_config, we issue the following command:
# ln -s /etc/ssh/sshd_config /home/tek/mysshd_config
# ls -l /home/tek/mysshd_config
lrwxrwxrwx 1 tek tek 20 Jan 8 21:48 /home/tek/mysshd_config -> /etc/ssh/sshd_config
FILE ATTRIBUTES AND PERMISSIONS
Every file has a set of nine (9) permission bits that control who can read, write, and execute the contents of the file. The nine permission bits are used to determine what operations on a file, and by whom.
Linux/Unix does not allow permissions to be set on a per-user basis. Instead, there are sets of permissions for the owner of the file, the group owners of the file, and everyone else. Each set has three bits: a read bit, a write bit, and an execute bit.
In a summary, there are three types of people that can do things to files – the Owner of the file, anyone in the Group that the file belongs to, and Others (everyone else). In UNIX they are referred to using the letters U (for Owner or User), G (for Group), and O (for Others).
Therefore there are three types of permissions:
r - read the file or directory w - write to the file or directory x - execute the file or search the directory
Each of these permissions can be set for any one of three types of user:
u - the user who owns the file (you) g - members of the group to which the owner belongs o - all other users
Let us look at an example:
-bash-3.00$ ls -l /usr/bin/yelp
-rwxr-xr-x 1 root other 107504 Dec 17 2004 /usr/bin/yelp
As you can see above, there are nine (9) permission bits on the file /usr/bin/yelp
On the left side, you can see the file attributes and permissions:
As can be seen, the following users have the following permissions on the file:
Owner – can read, write, and execute
Group – can read, no-write, and execute
Other – can read, no-write, and execute
Owner of /usr/bin/yelp is root and group owner of /usr/bin/yelp is other.
drwxrwxrwx : a folder which has read, write and execute permissions for the owner, the group and for other users.
-rwxr–r– : a file that can be read and written by the user, but only read and executed by the group, and only read by everyone else.
Using numbers (octal) for permissions
We can also use numbers for setting file and folder permissions. Each of the three numbers corresponds to each of the three sections of letters. The first number determines the owner permissions, the second number determines the group permissions and the third number determines the other permissions. Each number can have one of eight values ranging from 0 to 7. Each value corresponds to a certain setting of the read, write and execute permissions.
These values are added together for any one user category:
1 = execute only 2 = write only 3 = write and execute (1+2) 4 = read only 5 = read and execute (4+1) 6 = read and write (4+2) 7 = read and write and execute (4+2+1)
777 is the same as rwxrwxrwx
755 is the same as rwxr-xr-x
ls output is slightly different for a device file. For example,
09:17:07 root@gw-dml-sp:~$ ls -l /dev/tty0
crw-rw—- 1 root tty 4, 0 Jan 4 13:05 /dev/tty0
As can be seen, the file /dev/tty0 is a Character device file whose owner and group owner can read, write but could not execute it since this is a character device file!
The filesystem maintains about forty (40) separate pieces of information for each file! But the good news is that most of them are only useful for the filesystem itself. As a system administrator, we should be concerned mostly with the link count, owner, group, mode, size, last access time, last modification time, and type.
Looking at the next example,
09:32:10 root@gw-dml-sp:~$ ls -l /bin/gzip
-rwxr-xr-x 3 root root 55792 Feb 22 2005 /bin/gzip
The first field specifies the file’s type and mode. The first character is a dash, so /bin/gzip is a regular file.
The next nine characters in this field are the three sets of permission bits. I have stressed several times the order of this 3 sets of permission bits. The order is owner-group-other.
In the example of: -rwxr-xr-x 3 root root 55792 Feb 22 2005 /bin/gzip
In this case, the owner can read–write–execute, the Group owner can only execute–read and Others can only execute.
The next field in the listing is the link count for the file. In this case, it is 3, indicating that /bin/gzip is just one of three names for this file (the others are /bin/gunzip and /bin/zcat). Each time a hard link is made to a file, the count link is incremented by 1.
The setuid and setgid bits
The bits with octal values 4000 and 2000 are the setuid and setgid bits. These bits allow programs to access files and processes that would otherwise be off-limits to the user that runs them.
When set on a directory, the setuid bit causes newly created files within the directory to take on the group ownership of the directory rather than the default group of the user of the user that created the file.
The Sticky Bit
The bit with octal value 1000 is called the sticky bit. If a sticky bit is set on a directory, the filesystem won’t allow anyone to delete or rename a file unless that person is the owner of the directory, the owner of the file, or the superuser. This convention helps to make directories like /tmp a little more secure.
If the setuid bit had been set, the x representing the owner’s execute permission would have been replaced with an s, and if the setgid bit had been set, the x for the group would also have been replaced with an s.
The last character of the permissions (execute permission for “other”) is shown as t if the sticky bit of the file is turned on. If either the setuid/setgid bit or the sticky bit is set but the corresponding execute bit is not, these bits appear as S or T.
The filesystem automatically keeps track of modification time stamps, link counts, and file size information. The permission bits, ownership, and group ownership can only be changed by with the chmod, chown, chgrp commands.
chmod: change permissions
The chmod command changes the permissions on a file. Only the owner of the file and the superuser can change its permissions.
The octal notation is generally more convenient for administrators but the mnemonic syntax can be useful for new comers.
The first argument to chmod is a specification of the permissions to be assigned, and the second and subsequent arguments are names of files on which these permissions apply to.
To see chmod in action,
As can be seen above, the original permission of the file /home/tek/myprog was:
Upon issuing the command chmod 711 /home/tek/myprog, the permission was changed to:
The same effect can be applied using mnemonic syntax instead of octal notation.
chown: change ownership and group
The chown command changes the file’s ownership and group ownership. It’s syntax mirrors that of chmod, except that the first argument specifies the new owner and group in the form of user.group (user:group). Either of user or group may be left out. If there is no group, you don’t need the dot either.
Looking at the example below:
The above command changes the owner:group of the file /home/tek/robots.txt from root:root to tek:wheel.
To change a file’s group, you must either be the owner of the file and belong to the group you’re changing to or be the superuser. However, you must be the superuser to change the file’s owner.
Like chmod, chown offers the recursive -R flag to change the settings of a directory and all the files underneath it. For example, the sequence:
# chmod -755 ~john
# chown -R john:wheel ~john
might be used to setup the home directory of a new user called john after copying the default startup files. The commands above will set the directory /home/john and all it’s files and sub directories to be owned by user john and group wheel.
Traditional UNIX uses a separate command called chgrp, to change the group owner of a file. Linux provides the chgrp command too. It works just like chown but chgrp takes just a parameter which is the group owner.
The above chgrp command will change the group owner from tek to wheel.
I hope that the materials above will serve as a basis to understand the file system and structure of your Linux/Unix machines. It should also give you hindsights to avoid common mistakes such as making a important file to be read, written, or executed by everybody. It should also provide you how to protect and give access to important files and directories only to certain users on your system.