17

Here's my source:

#!/bin/bash

echo "Running script to free general cached memory!"
echo "";
echo "Script must be run as root!";
echo "";
echo "Clearing swap!";
swapoff -a && swapon -a;
echo "";
echo "Clear inodes and page file!";
echo 1 > /proc/sys/vm/drop_caches;
echo "";

It clears caches and stuff, and it echoes that it needs to be run as root in the terminal. I basically just want the script to cease running if it detects it's not being executed as root.

Example:

"Running script to free general cached memory!"
"Warning: script must be run as root or with elevated privileges!"
"Error: script not running as root or with sudo! Exiting..."

If run with elevated privileges, it just runs as normal. Any ideas? Thanks!

  • Possible duplicate of How to hinder root from running a script – muru Aug 31 '17 at 6:44
  • 2
    @muru, except that other question is for the opposite: fail the script if running as root. – Stéphane Chazelas Aug 31 '17 at 6:48
  • 3
    @StéphaneChazelas ah, my bad. Retracted – muru Aug 31 '17 at 6:48
  • An alternative is to limit the amount of work performed as root by prefixing prefix all commands that must run as root with sudo. – reinierpost Sep 1 '17 at 9:50
46
#!/bin/sh

if [ "$(id -u)" -ne 0 ]; then
        echo 'This script must be run by root' >&2
        exit 1
fi

cat <<HEADER
Host:          $(hostname)
Time at start: $(date)

Running cache maintenance...
HEADER

swapoff -a && swapon -a
echo 1 >/proc/sys/vm/drop_caches

cat <<FOOTER
Cache maintenance done.
Time at end:   $(date)
FOOTER

The root user has UID 0 (regardless of the name of the "root" account). If the effective UID returned by id -u is not zero, the user is not executing the script with root privileges. Use id -ru to test against the real ID (the UID of the user invoking the script).

Don't use $EUID in the script as this may be modified by an unprivileged user:

$ bash -c 'echo $EUID'
1000

$ EUID=0 bash -c 'echo $EUID'
0

If a user did this, it would obviously not lead to privilegie escalation, but may lead to commands in the script not being able to do what they are supposed to do and files being created with the wrong owner etc.

  • 1
    Note: on Solaris 5.10, /bin/id -u gives /bin/id: illegal option -- u Usage: id [-ap] [user] – jrw32982 Sep 6 '17 at 17:44
  • 1
    @jrw32982 You should have /usr/xpg4/bin early in your $PATH to get access to POSIX utilities on Solaris. – Kusalananda Sep 6 '17 at 17:47
  • 1
    The point is that the -u option of id is not universal and therefore this solution is universal only with the caveat that a POSIX version of id must occur first in your PATH. – jrw32982 Sep 6 '17 at 21:25
  • 1
    @jrw32982 For your script to pick up the correct POSIX utilities on Solaris, modify $PATH at the top of the script so that /usr/xpg4/bin is before /bin. If you insist on using non-POSIX id, then obviously you will have to come up with a more portable solution. – Kusalananda Sep 6 '17 at 21:57
  • 1
    @Harry Yes, so the script could use PATH=$( getconf PATH ) or set some other explicit default path, or use an explicit path for calling id. – Kusalananda Jul 13 '18 at 9:25
19

I think what you want is rather to check that you have super-user privileges, that is, that your effective user id is 0.

zsh and bash make that available in the $EUID variable, so you can do:

if ((EUID != 0)); then
  echo >&2 "Error: script not running as root or with sudo! Exiting..."
  exit 1
fi

With any POSIX-like shells, you can use the id standard command:

if [ "$(id -u)" -ne 0 ]; then
  echo >&2 "Error: script not running as root or with sudo! Exiting..."
  exit 1
fi

Note that all of id -un or whoami or the $USERNAME variable in zsh will get you the first username for the uid. On systems that have other users with id 0, that may not be root even if the process is a descendant of one that has been authenticated as root.

$USER would usually give you the user that authenticated, but relying on it is quite brittle. It's not set by the shell, but is usually set by the authenticating command (like login, su (on GNU/Linux systems, not necessarily others), sudo, sshd (the one from openssh at least)...). It's not always though (changing the uid does not automagically set that variable, it has to be done explicitly by the application changing the uid) and it could also have been modified by some other process in the shell's ancestry. $LOGNAME, with the same caveat is more reliable as it's specified by POSIX (originally from FIPS 151-2)

12

You can use $USER or whoami to check the current user.

if [[ "$USER" != "root" ]]; then
    echo "Error: script not running as root or with sudo! Exiting..."
    exit 1
fi

if [[ $(whoami) != "root" ]]; then
    echo "Warning: script must be run as root or with elevated privileges!"
    exit 1
fi

if [[ $(id -u) != "0" ]]; then
    echo "Error: script not running as root or with sudo! Exiting..."
    exit 1
fi
  • 1
    NP. I suggest literally just reading straight through the bash manual [gnu.org/software/bash/manual/bashref.html]. It's actually a surprisingly easy ready. For this answer in particular I suggest referencing: 3.2.4.2 Conditional Constructs 3.5.4 Command Substitution – Jesse_b Aug 31 '17 at 2:01
  • 9
    The command id -u with or without a -n option is an alternative to using whoami. Without a -n and comparing to zero is a better match to the test the kernel is actually doing. All the kernel cares about is the id, not the name from the password file. – icarus Aug 31 '17 at 2:28
  • 6
    I believe that using $(id -u) is better. In some (malicious) cases, $USER could be wrong. – Basile Starynkevitch Aug 31 '17 at 8:15
  • 1
    For those who are interested in the link provided by @Jesse_b: there's a typo. It should be gnu.org/software/bash/manual/bashref.html – Kryten Sep 1 '17 at 14:17
  • 1
    Some systems do not use "root" as the name of the privileged account having uid 0. QNAP springs to mind as one. So you should only check uid 0, and not the root account name. – roaima Sep 9 '17 at 9:20
10

What you actually want is to determine is whether you have access to do these operations. It's considered bad practice to check whether or not you're root in lieu of that.

If the system has been configured to allow a non-root user to modify swap and drop page cache, why shouldn't that user get to run your script?

Instead, you can simply try the operation and exit with a helpful message if it fails:

if ! ( swapoff -a && swapon -a )
then
  echo "Failed to clear swap (rerun as root?)" >&2
  exit 1
fi

if ! echo 1 > /proc/sys/vm/drop_caches
then 
  echo "Failed to free page cache (rerun as root?)" >&2
  exit 1
fi
  • A non-root user turning off swap? – Kusalananda Aug 31 '17 at 20:18
  • 2
    Yes. You can set this up with SELinux. Likewise, you can disable a root process from doing it. – that other guy Aug 31 '17 at 20:32
  • 1
    You might not want to exit after something fails, in case the user wants to do as much as they can with their current privileges. (But for a typical system where all of this requires root, exiting would be more useful / less noisy.) – Peter Cordes Sep 1 '17 at 1:31
  • 2
    I wouldn't go so far as to say it's "bad practice" to check whether or not you're root. Particularly if that's exactly what you want to know. I do take your point that it's best to check if you have sufficient permissions to do what you want. – Erik Bennett Sep 9 '17 at 14:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.