From d5fe1795d40db8c61c0c84d29a8131600e0986bb Mon Sep 17 00:00:00 2001 From: Prashanth Pai Date: Wed, 15 Jan 2014 15:31:07 +0530 Subject: Handle case in passive mode where Kerberos password has expired In RHEL IdM or Windows AD server, the administrator can expire user passwords after certain period of time. On password expiry, running kinit will present a prompt to enter the new passwod. This used to result in kinit subprocess waiting indefinitely for user input and request never reaching completion. This fix will kill kinit child process if it is taking too long to finish. Change-Id: I129a420663c67debe3345448a172b54abc8179bc Signed-off-by: Prashanth Pai Reviewed-on: http://review.gluster.org/6713 Tested-by: Chetan Risbud Reviewed-by: Chetan Risbud --- swiftkerbauth/kerbauth.py | 4 ++++ swiftkerbauth/kerbauth_utils.py | 25 +++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/swiftkerbauth/kerbauth.py b/swiftkerbauth/kerbauth.py index c8b51fb..fa06bcd 100644 --- a/swiftkerbauth/kerbauth.py +++ b/swiftkerbauth/kerbauth.py @@ -407,6 +407,10 @@ class KerbAuth(object): return HTTPServerError("kinit command not found\n") if ret != 0: self.logger.warning("Failed: kinit %s", user) + if ret == -1: + self.logger.warning("Failed: kinit: Password has probably " + "expired.") + return HTTPServerError("Kinit is taking too long.\n") return HTTPUnauthorized(request=req) self.logger.debug("kinit succeeded") diff --git a/swiftkerbauth/kerbauth_utils.py b/swiftkerbauth/kerbauth_utils.py index 683cdea..effa472 100644 --- a/swiftkerbauth/kerbauth_utils.py +++ b/swiftkerbauth/kerbauth_utils.py @@ -16,6 +16,7 @@ import re import random import grp +import signal from subprocess import Popen, PIPE from time import time from swiftkerbauth import TOKEN_LIFE, RESELLER_PREFIX @@ -111,5 +112,25 @@ def run_kinit(username, password): kinit = Popen(['kinit', username], stdin=PIPE, stdout=PIPE, stderr=PIPE) kinit.stdin.write('%s\n' % password) - kinit.wait() - return kinit.returncode + + # The following code handles a corner case where the Kerberos password + # has expired and a prompt is displayed to enter new password. Ideally, + # we would want to read from stdout but these are blocked reads. This is + # a hack to kill the process if it's taking too long! + + class Alarm(Exception): + pass + + def signal_handler(signum, frame): + raise Alarm + # Set the signal handler and a 1-second alarm + signal.signal(signal.SIGALRM, signal_handler) + signal.alarm(1) + try: + kinit.wait() # Wait for the child to exit + signal.alarm(0) # Reset the alarm + return kinit.returncode # Exit status of child on graceful exit + except Alarm: + # Taking too long, kill and return error + kinit.kill() + return -1 -- cgit