Drop Privilege

When writing a small Python web application using the lightweight Pyramid framework, I needed the server to run on port 80. Of course running a server as root is enough to scare even the hardest sysadmin, so I obviously wanted it to drop privs immediately upon startup, once it had opened the default http port. I wrote the function below to drop privs and switch to a new user and group (usually nobody/nogroup). It is self-contained, should work with anything - there is nothing specific to any system. If you find it useful of have any suggestions to improve it, please leave a comment.

To use this within Pyramid, set the port to 80 in the cherrypy config file, then add the following before your server start:

cpg.server.onStartServerList = [drop_privileges]## drop_privileges.pyimport logginglog = logging.getLogger('server')logging.basicConfig()logging.root.setLevel(level=logging.INFO)# ...def drop_privileges(uid_name='nobody', gid_name='nogroup'): import os, pwd, grp starting_uid = os.getuid() starting_gid = os.getgid() starting_uid_name = pwd.getpwuid(starting_uid)[0] log.info('drop_privileges: started as %s/%s' % \ (pwd.getpwuid(starting_uid)[0], grp.getgrgid(starting_gid)[0])) if os.getuid() != 0: # We're not root so, like, whatever dude log.info("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: os.setgid(running_gid) except OSError, e: log.error('Could not set effective group id: %s' % e) try: os.setuid(running_uid) except OSError, e: log.error('Could not set effective user id: %s' % e) # Ensure a very convervative umask new_umask = 077 old_umask = os.umask(new_umask) log.info('drop_privileges: Old umask: %s, new umask: %s' % \ (oct(old_umask), oct(new_umask))) final_uid = os.getuid() final_gid = os.getgid() log.info('drop_privileges: running as %s/%s' % \ (pwd.getpwuid(final_uid)[0], grp.getgrgid(final_gid)[0]))# Test itif __name__ == '__main__': drop_privileges()

References:

Drop Privilege in Python