Created
July 19, 2016 16:14
-
-
Save antevens/744db209b7d79394fb0f98d6c4f2bf6c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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