Skip to content

Commit 42cdb1e

Browse files
committed
fixing canlogon
1 parent b25a284 commit 42cdb1e

File tree

3 files changed

+65
-11
lines changed

3 files changed

+65
-11
lines changed

Diff for: msldap/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
__version__ = "0.3.12"
2+
__version__ = "0.3.13"
33
__banner__ = \
44
"""
55
# msldap %s

Diff for: msldap/ldap_objects/adcomp.py

+55
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Tamas Jos (@skelsec)
55
#
66

7+
import datetime
78
from msldap.ldap_objects.common import MSLDAP_UAC, vn
89

910
MSADMachine_ATTRS = [
@@ -63,6 +64,53 @@ def __init__(self):
6364
self.whenCreated = None
6465
self.servicePrincipalName = None
6566
self.allowedtodelegateto = None
67+
68+
## calculated properties
69+
self.when_pw_change = None #datetime
70+
self.when_pw_expires = None #datetime
71+
self.must_change_pw = None #datetime
72+
self.canLogon = None #bool
73+
74+
# https://msdn.microsoft.com/en-us/library/cc245739.aspx
75+
def calc_PasswordMustChange(self, adinfo):
76+
# Crtieria 1
77+
flags = [MSLDAP_UAC.DONT_EXPIRE_PASSWD, MSLDAP_UAC.SMARTCARD_REQUIRED, MSLDAP_UAC.INTERDOMAIN_TRUST_ACCOUNT, MSLDAP_UAC.WORKSTATION_TRUST_ACCOUNT, MSLDAP_UAC.SERVER_TRUST_ACCOUNT]
78+
for flag in flags:
79+
if flag & self.userAccountControl:
80+
return datetime.datetime.max #never
81+
82+
#criteria 2
83+
if self.pwdLastSet == 0:
84+
return datetime.datetime.min
85+
86+
if adinfo.maxPwdAge == 0:
87+
return datetime.datetime.max #never
88+
89+
return (self.pwdLastSet - adinfo.maxPwdAge).replace(tzinfo=None)
90+
91+
92+
# https://msdn.microsoft.com/en-us/library/cc223991.aspx
93+
def calc_CanLogon(self):
94+
flags = [MSLDAP_UAC.ACCOUNTDISABLE, MSLDAP_UAC.LOCKOUT, MSLDAP_UAC.SMARTCARD_REQUIRED, MSLDAP_UAC.INTERDOMAIN_TRUST_ACCOUNT, MSLDAP_UAC.WORKSTATION_TRUST_ACCOUNT, MSLDAP_UAC.SERVER_TRUST_ACCOUNT]
95+
for flag in flags:
96+
if flag & self.userAccountControl:
97+
return False
98+
99+
if (not (MSLDAP_UAC.DONT_EXPIRE_PASSWD & self.userAccountControl)) and (self.accountExpires.replace(tzinfo=None) - datetime.datetime.now()).total_seconds() < 0:
100+
return False
101+
102+
#
103+
# TODO: logonHours check!
104+
#
105+
106+
if self.must_change_pw == datetime.datetime.min:
107+
#can logon, but must change the password!
108+
return True
109+
110+
if (self.must_change_pw - datetime.datetime.now()).total_seconds() < 0:
111+
return False
112+
113+
return True
66114

67115
@staticmethod
68116
def from_ldap(entry, adinfo = None):
@@ -106,6 +154,13 @@ def from_ldap(entry, adinfo = None):
106154
temp = entry['attributes'].get('userAccountControl')
107155
if temp:
108156
adi.userAccountControl = MSLDAP_UAC(temp)
157+
158+
if adinfo:
159+
adi.when_pw_change = (adi.pwdLastSet - adinfo.minPwdAge).replace(tzinfo=None)
160+
adi.when_pw_expires = (adi.pwdLastSet - adinfo.maxPwdAge).replace(tzinfo=None) if adinfo.maxPwdAge != 0 else adi.pwdLastSet
161+
adi.must_change_pw = adi.calc_PasswordMustChange(adinfo) #datetime
162+
adi.canLogon = adi.calc_CanLogon() #bool
163+
109164
return adi
110165

111166
def to_dict(self):

Diff for: msldap/ldap_objects/aduser.py

+9-10
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def __init__(self):
8080
self.canLogon = None #bool
8181

8282
# https://msdn.microsoft.com/en-us/library/cc245739.aspx
83-
def calc_PasswordMustChange(self):
83+
def calc_PasswordMustChange(self, adinfo):
8484
# Crtieria 1
8585
flags = [MSLDAP_UAC.DONT_EXPIRE_PASSWD, MSLDAP_UAC.SMARTCARD_REQUIRED, MSLDAP_UAC.INTERDOMAIN_TRUST_ACCOUNT, MSLDAP_UAC.WORKSTATION_TRUST_ACCOUNT, MSLDAP_UAC.SERVER_TRUST_ACCOUNT]
8686
for flag in flags:
@@ -91,10 +91,10 @@ def calc_PasswordMustChange(self):
9191
if self.pwdLastSet == 0:
9292
return datetime.datetime.min
9393

94-
if (self.when_pw_expires - datetime.datetime.now()).total_seconds() > 0:
94+
if adinfo.maxPwdAge == 0:
9595
return datetime.datetime.max #never
9696

97-
return self.pwdLastSet.replace(tzinfo=None)
97+
return (self.pwdLastSet - adinfo.maxPwdAge).replace(tzinfo=None)
9898

9999

100100
# https://msdn.microsoft.com/en-us/library/cc223991.aspx
@@ -103,8 +103,8 @@ def calc_CanLogon(self):
103103
for flag in flags:
104104
if flag & self.userAccountControl:
105105
return False
106-
107-
if (self.accountExpires.replace(tzinfo=None) - datetime.datetime.now()).total_seconds() < 0:
106+
107+
if (not (MSLDAP_UAC.DONT_EXPIRE_PASSWD & self.userAccountControl)) and (self.accountExpires.replace(tzinfo=None) - datetime.datetime.now()).total_seconds() < 0:
108108
return False
109109

110110
#
@@ -162,11 +162,10 @@ def from_ldap(entry, adinfo = None):
162162
adi.userAccountControl = MSLDAP_UAC(temp)
163163

164164
if adinfo:
165-
adi.when_pw_change = (adi.pwdLastSet - adinfo.minPwdAge/10000000).replace(tzinfo=None)
166-
adi.when_pw_expires = (adi.pwdLastSet - adinfo.maxPwdAge/10000000).replace(tzinfo=None)
167-
adi.must_change_pw = adi.calc_PasswordMustChange() #datetime
168-
if adi.sAMAccountName[-1] != '$':
169-
adi.canLogon = adi.calc_CanLogon() #bool
165+
adi.when_pw_change = (adi.pwdLastSet - adinfo.minPwdAge).replace(tzinfo=None)
166+
adi.when_pw_expires = (adi.pwdLastSet - adinfo.maxPwdAge).replace(tzinfo=None) if adinfo.maxPwdAge != 0 else adi.pwdLastSet
167+
adi.must_change_pw = adi.calc_PasswordMustChange(adinfo) #datetime
168+
adi.canLogon = adi.calc_CanLogon() #bool
170169

171170

172171
return adi

0 commit comments

Comments
 (0)