tags:

views:

670

answers:

7

I'm developing an application that manages network interfaces on behalf of the user and it calls out to several external programs (such as ifconfig) that requires root to make changes. (Specifically, changing the IP address of a local interface, etc.) During development, I have been running the IDE as root (ugh) and the debugger as root (double-ugh). Is there a nice way for the end-user to run these under a non-root account? I strongly dislike the size of the attack surface presented by GTK, wxPython, Python, and my application when it runs as root.

I have looked into capabilities, but they look half-baked and I'm not sure if I'd be able to use them in Python, especially if they are on a thread basis. The only option I haven't explored is a daemon that has the setuid bit set and does all the root-type stuff on behalf of the UI. I'm hesitant to introduce that complexity this early in the project, as running as root is not a dealbreaker for the users.

A: 

There's no single user that is halfway between a "normal" user and root. You have root, and then you have users; users can have differing levels of capabilities. If you want something that's more powerful than a "normal" user but not as powerful as root, you just create a new user with the capabilities you want, but don't give it the privileges you don't want it to have.

mipadi
In my example, how do I grant the user the capability to do things like control network interfaces? Or, more generally, what do I look up in order to learn what capabilities to grant to users?
Matt Green
sudo -- use sudoers to grant access to specific programs and run them as root.
tvanfosson
+1  A: 

You could create and distribute a selinux policy for your application. Selinux allows the kind of fine-grained access that you need. If you can't or won't use selinux, then the daemon is the way to go.

florin
+1  A: 

I would not run the application full time as root, but you might want to explore making your application setuid root, or setuid to some id that can become root using something like sudo for particular applications. You might be able to set up an account that cannot login, use setuid to change your program's id (temporarily when needed) and have sudo set up to not prompt for password, but always allow access to that account for specific tasks.

This way your program has no special privileges when running normally, only elevates it's privileges when needed, and is restricted by sudo to only running certain programs.

It's been awhile since I've done much Unix development, so I'm not really sure whether it's possible to set up sudo to not prompt for a password (or even if there is an API for it), but as a fallback you could enable setuid to root only when needed.

[EDIT] Looks like sudo has a NOPASSWD mode so I think it should work since you're running the programs as external commands.

tvanfosson
+6  A: 

Your idea about the daemon has much merit, despite the complexity it introduces. As long as the actions don't require some user interface interaction as root, a daemon allows you to control what operations are allowed and disallowed.

However, you can use SUDO to create a controlled compromise between ROOT and normal users... simply grant SUDO access to the users in question for the specific tools they need. That reduces the attack surface by allowing only "permitted" root launches.

Godeke
+3  A: 

What you want is a "Group"

You create a group, specify that the account wanting to do the action belongs to the group, then you specify that the resource you want access to is a member of that group.

Sometimes group management can be kind of irritating, but it should allow you to do anything you want, and it's the user that is authorized, not your program.

(If you want your program authorized, you can create a specific user to run it as and give that user the proper group membership, then su to that group within your program to execute the operation without giving the running user the ability.)

Bill K
Not really. Some of these programs need actual root level access to run. It's not just the permissions on the file, but the permissions on the actions that need to be performed and the resources they touch. For example, anyone can execute ifconfig (for list), but you need root to do ifconfig up.
tvanfosson
Most resources also have groups. Many only have the "root" group as default. Any that don't have groups, should. I'm certian ifconfig is one of them. In fact, the wheel group may already have access to it.
Bill K
@Bill K: the wheel group has a lot of privileges; it is not one to give to users. A group may be correct still -- the OP could provide a SUID root program that can only be executed by members of a chosen (special) group, and that program runs ifconfig or whatever. Using 'sudo' is probably better.
Jonathan Leffler
Correct, I was just using wheel to indicate that group access to functions like ifconfig is possible. Adding another user to that list shouldn't be difficult. I'm not crazy about the Unix permission system, but it's nothing if not flexible.
Bill K
A: 

I'm not familiar enough with Python to tell you what the necessary commands would be in that language, but you should be able to accomplish this by forking and using a pipe to communicate between the parent and child processes. Something along the lines of:

  • Run the program as root via sudo or suid
  • On startup, the program immediately forks and establishes a pipe for communication between the parent and child processes
  • The child process retains root power, but just sits there waiting for input from the pipe
  • The parent process drops root (changes its uid back to that of the user running it), then displays the GUI, interacts with the user, and handles all operations which are available to a non-privileged user
  • When an operation is to be performed which requires root privileges, the (non-root) parent process sends a command down the pipe to the (root) child process which executes it and optionally reports back to the parent

This is likely to be a bit easier to write than an independent daemon, as well as more convenient to run (since you don't need to worry about whether the daemon is running or not), while also allowing the GUI and other things which don't need root powers to be run as non-root.

Dave Sherohman
+1  A: 

The traditional way would be to create and use a setuid helper to do whatever you need. Note that, however, properly writing a setuid helper is tricky (there are several attack vectors you have to protect against).

The modern way would be to use a daemon (running as root, started on boot) which listens to requests from the rest of the application. This way, your attack surface is mostly limited to whichever IPC you chose (I'd suggest d-bus, which seems to be the modern way).

Finally, if you are managing network interfaces, what you doing is very similar to what network-manager does on a modern distribution. It would be a good idea to either try to somehow integrate what you are doing with network-manager (so it will not conflict with your manipulations), or at least looks at how it works.

CesarB