Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added unlock account functionality #1705

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 65 additions & 4 deletions examples/changepasswd.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,56 @@ def _changePassword(
newPasswordEncoded = self.encodeLdapPassword(newPassword)
return self._modifyPassword(True, targetUsername, targetDomain, oldPasswordEncoded, newPasswordEncoded)

def unlockAccount(self, targetUsername, targetDomain):
"""
unlock account of a user

Must send a modify operation (must have privileges).
"""

if not targetUsername:
logging.critical("LDAP requires the target username")
return False

if not self.connect(targetDomain):
return False

targetDN = self.findTargetDN(targetUsername, targetDomain)
if not targetDN:
logging.critical("Could not find the target user in LDAP")
return False

logging.debug(f"Found target distinguishedName: {targetDN}")

# Build our Modify request
request = ldapasn1.ModifyRequest()
request["object"] = targetDN

request["changes"][0]["operation"] = ldapasn1.Operation("replace")
request["changes"][0]["modification"]["type"] = "lockoutTime"
request["changes"][0]["modification"]["vals"][0] = '0'

logging.debug(f"Sending: {str(request)}")

response = self.ldapConnection.sendReceive(request)[0]

logging.debug(f"Receiving: {str(response)}")

resultCode = int(response["protocolOp"]["modifyResponse"]["resultCode"])
result = str(ldapasn1.ResultCode(resultCode))
diagMessage = str(response["protocolOp"]["modifyResponse"]["diagnosticMessage"])

if result == "success":
logging.info(f"Account unlocked successfully: {targetDN}")
return True
elif result == "insufficientAccessRights":
logging.error(f"Could not unlock {targetDN}, {self.domain}\\{self.username} has insufficient rights")
else:
logging.error(f"Could not unlock {targetDN}. {result}: {diagMessage}")

return False


def _setPassword(self, targetUsername, targetDomain, newPassword, newPwdHashLM, newPwdHashNT):
"""
Set the password of a user.
Expand Down Expand Up @@ -788,6 +838,11 @@ def parse_args():
"ldap",
),
)
group.add_argument(
"-unlock",
action="store_true",
help="Try to unlock the account (requires -altuser and (-altpass or -althash))",
)
group.add_argument(
"-reset",
"-admin",
Expand Down Expand Up @@ -839,13 +894,14 @@ def parse_args():
"ldap": LdapPassword,
}


try:
PasswordProtocol = handlers[options.protocol]
PasswordProtocol = handlers[options.protocol if not options.unlock else "ldap"]
except KeyError:
logging.critical(f"Unsupported password protocol {options.protocol}")
sys.exit(1)

# Parse account whose password is changed
# Parse account whose password is changed or unlocked
targetDomain, targetUsername, oldPassword, address = parse_target(options.target)

if not targetDomain:
Expand All @@ -864,7 +920,7 @@ def parse_args():
oldPwdHashLM = ""
oldPwdHashNT = ""

if oldPassword == "" and oldPwdHashNT == "":
if oldPassword == "" and oldPwdHashNT == "" and not options.unlock:
if options.reset:
pass # no need for old one when we reset
elif options.no_pass:
Expand All @@ -884,7 +940,7 @@ def parse_args():
else:
newPwdHashLM = ""
newPwdHashNT = ""
if options.newpass is None:
if options.newpass is None and options.unlock is False:
newPassword = getpass("New password: ")
if newPassword != getpass("Retype new password: "):
logging.critical("Passwords do not match, try again.")
Expand Down Expand Up @@ -948,6 +1004,11 @@ def parse_args():
# Attempt the password change/reset
if options.reset:
handler.setPassword(targetUsername, targetDomain, newPassword, newPwdHashLM, newPwdHashNT)
elif options.unlock:
if not options.altuser or (not options.altpass and not options.althash):
logging.critical("You must specify an altuser and an althash or altpass to use unlock")
sys.exit(1)
handler.unlockAccount(targetUsername, targetDomain)
else:
if (authDomain, authUsername) != (targetDomain, targetUsername):
logging.warning(
Expand Down
Loading