From 74804944323ff2d6fe09ed354058f87855a15c01 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 6 Feb 2020 10:05:57 -0500 Subject: [PATCH] Tighten up new PAM check For one, remove the password cache cleaning, as it no longer is run. For another, skip the fork if uid is already 0. Finally, wrap the check in a try/finally to keep the privileged process more certain in exiting. --- confluent_server/confluent/auth.py | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/confluent_server/confluent/auth.py b/confluent_server/confluent/auth.py index d978281e..5d3906b9 100644 --- a/confluent_server/confluent/auth.py +++ b/confluent_server/confluent/auth.py @@ -99,17 +99,6 @@ _deniedbyrole = { } -def _prune_passcache(): - # This function makes sure we don't remember a passphrase in memory more - # than 10 seconds - while True: - curtime = time.time() - for passent in _passcache.iterkeys(): - if passent[2] < curtime - 90: - del _passcache[passent] - eventlet.sleep(90) - - def _get_usertenant(name, tenant=False): """_get_usertenant @@ -269,16 +258,27 @@ def check_user_passphrase(name, passphrase, operation=None, element=None, tenant _passcache[(user, tenant)] = hashlib.sha256(passphrase).digest() return authorize(user, element, tenant, operation) if pam: - pid = os.fork() - if not pid: - os.setuid(0) - pammy = pam.pam() - usergood = pammy.authenticate(user, passphrase, service=_pamservice) - os._exit(0 if usergood else 1) - usergood = os.waitpid(pid, 0)[1] - if usergood == 0: + if os.getuid() != 0: + # confluent is running with reduced privilege, however, pam_unix refuses + # to let a non-0 user check anothers password. + # We will fork and the child will assume elevated privilege to + # get unix_chkpwd helper to enable checking /etc/shadow + pid = os.fork() + if not pid: + usergood = False + try: + os.setuid(0) + usergood = pam.authenticate(user, passphrase, service=_pamservice) + finally: + os._exit(0 if usergood else 1) + usergood = os.waitpid(pid, 0)[1] == 0 + else: + # We are running as root, we don't need to fork in order to authenticate the + # user + usergood = pam.authenticate(user, passphrase, service=_pamservice) + if usergood: _passcache[(user, tenant)] = hashlib.sha256(passphrase).digest() - return authorize(user, element, tenant, operation, skipuserobj=False) + return authorize(user, element, tenant, operation, skipuserobj=False) eventlet.sleep(0.05) # stall even on test for existence of a username return None