Classic Shell Scripting - Arnold Robbins [150]
* * *
Tip
Here is why we recommend a dozen or more X characters. The easily guessable process ID might account for as many as six or seven of them, so the number of random letters might be as small as five: there are then 525 (about 380 million) random strings of letters. However, with just 10 X's (mktemp's default, and illustrated in its manual pages) and a seven-digit PID, only about 140,000 guesses are needed. We tested such an attack on our fastest machines with a 40-line C program, and found that a million guesses can be checked in less than three seconds!
* * *
Here is an example of the use of mktemp:
$ TMPFILE=`mktemp /tmp/myprog.XXXXXXXXXXXX` || exit 1
Make unique temporary file
$ ls -l $TMPFILE
List the temporary file
-rw------- 1 jones devel 0 Mar 17 07:30 /tmp/myprog.hJmNZbq25727
The process ID, 25727, is visible at the end of the filename, but the rest of the suffix is unpredictable. The conditional exit command ensures that we terminate immediately with an error if the temporary file cannot be created, or if mktemp is not available.
The newest version of mktemp allows the template to be omitted; it then uses a default of /tmp/tmp.XXXXXXXXXX. However, older versions require the template, so avoid that shortcut in your shell scripts.
* * *
Warning
HP-UX has a weak version of mktemp: it ignores any user-provided template, and constructs an easily guessable temporary filename from the username and the process ID. On HP-UX, we strongly recommend that you install the OpenBSD version mentioned earlier in this section.
* * *
To eliminate the need to hardcode a directory name, use the -t option: mktemp then uses whatever directory the environment variable TMPDIR specifies, or else /tmp.
The -d option requests the creation of a temporary directory:
$ SCRATCHDIR=`mktemp -d -t myprog.XXXXXXXXXXXX` || exit 1
Create temporary directory
$ ls -lFd $SCRATCHDIR
List the directory itself
drwx------ 2 jones devel 512 Mar 17 07:38 /tmp/myprog.HStsWoEi6373/
Since that directory has no access for group and other, an attacker cannot even find out the names of files that you subsequently put there, but still might be able to guess them if your script is publicly readable. However, because the directory is not listable, an unprivileged attacker cannot confirm the guesses.
The /dev/random and /dev/urandom Special Files
Some systems provide two random pseudodevices: /dev/random and /dev/urandom. These are currently available only on BSD systems, GNU/Linux, IBM AIX 5.2, Mac OS X, and Sun Solaris 9, with two third-party implementations and retrofits available for earlier Solaris versions.[3] These devices serve as never-empty streams of random bytes: such a data source is needed in many cryptographic and security applications. While there are plenty of simple algorithms for generating streams of pseudorandom numbers, generation of truly random data is a difficult problem: see the book Cryptographic Security Architecture: Design and Verification.[4]
The distinction between the two devices is that /dev/random may block until sufficient randomness has been gathered from the system so that it can guarantee high-quality random data. By contrast, /dev/urandom never blocks, but then its data may be somewhat less random (but still good enough to pass many statistical tests of randomness).
Because these devices are shared resources, it is easy to mount a denial-of-service attack against the blocking /dev/random pseudodevice simply by reading it and discarding the data. Compare these experiments on the two devices, and notice the difference in the count arguments:
$ time dd count=1 ibs=1024 if=/dev/random > /dev/null
Read 1KB of random bytes
0+1 records in
0+1 records out
0.000u 0.020s 0:04.62 0.4% 0+0k 0+0io 86pf+0w
$ time dd count=1024 ibs=1024 if=/dev/urandom > /dev/null
Read 1MB of random