0
votes

I have been trying to set an account attribute for an Active Directory user but this one attribute cannot be applied the same way as other account attributes (ACE type), im applying the other attributes but "User cannot change password" is the one attribute im unable to do with python programmatically. This is the code im using to set the password in AD and set attributes for "Password never expires" and "Store password using reversable encyption"

My sources for the code came from here: https://blog.steamsprocket.org.uk/2011/07/04/user-cannot-change-password-using-python/

Someone else other attempt was here but i'm unable to apply it:https://web.archive.org/web/20150829114442/http://www.robertmeany.com/programming/python-and-the-active-directory-security_descriptor/

Hopefully someone may be able to assist me, thank you.

import ldap3
from ldap3 import Connection,Server,ALL,SUBTREE,MODIFY_REPLACE
zid = input("username: ")
zid = str(zid).lower()
print(f'Searching for {zid}')
server = Server('ldaps://IP_OF_MY_AD_SERVER', use_ssl=True, get_info=all)
conn = Connection(server, user='DOMAIN\\USERNAME', password='password',   auto_bind=True)
conn.bind()
Path_Root = "DC=kurnai,DC=lan"
Filter = f'(&(objectclass=user)(&(sAMAccountName={zid})(!(objectclass=computer))))'
conn.search(search_base = Path_Root,
     search_filter = Filter,
     search_scope = SUBTREE,
     attributes = ["cn", "sAMAccountName", "displayName"]
     )
if len(conn.entries) == 1:
    USER_DN = conn.response[0].get("dn")
    print(USER_DN)
try:
   new_password = "A__PASSWORD22"
   print(new_password)
   print("New password successfully applied")
except:
print("New password could not be applied")
#setting the password:
try:
   res = ldap3.extend.microsoft.modifyPassword.ad_modify_password(conn, USER_DN, new_password, old_password=None,  controls=None)
   res = conn.extend.microsoft.modify_password(USER_DN, new_password)
   changeUACattribute = {'userAccountControl': [('MODIFY_REPLACE', 66236)]}
   conn.modify(USER_DN, changes=changeUACattribute)
   print(conn.result)
   print(res)
   if res:
       print('user %s change password Success.')
       print('password: %s' %new_password)
   else:
       print('user %s change password Failed.')
 except Exception as e:
    print(f'Error setting AD password: {e}')

This is the code im trying to apply the nTSecurityDescriptor:

import win32security
import win32com.client as win32

domains = ["FQDN","IP_OF_DOMAIN"]
username = "DOMAIN\\USERNAME"
print(username)
password = input("Password: ")

print ("AUTHENTICATING ACCOUNT...")

for d in domains:
   try:
      token = win32security.LogonUser(
         username,
         d,
         password,
         win32security.LOGON32_LOGON_NEW_CREDENTIALS,
         win32security.LOGON32_PROVIDER_DEFAULT)
         authenticated = True
         token.Close()
       break
    except:
    authenticated = False

if (authenticated):
   print ("VALID ACCOUNT!")
else:
   print ("Wrong username or password!")

authenticated = bool(token)
ChangePasswordGuid = '{ab721a53-1e2f-11d0-9819-00aa0040529b}'
ADS_ACETYPE_ACCESS_DENIED_OBJECT = 0x6
SID_SELF = "S-1-5-10"
SID_EVERYONE = "S-1-1-0"

selfAccount = win32security.LookupAccountSid(None,
        win32security.GetBinarySid(SID_SELF))
everyoneAccount = win32security.LookupAccountSid(None,
        win32security.GetBinarySid(SID_EVERYONE))
selfName = ("%s\\%s" % (selfAccount[1], selfAccount[0])).strip('\\')
everyoneName = ("%s\\%s" % (everyoneAccount[1], everyoneAccount[0])).strip('\\')
print(USER_DN)
location = USER_DN
user = win32.GetObject("ldap://cn=%s,%s" % (zid, location))
print(user)
sd = user.nTSecurityDescriptor
dacl = sd.DiscretionaryAcl
for ace in dacl:
    if ace.ObjectType.lower() == ChangePasswordGuid.lower():
        if ace.Trustee == selfName or ace.Trustee == everyoneName:
            ace.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT

sd.DiscretionaryAcl = dacl
user.Put('ntSecurityDescriptor', sd)
user.SetInfo()

The Error:

 sd = USER_DN.nTSecurityDescriptor
 AttributeError: 'str' object has no attribute 'nTSecurityDescriptor'