Dropping Root Permissions In Python

前端 未结 6 2009
南旧
南旧 2020-12-02 15:36

I\'d like to have a Python program start listening on port 80, but after that execute without root permissions. Is there a way to drop root or to get port 80 without it?

6条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-02 16:16

    The following is a further adaptation of Tamás's answer, with the following changes:

    • Use the python-prctl module to drop Linux capabilities to a specified list of capabilities to preserve.
    • The user can optionally be passed as a parameter (it defaults to looking up the user who ran sudo).
    • It sets all the user's groups and HOME.
    • It optionally changes directory.

    (I'm relatively new to using this functionality, however, so I may have missed something. It might not work on older kernels (<3.8) or kernels with filesystem capabilities disabled.)

    def drop_privileges(user=None, rundir=None, caps=None):
        import os
        import pwd
    
        if caps:
            import prctl
    
        if os.getuid() != 0:
            # We're not root
            raise PermissionError('Run with sudo or as root user')
    
        if user is None:
            user = os.getenv('SUDO_USER')
            if user is None:
                raise ValueError('Username not specified')
        if rundir is None:
            rundir = os.getcwd()
    
        # Get the uid/gid from the name
        pwnam = pwd.getpwnam(user)
    
        if caps:
            prctl.securebits.keep_caps=True
            prctl.securebits.no_setuid_fixup=True
    
        # Set user's group privileges
        os.setgroups(os.getgrouplist(pwnam.pw_name, pwnam.pw_gid))
    
        # Try setting the new uid/gid
        os.setgid(pwnam.pw_gid)
        os.setuid(pwnam.pw_uid)
    
        os.environ['HOME'] = pwnam.pw_dir
    
        os.chdir(os.path.expanduser(rundir))
    
        if caps:
            prctl.capbset.limit(*caps)
            try:
                prctl.cap_permitted.limit(*caps)
            except PermissionError:
                pass
            prctl.cap_effective.limit(*caps)
    
        #Ensure a reasonable umask
        old_umask = os.umask(0o22)
    

    It can be used as follows:

    drop_privileges(user='www', rundir='~', caps=[prctl.CAP_NET_BIND_SERVICE])
    

提交回复
热议问题