views:

530

answers:

4

I need a way to execute the os.system() module as different UID's. It would need to behave similar to the following BASH code (note these are not the exact commands I am executing):

su user1
ls ~
mv file1
su user2
ls ~
mv file1

The target platform is GNU Linux Generic.

Of course I could just pass these to the os.system module, but how to send the password? Of course I could run the script as root, but that's sloppy and insecure.

Preferably I would like to do with without requiring any passwords to be in plain text.

+3  A: 

I think that's not trivial: you can do that with a shell because each command is launched into its own process, which has its own id. But with python, everything will have the uid of the python interpreted process (of course, assuming you don't launch subprocesses using the subprocess module and co). I don't know a way of changing the user of a process - I don't know if that's even possible - even if it were, you would at least need admin privileges.

What are you trying to do exactly ? This does not sound like the right thing to do for admin purpose, for example. Generally, admin scripts run in a priviledge user - because nobody knows the password of user 2 except user 2 (in theory). Being root means su user always work for a 'normal' user, without requesting password.

David Cournapeau
Your right, it makes more sense to just make a separate privileged user that can execute the script with certain elevated rights. A cleaner solution than running as root.
Caedis
+1  A: 

The function you're looking for is called os.seteuid. I'm afraid you probably won't escape executing the script as root, in any case, but I think you can use the capabilities(7) framework to 'fence in' the execution a little, so that it can change users--but not do any of the other things the superuser can.

Alternatively, you might be able to do this with PAM. But generally speaking, there's no 'neat' way to do this, and David Cournapeau is absolutely right that it's traditional for admin scripts to run with privileges.

Michiel Buddingh'
+2  A: 

maybe sudo can help you here, otherwise you must be root to execute os.setuid

alternatively if you want to have fun you can use pexpect to do things something like this, you can improve over this

p = pexpect.spawn("su guest")
p.logfile = sys.stdout 
p.expect('Password:')
p.sendline("guest")
Anurag Uniyal
+1  A: 

Somewhere along the line, some process or other is going to need an effective UID of 0 (root), because only such a process can set the effective UID to an arbitrary other UID.

At the shell, the su command is a SUID root program; it is appropriately privileged (POSIX jargon) and can set the real and effective UID. Similarly, the sudo command can do the same job. With sudo, you can also configure which commands and UID are allowed. The crucial difference is that su requires the target user's password to let you in; sudo requires the password of the user running it.

There is, of course, the issue of whether a user should know the passwords of other users. In general, no user should know any other user's password.

Scripting UID changes is hard. You can do:

su altuser -c "commands to execute as altuser"
sudo -u altuser commands to execute as altuser

However, su will demand a password from the controlling terminal (and will fail if there is no controlling terminal). If you use sudo, it will cache credentials (or can be configured to do so) so you only get asked once for a password - but it will prompt the first time just like su does.

Working around the prompting is hard. You can use tools parallel to expect which handle pseudo-ttys for you. However, you are then faced with storing passwords in scripts (not a good idea) or somehow stashing them out of sight.


The tool I use for the job is one I wrote, called asroot. It allows me to control precisely the UID and GID attributes that the child process should have. But it is designed to only allow me to use it - that is, at compile time, the authorized username is specified (of course, that can be changed). However, I can do things like:

asroot -u someone -g theirgrp -C -A othergrp -m 022 -- somecmd arg1 ...

This sets the real and effective UID to 'someone', sets the primary group to 'theirgrp', removes all auxilliary groups, and adds 'othergrp' (so the process belongs to just two groups) and sets the umask to 0222; it then executes 'somecmd' with the arguments given.

For a specific user who needs limited (or not so limited) access to other user accounts, this works well. As a general solution, it is not so hot; sudo is better in most respects, but still requires a password (which asroot does not).

Jonathan Leffler