op vs. sudo

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.

  1. Write a small script that does what is needed, and give the user permission to run that script using sudo.
  2. Hope that the user can remember the full command, no matter how long and convoluted it is.
  3. Force the user(s) to maintain their own command alias(es) rather than typing in the full command.

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.

Using “mnemonics”

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.

Customizing mnemonics

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.

Regular-Expressions.info

A Tao of Regular Expressions

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.

Using macros

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)

Magic shells

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

Environment inheritance

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.

Inheritance isn’t always what you want

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.

Forced inheritance

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.

Not all privileges are escalated

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.

Password laziness

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:

  1. Use a password protected screensaver
  2. Delete your ticket (sudo -k)
  3. Nobody will come by my keyboard in the next five minutes

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?

Embedded scripting

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

Setting defaults

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).

Summary

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.

Tags:

Comments are closed.