UNIX-like operating systems use a hierarchical filesystem to store files and directories. Directories can contain files and other directories, the top directory (/) is named the root directory (not to be confused with the /root directory). Most filesystems also support file links (which provide alternative names for a file) and soft links. Other filesystems can be "connected" to an arbitrary directory. This process is named "mounting", and the directory in which the filesystem is mounted is named the "mount point".
This chapter covers the basic navigation of the filesystem, commands which are used to remove and create directories, filesystem permissions, links and mounting.
pwd(1) is a simple utility which shows the directory you are currently working in. The pwd does not require any parameters. This is an example output of pwd:
$ pwd /home/danieldk
ls is similar to the dir command in DOS and Windows. ls can be used to display files and directories located in specific directories. Running the ls command without any parameters shows the contents of the current directory:
$ ls COPYING CVS Makefile README html images pdf src tex
Naturally it is also possible to show the contents of other directories. You can do this by specifying the path as a parameter tot the ls command:
$ ls / bin cdrom dev floppy initrd lost+found opt root sys usr windows boot cdrom1 etc home lib mnt proc sbin tmp var
A disadvantage of the default output is that it provides little information about files and directories. For example, it is not possible to see whether some entry is a file or directory, what size a file is, or who the owner of the file is. The ls has the -l parameter to show more information:
$ ls -l total 52 -rw-r--r-- 1 daniel daniel 20398 Jul 16 14:28 COPYING drwxr-xr-x 2 daniel daniel 4096 Jul 16 14:28 CVS -rw-r--r-- 1 daniel daniel 768 Jul 16 14:28 Makefile -rw-r--r-- 1 daniel daniel 408 Jul 16 14:28 README drwxr-xr-x 3 daniel daniel 4096 Jul 16 14:28 html drwxr-xr-x 3 daniel daniel 4096 Jul 16 14:28 images drwxr-xr-x 3 daniel daniel 4096 Jul 16 14:28 pdf drwxr-xr-x 3 daniel daniel 4096 Jul 20 00:11 src drwxr-xr-x 3 daniel daniel 4096 Jul 16 14:28 tex
Another important command is the cd command. It can be used to change the current working directory:
$ cd /home/danieldk/
With the pwd command you can see it worked:
$ pwd /home/danieldk
As you might have guessed, the mkdir(1) command can be used to create directories. For example:
$ pwd /home/danieldk $ mkdir test $ cd test $ pwd /home/danieldk/test
It might happen that you want to create a directory in a parent directory which does not exist yet. For example, if you want to create the test2/hello/ directory, but the test2 directory does not yet exist. In this case you can make both directories with only one mkdir command:
$ mkdir -p test2/hello
Files can be copied with the cp(1) command, the basic syntax is cp source destination. For example, suppose that we have a file named memo which we would like to copy to the writings directory. You can do this with the following command:
$ cp memo writings/
It is also possible to copy a file in the same directory. For example, if we would like to make a new memo based on memo, named memo2, we could execute the following command:
$ cp memo memo2
It is also possible to copy directories recursively, this can be done by adding the -r parameter. The following command copies the memos directory, and all subdirectories, and (sub)files to the writings directory:
$ cp -r memos writings/
The mv(1) command is comparable to cp, but it is used to move files. Suppose that we have the same situation as in the first cp example, but you would rather like to move memo to the writings directory. The following command would do that:
$ mv memo writings/
It is also possible to move directories. But, mv always works recursively. For example, the following command will move the memos directory to the writings directory:
$ mv memos writings/
The rm(1) command is used to remove files and directories. Let's look at a simple example:
$ rm hello.c
This commands removes the file hello.c. Sometimes the rm asks for a confirmation. You can ignore this with the -f parameter:
$ rm -f *
This command removes all files in the current directory without asking for confirmation. It is also possible to delete directories or even whole directory trees. rm provides the -r parameter to do this. Suppose that we want to delete the ogle directory and all subdirectories and files in that directory, this can be done in the following way:
$ rm -r -f ogle/
Many commands allow you to combine parameters. The following example is equivalent to the last one:
$ rm -rf ogle/
Every file in GNU/Linux has permissions. As you might have noticed, file permissions can be shown with the ls -l command:
$ ls -l logo.jpg -rw-r--r-- 1 danieldk users 9253 Dec 23 19:12 logo.jpg
The permissions are shown in the first column. Permissions that can be set are read(r), write(w) and execute(x). These permissions can we set for three classes: owner(u), group(g) and others(o). The permissions are visible in the second to ninth character in the first column. These nine characters are divided in three groups. The first three characters represent the permissions for the owner, the next three characters represent the permissions for the group, finally the last three characters represent the permissions for other users. Thus, the example file shown above can be written to by the owner and can be read by all three classes of users (owner, group and others).
Each GNU/Linux system has many distinct users (a list of users can be found in /etc/passwd), and a user can be a member of certain groups. This kind of user management provides makes it possible to manage detailed permissions for each file. In the example shown above danieldk is the owner of the file and group permissions apply to the group users. In this example groups rights do not differ from the rights of other users.
The chown(1) command is used to set the file owner and to which group group permissions should apply to. Suppose we want to make danieldk the owner of the file logo2.jpg, this can be done with the chown:
# chown danieldk logo2.jpg
Using the ls we can see that the owner is now danieldk:
# ls -l logo2.jpg -rw-r--r-- 1 root root 9253 Dec 29 11:35 logo2.jpg # chown danieldk logo2.jpg # ls -l logo2.jpg -rw-r--r-- 1 danieldk root 9253 Dec 29 11:35 logo2.jpg
But group permissions still apply for the root group. This group can be changed by adding a colon after the owner, followed by the name of the group (in this example the group is nedslackers):
# chown danieldk:nedslackers logo2.jpg # ls -l logo2.jpg -rw-r--r-- 1 danieldk nedslackers 9253 Dec 29 11:35 logo2.jpg
It is also possible to change ownership recursively, this can be done with the recursive (-R) parameter:
# chown -R danieldk:users oggs/
File permissions can be manipulated using the chmod(1) command. The most basic syntax of chmod is chmod [u,g,o][+/-][r,w,x] filename. The first parameter consists of the following elements: 1. which classes this manipulation permission applies to, 2. if the permissions should be added (+) or removed (-), and 3. which permissions should be manipulated. Suppose we want to make the file memo writable for the owner of the file and the groups for which the group permissions apply. This can be done with the following command:
$ chmod ug+w memo
As you can see below the memo is now writable for the file owner and group:
$ ls -l memo -r--r--r-- 1 daniel users 12 Mar 9 16:28 memo bash-2.05b$ chmod ug+w memo bash-2.05b$ ls -l notes -rw-rw-r-- 1 daniel users 12 Mar 9 16:28 memo
Just like the chown command it is also possible to do recursive (-R) operations. In the following example the secret/, including subdirectories and files in this directory, is made unreadable for the group set for this directory and other users:
$ chmod -R go-r secret/
Sooner or later a GNU/Linux user will encounter tar archives, tar is the standard format for archiving files on GNU/Linux. It is often used in conjunction with gzip or bzip2. Both commands can compress files and archives. Table 8-1 lists frequently used archive extensions, and what they mean.
Table 8-1. Archive file extensions
Extension | Meaning |
---|---|
.tar | An uncompressed tar archive |
.tar.gz | A tar archive compressed with gzip |
.tgz | A tar archive compressed with gzip |
.tar.bz2 | A tar archive compressed with bzip2 |
.tbz | A tar archive compressed with bzip2 |
The difference between bzip2 and gzip is that bzip2 can find repeating information in larger blocks, resulting in better compression. But bzip2 is also a lot slower, because it does more data analysis.
Since many software and data in the GNU/Linux world is archived with tar it is important to get used to extracting tar archives. The first thing you will often want to do when you receive a tar archive is to list its contents. This can be achieved by using the t parameter. However, if we just execute tar with this parameter and the name of the archive it will just sit and wait until you enter something to the standard input:
$ tar t test.tar
This happens because tar reads data from its standard input. If you forgot how redirection works, it is a good idea to reread Section 7.3.5. Let's see what happens if we redirect our tar archive to tar:
$ tar t < test.tar test/ test/test2 test/test1
That looks more like the output you probably expected. This archive seems to contain a directory test, which contains the files test2 and test2. It is also possible to specify the archive file name as an parameter to tar, by using the f parameter:
$ tar tf test.tar test/ test/test2 test/test1
This looks like an archive that contains useful files ;). We can now go ahead, and extract this archive by using the x parameter:
$ tar xf test.tar
We can now verify that tar really extracted the archive by listing the contents of the directory with ls:
$ ls test/ test1 test2
Extracting or listing files from a gzipped or bzipped archive is not much more difficult. This can be done by adding a z or b for respectively archives compressed with gzip or bzip2. For example, we can list the contents of a gzipped archive with:
$ tar ztf archive2.tar.gz
And a bzipped archive can be extracted with:
$ tar bxf archive3.tar.bz2
You can create archives with the c parameter. Suppose that we have the directory test shown in the previous example. We can make an archive with the test directory and the files in this directory with:
$ tar cf important-files.tar test
This will create the important-files.tar archive (which is specified with the f parameter). We can now verify the archive:
$ tar tf important-files.tar test/ test/test2 test/test1
Creating a gzipped or bzipped archive goes along the same lines as extracting compressed archives: add a z for gzipping an archive, or b for bzipping an archive. Suppose that we wanted to create a gzip compressed version of the archive created above. We can do this with:
tar zcf important-files.tar.gz test
Extended attributes (EAs) are relatively new on GNU/Linux. Extended attributes are a special kind of values that are associated with a file or directory. EAs provide the means to add extra attributes besides the common attributes (modification time, traditional file permissions, etc.). For example, one could add the attribute "Photographer" to a collection of JPEG files. Extended attributes are not physically stored in the file, but as meta-data in the filesystem.
Extended attributes are only supported by 2.6.x and newer 2.4.x kernels. Besides that they are not supported on all filesystems, the commonly used Ext2, Ext3 and XFS filesystems do support extended attributes.
The extended attribute software is available in Slackware Linux through the xfsprogs package, which can be found in the "a" disk set. Don't be misled by the name of the package, the extended attribute tools also work with other filesystems, like Ext3.
Extended attributes can be queried using the getfattr command. Just using getfattr with a file as a parameter will show the attributes that are known for that particular file, without the values set for the attributes. For example:
$ getfattr note.txt # file: note.txt user.Author
This file has one extended attribute, "user.Author". An attribute has the following form: "namespace.attribute". There are four defined namespaces: "security", "system", "trusted", and "user". The role of these namespaces are described in the attr(5) manual page. The "user" namespace is of particular interest to us, because this namespace is used to assign arbitrary attributes to files.
The values associated with an attribute can be shown using the -d (dump) parameter. For example:
$ getfattr -d note.txt # file: note.txt user.Author="Daniel"
In this example the attribute "user.Author" has the value "Daniel" for the file note.txt.
Attributes are set with the setfattr command. An attribute can be added to a file using the -n (name) parameter, be sure to specify the namespace and the attribute name, for example:
$ setfattr -n user.Author note2.txt
The value of the attribute can be set using the -v (value) parameter:
$ setfattr -n user.Author -v Mike note2.txt
But it is also possible to add an attribute and setting its value in one run, by specifying both the -n and -v parameters. For example, the following command adds the MD5 sum of the file as an extended attribute:
$ setfattr -n user.MD5 -v `md5sum note2.txt` note2.txt $ getfattr -d note2.txt # file: note2.txt user.Author="Mike" user.MD5="78be7a3148027ae7a897aad95e7d9c58"
Like most Unices Linux uses a technique named "mounting" to access filesystems. Mounting means that a filesystem is connected to a directory in the root filesystem. One could for example mount a CD-ROM drive to the /mnt/cdrom directory. Linux supports many kinds of filesystems, like Ext2, Ext3, ReiserFS, JFS, XFS, ISO9660 (used for CD-ROMs), UDF (used on some DVDs) and DOS/Windows filesystems, like FAT, FAT32 and NTFS. These filesystems can reside on many kinds of media, for example hard drives, CD-ROMs and Flash drives. This section explains how filesystems can be mounted and unmounted.
The mount(8) is used to mount filesystems. The basic syntax is: "mount /dev/devname /mountpoint". The device name can be any block device, like hard disks or CD-ROM drives. The mount point can be an arbitrary point in the root filesystem. Let's look at an example:
# mount /dev/cdrom /mnt/cdrom
This mounts the /dev/cdrom on the /mnt/cdrom mountpoint. The /dev/cdrom device name is normally a link to the real CD-ROM device name (for example, /dev/hdc). As you can see, the concept is actually very simple, it just takes some time to learn the device names ;). Sometimes it is necessary to specify which kind of filesystem you are trying to mount. The filesystem type can be specified by adding the -t parameter:
# mount -t vfat /dev/sda1 /mnt/flash
This mounts the vfat filesystem on /dev/sda1 to /mnt/flash.
The umount(8) command is used to unmount filesystems. umount accepts two kinds of parameters, mount points or devices. For example:
# umount /mnt/cdrom # umount /dev/sda1
The first command unmounts the filesystem that was mounted on /mnt/cdrom, the second commands unmounts the filesystem on /dev/sda1.
The GNU/Linux system has a special file, /etc/fstab, that specifies which filesystems should be mounted during the system boot. Let's look at an example:
/dev/hda10 swap swap defaults 0 0 /dev/hda5 / xfs defaults 1 1 /dev/hda6 /var xfs defaults 1 2 /dev/hda7 /tmp xfs defaults 1 2 /dev/hda8 /home xfs defaults 1 2 /dev/hda9 /usr xfs defaults 1 2 /dev/cdrom /mnt/cdrom iso9660 noauto,owner,ro 0 0 /dev/fd0 /mnt/floppy auto noauto,owner 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 proc /proc proc defaults 0 0
As you can see each entry in the fstab file has five entries: fs_spec, fs_file, fs_vfstype, fs_mntops, fs_freq, and fs_passno. We are now going to look at each entry.
The fs_spec option specifies the block device, or remote filesystem that should be mounted. As you can see in the example several /dev/hda partitions are specified, as well as the CD-ROM drive and floppy drive. When NFS volumes are mounted an IP address and directory can be specified, for example: 192.168.1.10:/exports/data.
fs_file specifies the mount point. This can be an arbitrary directory in the filesystem.
This option specifies what kind of filesystem the entry represents. For example this can be: ext2, ext3, reiserfs, xfs, nfs, vfat, or ntfs.
The fs_mntops option specifies which parameters should be used for mounting the filesystem. The mount(8) manual page has an extensive description of the available options. These are the most interesting options:
noauto: filesystems that are listed in /etc/fstab are normally mounted automatically. When the "noauto" option is specified, the filesystem will not be mounted during the system boot, but only after issuing a mount command. When mounting such filesystem, only the mount point or device name has to be specified, for example: mount /mnt/cdrom
user: adding the "user" option will allow normal users to mount the filesystem (normally only the superuser is allowed to mount filesystems).
owner: the "owner" option will allow the owner of the specified device to mount the specified device. You can see the owner of a device using ls, e.g. ls -l /dev/cdrom.
noexec: with this option enabled users can not run files from the mounted filesystem. This can be used to provide more security.
nosuid: this option is comparable to the "noexec" option. With "nosuid" enabled SUID bits on files on the filesystem will not be allowed. SUID is used for certain binaries to provide a normal user to do something privileged. This is certainly a security threat, so this option should really be used for removable media, etc. A normal user mount will force the nosuid option, but a mount by the superuser will not!
unhide: this option is only relevant for normal CD-ROMs with the ISO9660 filesystem. If "unhide" is specified hidden files will also be visible.
If the "fs_freq" is set to 1 or higher, it specifies after how many days a filesystem dump (backup) has to be made. This option is only used when dump is installed, and set up correctly to handle this.
This field is used by fsck(8) to determine the order in which filesystems are checked during the system boot.
There are two security mechanisms for securing files: signing files and encrypting files. Signing a file means that a special digital signature is generated for a file. You, or other persons can use the signature to verify the integrity of the file. File encryption encodes a file in a way that only a person for which the file was intended to read can read the file.
This system relies on two keys: the private and the public key. Public keys are used to encrypt files, and files can only be decrypted with the private key. This means that one can sent his public key out to other persons. Others can use this key to send encrypted files, that only the person with the private key can decode. Of course, this means that the security of this system depends on how well the private is kept secret.
Slackware Linux provides an excellent tool for signing and encrypting files, named GnuPG. GnuPG can be installed from the "n" disk set.
Generating public and private keys is a bit complicated, because GnuPG uses DSA keys by default. DSA is an encryption algorithm, the problem is that the maximum key length of DSA is 1024 bits, this is considered too short for the longer term. That is why it is a good idea to use 2048 bit RSA keys. This section describers how this can be done.
1024-bit keys were believed to be secure for a long time. But Bernstein's paper Circuits for Integer Factorization: a Proposal contests this, the bottom line is that it is quite feasible for national security agencies to produce hardware that can break keys in a relatively short amount of time. Besides that it has be shown that 512-bit RSA keys can be broken in a relatively short time using common hardware. More information about these issues can by found in this e-mail to the cypherpunks list: http://lists.saigon.com/vault/security/encryption/rsa1024.html |
We can generate a key by executing:
$ gpg --gen-key
The first question is what kind of key you would like to make. We will choose (4) RSA (sign only):
Please select what kind of key you want: (1) DSA and ElGamal (default) (2) DSA (sign only) (4) RSA (sign only) Your selection? 4
You will then be asked what the size of the key you want to generate has to be. Type in 2048 to generate a 2048 bit key, and press enter to continue.
What keysize do you want? (1024) 2048
The next question is simple to answer, just choose what you like. Generally speaking it is not a bad idea to let the key be valid infinitely. You can always deactivate the key with a special revocation certificate.
Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) 0
GnuPG will then ask for confirmation. After confirming your name and e-mail address will be requested. GnuPG will also ask for a comment, you can leave this blank, or you could fill in something like "Work" or "Private", to indicate what the key is used for. For example:
Real name: John Doe Email address: [email protected] Comment: Work You selected this USER-ID: "John Doe (Work) <[email protected]>"
GnuPG will the ask you to confirm your user ID. After confirming it GnuPG will ask you to enter a password. Be sure to use a good password:
You need a Passphrase to protect your secret key. Enter passphrase:
After entering the password twice GnuPG will generate the keys. But we are not done yet. GnuPG has only generated a key for signing information, not for encryption of information. To continue, have a look at the output, and look for the key ID. In the information about the key you will see pub 2048R/. The key ID is printed after this fragment. In this example:
public and secret key created and signed. key marked as ultimately trusted. pub 2048R/8D080768 2004-07-16 John Doe (Work) <[email protected]> Key fingerprint = 625A 269A 16B9 C652 B953 8B64 389A E0C9 8D08 0768
the key ID is 8D080768. If you lost the output of the key generation you can still find the key ID in the output of the gpg --list-keys command. Use the key ID to tell GnuPG that you want to edit your key:
$ gpg --edit-key <Key ID>
With the example key above the command would be:
$ gpg --edit-key 8D080768
GnuPG will now display a command prompt. Execute the addkey command on this command prompt:
Command> addkey
GnuPG will now ask the password you used for your key:
Key is protected. You need a passphrase to unlock the secret key for user: "John Doe (Work) <[email protected]>" 2048-bit RSA key, ID 8D080768, created 2004-07-16 Enter passphrase:
After entering the password GnuPG will ask you what kind of key you would like to create. Choose RSA (encrypt only), and fill in the information like you did earlier (be sure to use a 2048 bit key). For example:
Please select what kind of key you want: (2) DSA (sign only) (3) ElGamal (encrypt only) (4) RSA (sign only) (5) RSA (encrypt only) Your selection? 5 What keysize do you want? (1024) 2048 Requested keysize is 2048 bits Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) 0
And confirm that the information is correct. After the key is generated you can leave the GnuPG command prompt, and save the new key with the save command:
Command> save
Congratulations! You have now generated the necessary keys to encrypt and decrypt e-mails and files. You can now configure your e-mail client to use GnuPG. It is a good idea to store the contents of the .gnupg directory on some reliable medium, and store that in a safe place! If your private key is lost you can't decrypt files and messages that were encrypted with your public key. If the private key, and your password are stolen, the security of this system is completely compromised.
To make GnuPG useful, you have to give your public key to people who send you files or e-mails. They can use your public key to encrypt files, or use it to verify whether a file has a correct signature or not. The key can be exported using the --export parameter. It is also a good idea to specify the --output parameter, this will save the key in a file. The following command would save the public key of John Doe, used in earlier examples, to the file key.gpg:
$ gpg --output key.gpg --export [email protected]
This saves the key in binary format. Often it is more convenient to use the so-called "ASCII armored output", which fits better for adding the key to e-mails, or websites. You export an ASCII armored version of the key by adding the --armor parameter:
$ gpg --armor --output key.gpg --export [email protected]
If you look at the key.gpg file you will notice that the ASCII armored key is a much more comfortable format.
With GPG you can make a signature for a file. This signature is unique, because your signature can only be made with your private key. This means that other people can check whether the file was really sent by you, and whether it was in any way altered or not. Files can be signed with the --detach-sign parameter. Let us look at an example. This command will make a signature for the memo.txt file. The signature will be stored in memo.txt.sig.
$ gpg --output memo.txt.sig --detach-sign memo.txt You need a passphrase to unlock the secret key for user: "John Doe (Work) <[email protected]>" 2048-bit RSA key, ID 8D080768, created 2004-07-16 Enter passphrase:
As you can see, GnuPG will ask you to enter the password for your private key. After you have entered the right key the signature file (memo.txt.sig) will be created.
You can verify a file with its signature using the --verify parameter. Specify the signature file as a parameter to the --verify parameter. The file that needs to be verified can be specified as the final parameter:
$ gpg --verify memo.txt.sig memo.txt gpg: Signature made Tue Jul 20 23:47:45 2004 CEST using RSA key ID 8D080768 gpg: Good signature from "John Doe (Work) <[email protected]>"
This will confirm that the file was indeed signed by John Doe (Work) <[email protected]>, with the key 8D080768, and that the file is unchanged. Suppose the file was changed, GnuPG would have complained about it loudly:
$ gpg --verify memo.txt.sig memo.txt gpg: Signature made Tue Jul 20 23:47:45 2004 CEST using RSA key ID 8D080768 gpg: BAD signature from "John Doe (Work) <[email protected]>"
One of the main features of GnuPG is encryption. Due to its use of asymmetric cryptography, the person who encrypts a file and the person who decrypts a file do not need to share a key. You can encrypt a file with the private key of another person, and she can decrypt it with her private key. You can encrypt files with the --encrypt. If you do not specify a user ID for which the file should be encrypted, GnuPG will prompt for the user ID. You can specify the user ID with the -r parameter. In the following example, the file secret.txt will be encrypted for another person named John Doe:
$ gpg --encrypt -r "John Doe" secret.txt
The user ID is quoted with double quotes for making sure that the ID is interpreted as a single program argument. After the encryption is completed, the encrypted version of the file will be available as secret.txt.gpg.
The user who receives the file can decrypt it with the --decrypt parameter of the gpg command:
$ gpg --output secret.txt --decrypt secret.txt.gpg You need a passphrase to unlock the secret key for user: "John Doe (Work) <[email protected]>" 2048-bit RSA key, ID 8D080768, created 2004-07-16 (main key ID EC3ED1AB) Enter passphrase: gpg: encrypted with 2048-bit RSA key, ID 8D080768, created 2004-07-16 "John Doe (Work) <[email protected]>"
In this example the --output parameter is used store the decrypted content in secret.txt.