Most systems have some way of letting ordinary users perform certain tasks as root or some other privileged user. SCO Open Server has "asroot" and can also directly assign "authorizations" such as backup privileges or being able to change other user's passwords. SCO Unixware/Open Unix 8 have a similar facility in "tfadmin".
Many other Unixes, and Linux, use "sudo".
The configuration of sudo is by the /etc/sudoers file. I'm sure that there are more poorly written man pages, but "man sudoers" is among my all time favorites for obfuscation and poor explanation. The creation of the file and the actual use of sudo isn't all that bad though.
First a little background. The sudo program itself is a setuid binary. If you examine its permissions, you will see:
---s--x--x 1 root root 81644 Jan 14 15:36 /usr/bin/sudo
That "s" means that this is a "setuid" program. You and everyone else have execute permission on this, so you can run it. When you do that, because it is setuid and owned by root, your effective user id becomes root- if you could get to a shell from sudo, you effectively WOULD be root- you could remove any file on the system, etc. That's why setuid programs have to be carefully written, and something like sudo (which is going to allow access to other programs) has to be especially careful.
A setuid program doesn't necessarily mean root access. A setuid program owned by a different user would give you that user's effective id. The sudo program can also change your effective id while it is running- I'll be showing an example of that here.
Finally, setuid and sudo are NOT the same thing as the administrative roles of Unixware or the authorizations and privileges of SCO Openserver. Those are entirely different concepts and I won't be talking about those things in this article.
You use "visudo" to edit the sudoers file. There are two reasons for that- it prevents two users from editing the file at the same time, and it also provides limited syntax checking. Even if you are the only root user, you need the syntax checking, so use "visudo".
We're going to start with the simplest setup of all: giving someone full root access. You might think there's no reason to do this- it would make more sense just to give them the root password, wouldn't it? Well, maybe, but then they can login as root also- with sudo they will have to use the sudo command and we can require a password that IS NOT root's password. Sudo commands can be logged, so we can keep track of what the person did. We can turn their sudo capability on or off at will without affecting other sudo users- no need to change the root password back and forth. This is a great way to keep track of consultants and other support people who may need root power, but you want to keep tabs on what they do. Of course there's a strong implication of honesty here- such a user could edit the sudo logs to hide any mischief.
So, here's a simple /etc/sudoers file (remember, edit with "visudo") to give "jim" access to root commands.
# sudoers file. # # This file MUST be edited with the 'visudo' command as root. # # User privilege specification root ALL=(ALL) ALL jim ALL=(ALL) ALL
That's it. With this in place, "jim" can use sudo to run any command with root privileges. Here's "jim" catting /etc/shadow:
[jim@lnxserve jim]$ head -5 /etc/shadow cat: /etc/shadow: Permission denied [jim@lnxserve jim]$ sudo head -5 /etc/shadow Password: root:$1$bukQnNBS$dkGDMUTf1.W5r1VE4OYLy.:11595:0:99999:7::: bin:*:11595:0:99999:7::: daemon:*:11595:0:99999:7::: adm:*:11595:0:99999:7::: lp:*:11595:0:99999:7::: [jim@lnxserve jim]$
Note that "jim" does not get root's PATH; his PATH is used by sudo (with exceptions noted later). If "jim" wanted to run (for example) lpc, he'd have to explicitly do "sudo /usr/sbin/lpc". That's typical, although sudo can be compiled to use its own compiled in PATH instead.
The password requested is NOT root's. In this case, "jim" has to provide his own login password to get sudo to work.
By default, sudo remembers the password for 5 minutes and won't ask again if reinvoked within that time:
[jim@lnxserve jim]$ sudo head -5 /etc/shadow root:$1$bukQnNBS$dkGDMUTf1.W5r1VE4OYLy.:11595:0:99999:7::: bin:*:11595:0:99999:7::: daemon:*:11595:0:99999:7::: adm:*:11595:0:99999:7::: lp:*:11595:0:99999:7::: [jim@lnxserve jim]$
The password behavior is entirely configurable: the password can be set to time out earlier, later, never or to be required always. Additionally, the password requested can be root's instead of their own. Let's change "jim" a bit by adding this line:
# Defaults specification Defaults:jim timestamp_timeout=0, runaspw, passwd_tries=1
This changes three things. First, "jim" needs root's password to run sudo (because of "runaspw"). Second, the password will not be remembered (timestamp_timeout), and he gets only one chance to enter it (the default is three tries).
If we set timestamp_timeout to -1, "jim" will only have to prove that he knows the password once. After that, it will not be forgotten, even if he logs out.
Different users can, of course, have different defaults. Here I've changed "jim", and added a new user "linda"
# sudoers file. # # This file MUST be edited with the 'visudo' command as root. # Defaults:jim timestamp_timeout=0 Defaults:linda timestamp_timeout=-1, runaspw # User privilege specification root ALL=(ALL) ALL jim ALL=(ALL) ALL linda ALL=(ALL) ALL
Jim and Linda have different defaults. A "Default" not followed by a ":" and a user name will apply to everyone (example further on).
Now let's add some logging. Without doing anything special, sudo logs authentication failures to syslog, but by adding another default, we can track every command run:
Notice that this time there is no ":". This default therefore applies to everyone.
With this in place, all sudo commands will be logged:
# /var/log/sudolog Feb 24 06:56:59 : jim : TTY=tty4 ; PWD=/home/jim ; USER=root ; COMMAND=/bin/cat /etc/shadow Feb 24 06:58:49 : jim : TTY=tty4 ; PWD=/var/log ; USER=root ; COMMAND=/bin/cat /etc/shadow
There's a limitation though:
[jim@lnxserve jim]$ sudo cat /etc/shadow > /tmp/shadow Password: [jim@lnxserve jim]$ sudo cat /var/log/sudo* Feb 24 06:56:59 : jim : TTY=tty4 ; PWD=/home/jim ; USER=root ; COMMAND=/bin/cat /etc/shadow Feb 24 06:58:49 : jim : TTY=tty4 ; PWD=/var/log ; USER=root ; COMMAND=/bin/cat /etc/shadow Feb 24 07:02:35 : jim : TTY=pts/0 ; PWD=/home/jim ; USER=root ; COMMAND=/bin/cat /etc/shadow Feb 24 07:02:49 : jim : TTY=pts/0 ; PWD=/home/jim ; USER=root ; COMMAND=/bin/cat /var/log/sudolog [jim@lnxserve jim]$
The redirection to /tmp/shadow does not show up in the log. That makes perfect sense: redirection is done by the shell before the commands are run, so sudo doesn't even see the redirection at all.
You might at this point suddenly think "Oh no- that means a sudo user could overwrite important files". We haven't limited the sudo users command set yet, but even if we do, what stops them from using such commands to pervert system files or other commands?
Well, remember that the shell does the redirection BEFORE sudo runs. If the redirection can't be done because of permissions, the command will fail.
[jim@lnxserve /tmp]$ sudo date > /etc/shadow bash: /etc/shadow: Permission denied [jim@lnxserve /tmp]$
So that's one thing you don't need to worry about. Actually, sudo itself makes reasonable efforts to protect you from malicious michief by a sudo user. Running "sudo -V" as root shows sudo's settings; part of that is environment variables that it will not pass on or that it will check for dangerous content:
Sudo version 1.6.4 ... (stuff deleted) Environment variables to check for sanity: LANGUAGE LANG LC_* Environment variables to remove: BASH_ENV ENV TERMCAP TERMPATH TERMINFO_DIRS TERMINFO _RLD* LD_* PATH_LOCALE NLSPATH HOSTALIASES RES_OPTIONS LOCALDOMAIN IFS
That's the default list; you can add or subtract from it in /etc/sudoers. Note that if you do add or subtract variables, "sudo -V" doesn't reflect those changes.
Let's try that out with our test user. First, we need a simple shell script that will show us the value of environment variables. I'll call it "showme":
We'll have "jim" try it out before making any changes to sudoers:
[jim@lnxserve jim]$ cat showme set | grep $1 [jim@lnxserve jim]$ export ENV [jim@lnxserve jim]$ ./showme ENV BASH_ENV=/home/jim/.bashrc [jim@lnxserve jim]$ sudo ./showme ENV SUDO_COMMAND='./showme ENV'
The ENV variable is not picked up by sudo even though it was marked for export. Ordinarily, environment variables would be passed:
[jim@lnxserve jim]$ export BOOP=betty [jim@lnxserve jim]$ ./showme BOOP BOOP=betty [jim@lnxserve jim]$ sudo ./showme BOOP BOOP=betty SUDO_COMMAND='./showme BOOP' [jim@lnxserve jim]$
But we can add to the list of variables to discard:
# sudoers file. # # This file MUST be edited with the 'visudo' command as root. # Defaults:jim timestamp_timeout=-1, env_delete+="BOOP"
Note the "+=" to ADD to the environment list. If we had just used "=", that would have replaced all of sudo's defaults. You can also use "-=" to subtract a default variable and allow it to be passwd.
Now "jim" won't get BOOP in his sudo environment.
[jim@lnxserve jim]$ sudo ./showme BOOP SUDO_COMMAND='./showme BOOP'
Sudo also rearranges your PATH internally. That can be a little confusing:
[jim@lnxserve jim]$ cat ./showme echo "I'm in /home/jim" set | grep $1 [jim@lnxserve jim]$ cat ./bin/showme echo "I'm in /home/jim/bin" set | grep $1 [jim@lnxserve jim]$ export PATH=".:$PATH" [jim@lnxserve jim]$ showme PATH I'm in /home/jim PATH=.:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/jim/bin [jim@lnxserve jim]$ sudo showme PATH I'm in /home/jim/bin PATH=.:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/jim/bin SUDO_COMMAND='/home/jim/bin/showme PATH' [jim@lnxserve jim]$
Although PATH still shows "." at the beginning, the showme in /bin is what is run by sudo. Internally sudo has ignored the leading "." and moved on to find "showme" in /home/jim/bin. Now let's remove the /home/jim/bin/showme:
[jim@lnxserve jim]$ rm bin/showme [jim@lnxserve jim]$ sudo showme PATH sudo: ignoring `showme' found in '.' Use `sudo ./showme' if this is the `showme' you wish to run. [jim@lnxserve jim]$ sudo ./showme PATH I'm in /home/jim PATH=.:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/jim/bin SUDO_COMMAND='./showme PATH' [jim@lnxserve jim]$
There's more that sudo does to protect tyou from malicious mischief. The :man sudo" pages cover that completely. Let's continue with our examples; it's time to limit "jim" to specific commands. There are two ways to do that. We can specifically list commands, or we can say that jim can only run commands in a certain directory. A combination of those methods is useful:
jim ALL= /bin/kill,/sbin/linuxconf, /usr/sbin/jim/
The careful reader will note that there was a bit of a change here. The line used to read "jim ALL=(ALL) ALL", but now there's only one "ALL" left. Reading the man page can easily leave you quite confused as to what those three "ALL"'s meant. In the example above, ALL refers to machines- the assumption is that this is a network wide sudoers file. In the case of this machine (lnxserve) we could do this:
jim lnxserve= /bin/kill, /usr/sbin/jim/
So what was the "(ALL)" for? Well, here;s a clue:
jim lnxserve=(paul,linda) /bin/kill, /usr/sbin/jim/
That says that jim can (using "sudo -u ") run commands as paul or linda.
This is perfect for giving jim the power to kill paul or linda's processes without giving him anything else. There is one thing we need to add though: if we just left it like this, jim is forced to use "sudo -u paul" or "sudo -u linda" every time. We can add a default "runas_default":
Defaults:jim timestamp_timeout=-1, env_delete+="BOOP", runas_default=linda
I hope that this introduction will get you started. Now that you have the basics, the man pages for sudo and sudoers should make more sense.
(OLDER) <- More Stuff -> (NEWER) (NEWEST)
Printer Friendly Version
Inexpensive and informative Apple related e-books:
Take Control of Apple Mail, Second Edition
Digital Sharing Crash Course
Take Control of Your Online Privacy
Take Control of Pages
Take Control of Podcasting on the Mac, Third Edition