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, grp
def 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)[0]
if os.getuid() != 0: # We're not root so don't drop, you may want to change this print("drop_privileges: already running as '%s'"%starting_uid_name) return
# If we started as root, drop privs and become the specified user/group if starting_uid == 0: # Get the uid/gid from the name running_uid = pwd.getpwnam(uid_name)[2] running_gid = grp.getgrnam(gid_name)[2]
# Try setting the new uid/gid try: safe_setgid(running_gid) except OverflowError, e: if (running_gid > 4294967290): running_gid = -4294967296 + running_gid safe_setgid(running_gid)
try: safe_setuid(running_uid) except OverflowError, e: if (running_uid > 4294967290): running_uid = -4294967296 + running_uid safe_setuid(running_uid)
# Ensure a very conservative umask new_umask = 077 old_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)[0],grp.getgrgid(final_gid)[0]))