
The day I took this photo, it was extraordinarily hot for Cleveland (high 90s). This poor polar bear just looked… well… blue. Dreaming of an ice floe, perhaps.

You know at least one person who makes you wish you had a remote control like this one. Admit it!
Submitted for Illustration Friday topic “Remote.”
Anyone in the system administration field today is probably familiar with sudo, a tool which allows an administrator to selectively dole out elevated privileges to users. Since sudo is fairly popular and has been written about extensively elsewhere, I’m not going to go into it in detail. Instead, I’d like to talk about a similar utility called op.
My main complaint about sudo is simple. Say you have a user who needs to run a command like this:
% kill -HUP `cat /var/run/mysql.pid | head -1`
In a situation like this there are generally three options, if you’re using sudo.
Having been a system administrator for some ten years now, I know that I can easily figure out or remember arcane commands like this one. If I can’t, I don’t mind resorting to a private script or a shell alias. But this is not generally something I can expect my users to have to deal with.
op makes this situation much more bearable by using what it calls “mnemonics.” A mnemonic is just a command boiled down to a short keyword. Let’s look at how this rule might look in an op.conf file.
restartdb kill -HUP `cat /var/run/mysql.pid | head -1`;
users=dan,joe
uid=root
gid=root
password
This will allow the defined users (dan or joe) to run the command as root, simply by typing this line, followed by their account password.
op restartdb
The primary advantage for the user is memorability, and a lack of fear when running a command. They don’t have to worry that they typed something incorrectly and completely botched the command. If they did enter a typo, the worst they’ll probably get back is an error saying that the command doesn’t exist.
The primary advantage for the system admin is not having to manage a ton of little shell scripts, while still making it easy for users to get work done. Everything can just live in one config file, and it’s directly tied to the permission configuration for the command.
Here’s a slightly different take on the previous mnemonic; this one will let the user specify a pattern to search for in the process table.
restart-process kill -HUP `cat $1 | head -1`;
users=dan,joe
uid=root
gid=root
$1=.*
password
In this example, we’ve introduced an argument ($1). The argument is defined using a regular expression pattern (.*), which in this case matches any string. The user would run this command to send SIGHUP to the process whose PID is recorded in /var/run/slapd.pid.
op restart-process /var/run/slapd.pid
To restrict things a bit, you could refine the regular expression to match only files which are in a certain path.
$1=/var/run/[a-zA-Z0-9_.-]*\.pid
You can also just limit the rule to certain specific files.
$1=/var/run/(mysql|slapd|postmaster)\.pid
If you aren’t familiar with regular expressions, don’t despair! They aren’t as hard to learn as you might think.
Jeffrey Friedl’s Mastering Regular Expressions is widely considered to be the seminal work on the subject. I recommend it for anyone’s bookshelf.
And of course, Google.
Like sudo, op allows you to define macros for commonly used values, to save on repeated text in the config file. For example, if you have a group of users that all need to access the same set of commands, you can define a macro for those users rather than putting them in all of the mnemonics explicity. This makes administration easier as well — you only have one place to update the list of users if it changes.
Here, we have two mnemonics that are accessible by the same three users.
ADMINS=(dan|joe|fred)
restart-process kill -HUP `cat $1 | head -1`;
users=ADMINS
uid=root
gid=root
$1=.*
password
reboot /usr/sbin/shutdown -r now;
users=ADMINS
uid=root
gid=root
password
Macros are also nestable.
ADM1=(dan|joe|fred)
ADM2=(jack|jill|dhill)
ADM3=(twisp|catsby)
ADMINS=(ADM1|ADM2|ADM3)
op has a feature called the magic shell. I suppose the name could have been meant to appeal to fans of hard shell ice cream toppings, but I would tend to doubt it.
Magic shell simply launches the user’s shell environment, but as a different user. This is handy if you want to offer the ability for a user to become root, but retain the value built up in their shell startup files.
shell MAGIC_SHELL;
users=dan,joe
uid=root
gid=root
password
As most readers will be aware, a subshell will normally inherit its initial environment from the process which called it. When you start a shell with op, this is no different. But if you wish to restrict what is passed, you can do so easily. Here’s an example; a modified version of the previous rule.
shell MAGIC_SHELL;
users=dan,joe
uid=root
gid=root
$HOME $EDITOR $DISPLAY $TERM $PATH
password
Now, only the five variables mentioned are going to be passed to the root shell environment.
What if you want to simulate (as much as possible) the user actually logging in a target user, but without sharing the target user’s password, and retaining the ability to know which users are logging in as the target user?
httpd /bin/su - httpd;
users=dan,joe
uid=root
gid=root
password
What we have here is a mnemonic used to simulate logging in as the httpd user (by using the bare “-” argument to the su command). The mnemonic runs as root, simply so that the su command is run as root. The end result is a shell as the user httpd, with the httpd user’s environment.
There are times you want the environment to have a certain value but don’t want to trust that value to the randomness of shell default files. You can force the value right in the rule definition. Here is an example rule I wrote which lets people update a web site from a CVS repository; the repository in this case can only be accessed via SSH.
siteupdate /usr/local/bin/cvs update $*;
users=SITEADMINS
uid=sitecvs
gid=cvs
dir=/web/main
$CVS_RSH=/usr/local/bin/ssh
password
As you can see, we’ve put the variable in just like we wanted to inherit it from the parent environment, except we tacked on a value. Note that if the target user’s environment explicitly sets a new value, that value will ultimately be the value that the shell uses. This is probably not something you want to use to enforce a security policy. It should be viewed as a convenience only.
You can also see here the use of the dir parameter. This tells op to change to a certain directory before running the command.
So far, most of the examples have shown how to become root. That’s not always what you need. Simply change the uid and gid values to become another user with another group.
oracle MAGIC_SHELL;
users=dan,joe
uid=oracle
gid=dba
$HOME $EDITOR $DISPLAY $TERM $PATH
$ORACLE_HOME $ORACLE_SID
password
And now dan and joe can put themselves into the oracle user’s shoes very easily. Note that I’ve added a couple of Oracle-related variables here.
sudo has a feature that lets the user get away with entering repeated commands, but only typing their password one time. It uses something it calls a ticket to do this. If you run a sudo command and successfully authenticate, you are given a ticket. If you run successive sudo commands, from the same terminal, within a given period of time, you don’t need to type your password in again and your ticket is renewed. By default, tickets are given a five minute lifetime, but that is configurable.
I tend to view this as a security flaw. It means you can’t just walk away from your keyboard, confident nobody can get to your escalated privileges. I know all the usual arguments:
My belief is that someone might come by your keyboard, and it’s putting the onus on the user to enforce security by protecting the terminal or by deleting their ticket. Much simpler to just make the software enforce the security barrier properly, than to assume the user is going to enforce the security policy for it.
For your home office users, how will they explain to the boss that the system was trashed because their three-year old hit the up arrow a couple of times and got into their command history, then mashed the enter key? You think it can’t happen?
You can embed a script in an op rule. Here is an example, based on one I found on the op home page.
mount /bin/sh -c '
case $1 in
cdrom) mount /mnt/cdrom ;;
dvd) mount -o ro /dev/dvd /mnt/dvd ;;
burner) mount -o ro /dev/burner /mnt/burner ;;
*) echo "no permission to mount \'$1\'" 1>2 ;;
esac
';
users=dan,joe
password
You can simply run this mnemonic with the appropriate argument to run the appropriate command, e.g.:
op mount dvd
If the first non-comment line in the op.conf begins with the word “DEFAULT,” then that line is the default settings line. You might have something like this on your default settings line (which can span multiple lines, like mnemonics themselves):
DEFAULT $USER $TERM
$PATH=/bin:/usr/sbin:/usr/local/bin:/usr/ucb
This tells op that by default, the $USER and $TERM variables should be inherited, and that the $PATH should be set to the value provided. If one were so inclined one could add other items to this line (such as password to force a password on every command).
sudo certainly isn’t a bad utility, and I wouldn’t presume to tell anybody that they should not use it. I happen to prefer op for my use for certain reasons, and I encourage others to at least give it a chance. The most popular is not always the best, after all.