Skip to content

Instantly share code, notes, and snippets.

@antevens
Created July 19, 2016 16:14
Show Gist options
  • Save antevens/744db209b7d79394fb0f98d6c4f2bf6c to your computer and use it in GitHub Desktop.
Save antevens/744db209b7d79394fb0f98d6c4f2bf6c to your computer and use it in GitHub Desktop.
def set_uid_gid(set_rguid_to_eguid=False, set_eguid_to_rguid=False, restore_ids=True):
"""
A decorator to set/swap real/effective UID/GID for the duration of an operation
EUID: Effective user ID, this is what is used to check permissions
RUID: Real user ID, this is used to determine who the original user is
when escalating priv. to determine the original user
SUID: Saved user ID, this is used to store original user ID when a process
needs to temporarily deescalate it's priv but is used to re-escalate.
"""
def set_uid_gid_decorator(func):
def inner(*args, **kwargs):
current_proc = multiprocessing.current_process()
logger.debug("Changing permissions for process: {0} with PID: {1}".format(current_proc.name, str(current_proc.pid)))
if sys.version > "2.7":
ruid, euid, suid = os.getresuid()
rgid, egid, sgid = os.getresgid()
logger.debug("UIDs before are: (ruid) {0}, (euid) {1}, (suid) {2}".format(ruid, euid, suid))
logger.debug("GIDs before are: (rgid) {0}, (egid) {1}, (sgid) {2}".format(rgid, egid, sgid))
# Store superuser if available
if 0 in (ruid, euid, suid):
tmp_stored_uid = 0
else:
tmp_stored_uid = suid
if 0 in (rgid, egid, rgid):
tmp_stored_gid = 0
else:
tmp_stored_gid = sgid
# Swap UID/GID's around as needed
if set_eguid_to_rguid is True:
neuid = ruid
negid = rgid
else:
neuid = euid
negid = egid
if set_rguid_to_eguid is True:
nruid = euid
nrgid = egid
else:
nruid = ruid
nrgid = rgid
# Make the actual permisson changes
logger.debug("Setting UIDs to: (ruid) {0}, (euid) {1}, (suid) {2}".format(nruid, neuid, tmp_stored_uid))
logger.debug("Setting GIDs to: (rgid) {0}, (egid) {1}, (sgid) {2}".format(nrgid, negid, tmp_stored_gid))
os.setresuid(nruid, neuid, tmp_stored_uid)
os.setresgid(nrgid, negid, tmp_stored_gid)
try:
# Run the code
retval = func(*args, **kwargs)
finally:
if restore_ids is True:
# Restore original permissions
logger.debug("Restoring UIDs to: (ruid) {0}, (euid) {1}, (suid) {2}".format(ruid, euid, suid))
logger.debug("Restoring GIDs to: (rgid) {0}, (egid) {1}, (sgid) {2}".format(rgid, egid, sgid))
os.setresgid(rgid, egid, sgid)
os.setresuid(ruid, euid, suid)
else:
# We can't check stored user ID, so we hope and try our best
ruid = os.getuid()
euid = os.geteuid()
rgid = os.getgid()
egid = os.getegid()
logger.debug("UIDs before are: (ruid) {0}, (euid) {1}".format(ruid, euid))
logger.debug("GIDs before are: (rgid) {0}, (egid) {1}".format(rgid, egid))
# Store superuser if available
if 0 in (ruid, euid):
# Set all UIDs to 0 (call twice for ruid -> euid -> suid)
os.setuid(0)
os.setuid(0)
elif 0 in (rgid, egid):
# Set all GIDs to 0 (call twice for rgid -> egid -> sgid)
os.setgid(0)
os.setgid(0)
# Swap UID/GID's around as needed
if set_eguid_to_rguid is True:
neuid = ruid
negid = rgid
else:
neuid = euid
negid = egid
if set_rguid_to_eguid is True:
nruid = euid
nrgid = egid
else:
nruid = ruid
nrgid = rgid
# Make the actual permisson changes
if nruid != 0 and neuid != 0:
logger.warning("Setting both Real and Effective UIDs to non-zero")
logger.debug("Setting UIDs to: (ruid) {0}, (euid) {1}".format(nruid, neuid))
logger.debug("Setting GIDs to: (rgid) {0}, (egid) {1}".format(nrgid, negid))
os.setreuid(nruid, neuid)
os.setregid(nrgid, negid)
try:
# Run the code
retval = func(*args, **kwargs)
finally:
if restore_ids is True:
# Restore original permissions
logger.debug("Restoring UIDs to: (ruid) {0}, (euid) {1}".format(ruid, euid))
logger.debug("Restoring GIDs to: (rgid) {0}, (egid) {1}".format(rgid, egid))
os.setregid(rgid, egid)
os.setreuid(ruid, euid)
return retval
if set_rguid_to_eguid is True or set_eguid_to_rguid is True:
return inner
else:
return func
return set_uid_gid_decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment