Recently, I had a simple python program that created a listening socket, and was uncomfortable running it as root (required to access a port below 1000). I had a quick look around, and found a good blog entry on doing exactly this. However, when running this on OSX, which uses negative UID and GID, I ran into a problem. It turns out that the negative ID is an offset from UINT32_MAX, i.e. 2^32+(-ve UID). The problem is, Python 2.7.1 (Lion's default) os.setgid() was returning an OverFlowError (but not in 2.7.2). I made a mod to the code to handle that case, and figured this pattern may be useful to others wanting to drop privs in a python app.
import os, pwd, grpdef safe_setgid(running_gid):try:os.setgid(running_gid)except OSError, e:print('Could not set effective group id: %s' % e)def safe_setuid(running_uid):try:os.setuid(running_uid)except OSError, e:print('Could not set effective group id: %s' % e)# Taken from http://antonym.org/2005/12/dropping-privileges-in-python.htmldef drop_privileges(uid_name='nobody', gid_name='nogroup'):starting_uid = os.getuid()starting_gid = os.getgid()starting_uid_name = pwd.getpwuid(starting_uid)if os.getuid() != 0:# We're not root so don't drop, you may want to change thisprint("drop_privileges: already running as '%s'"%starting_uid_name)return# If we started as root, drop privs and become the specified user/groupif starting_uid == 0:# Get the uid/gid from the namerunning_uid = pwd.getpwnam(uid_name)running_gid = grp.getgrnam(gid_name)# Try setting the new uid/gidtry:safe_setgid(running_gid)except OverflowError, e:if (running_gid > 4294967290):running_gid = -4294967296 + running_gidsafe_setgid(running_gid)try:safe_setuid(running_uid)except OverflowError, e:if (running_uid > 4294967290):running_uid = -4294967296 + running_uidsafe_setuid(running_uid)# Ensure a very conservative umasknew_umask = 077old_umask = os.umask(new_umask)print('drop_privileges: Old umask: %s, new umask: %s' % (oct(old_umask), oct(new_umask)))final_uid = os.getuid()final_gid = os.getgid()print('drop_privileges: running as %s/%s' % (pwd.getpwuid(final_uid),grp.getgrgid(final_gid)))
Display comments as (Linear | Threaded)