Reputation: 41
I am trying to create a service account via the Ldap3 library in Python. The service account is successfully created, but there is a small problem. The "User cannot change password" checkboxes is not selected.
I did some research and found that to set this property I need to follow some steps given here : https://learn.microsoft.com/en-us/windows/win32/adsi/modifying-user-cannot-change - password-ldap-provider . The logic given in this link is in a different programming language than Python, so i tried to replicate the same logic in Python. From what we understand, I’ve implemented the feature, which executed successfully, but didn't see the expected effect on the AD server ("User cannot change password" checkbox is still unchecked).
Below is the code used to create and add the ACL object to the service account.
def create_object_ace(privguid, sid):
print("creating ace object")
nace = ldaptypes.ACE()
nace['AceType'] = ldaptypes.ACCESS_DENIED_OBJECT_ACE.ACE_TYPE
nace['AceFlags'] = 0x00
acedata = ldaptypes.ACCESS_DENIED_OBJECT_ACE()
acedata['Mask'] = ldaptypes.ACCESS_MASK()
acedata['Mask']['Mask'] = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_CONTROL_ACCESS
acedata['ObjectType'] = string_to_bin(privguid)
acedata['InheritedObjectType'] = b''
acedata['Sid'] = ldaptypes.LDAP_SID()
acedata['Sid'].fromCanonical(sid)
assert sid == acedata['Sid'].formatCanonical()
acedata['Flags'] = ldaptypes.ACCESS_DENIED_OBJECT_ACE.ACE_OBJECT_TYPE_PRESENT
nace['Ace'] = acedata
return nace
s = Server('ad_server.com', get_info=ALL)
c = Connection(s, user="testdomain\\username", password="password", authentication=NTLM)
c.search(search_base="DC=testad,DC=com", search_filter="(CN=svc_account_47)",
search_scope=SUBTREE, attributes=['objectSid', 'sAMAccountName'])
entry = c.entries[0]
usersid = entry['objectSid'].value
controls = security_descriptor_control(sdflags=0x04)
c.search(search_base="DC=testahs,DC=com", search_filter='(&(objectCategory=domain))',
attributes=['SAMAccountName', 'nTSecurityDescriptor'], controls=controls)
entry = c.entries[0]
secDescData =. entry['nTSecurityDescriptor'].raw_values[0]
secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)
secDesc['Dacl']['Data'].append(create_object_ace('ab721a53-1e2f-11d0-9819-00aa0040529b', usersid)) # This GUID is for 'User cannot change password'
dn = entry.entry_dn
data = secDesc.getData()
c.modify(dn, {'nTSecurityDescriptor': (ldap3.MODIFY_REPLACE, [data])}, controls=controls)
print(c.result)
# gives -> {'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'modifyResponse'}
The Python code reference is from the following link:
Can someone help me here. Thanks in advance.
Upvotes: 2
Views: 520
Reputation: 115
The only way I could do this in Python was this:
import uuid
import bonsai
from bonsai import LDAPClient
from bonsai.active_directory import SecurityDescriptor
def set_not_change_pass(self, userdn):
client = LDAPClient(f"ldap://{self._server}")
client.set_credentials("SIMPLE", user=f"CN={self._srvaccname},CN=Users,{self._dc}",
password=self._srvaccpass)
with client.connect() as conn:
entry = conn.search(
userdn, 0, attrlist=["ntSecurityDescriptor", "userAccountControl"]
)[0]
uac = bonsai.active_directory.UserAccountControl(entry["userAccountControl"][0])
sec_desc = bonsai.active_directory.SecurityDescriptor.from_binary(
entry["ntSecurityDescriptor"][0]
)
new_dacl_aces = []
for ace in sec_desc.dacl.aces:
if ace.object_type == uuid.UUID("ab721a53-1e2f-11d0-9819-00aa0040529b"):
# Find change password ACE and change it to deny.
new_ace = bonsai.active_directory.ACE(
bonsai.active_directory.ACEType.ACCESS_DENIED_OBJECT,
ace.flags,
ace.mask,
ace.trustee_sid,
ace.object_type,
ace.inherited_object_type,
ace.application_data,
)
# Insert new deny ACEs to the front of the list.
new_dacl_aces.insert(0, new_ace)
else:
new_dacl_aces.append(ace)
new_dacl = bonsai.active_directory.ACL(sec_desc.dacl.revision, new_dacl_aces)
new_sec_desc = bonsai.active_directory.SecurityDescriptor(
sec_desc.control,
sec_desc.owner_sid,
sec_desc.group_sid,
sec_desc.sacl,
new_dacl,
sec_desc.revision,
sec_desc.sbz1,
)
entry.change_attribute(
"ntSecurityDescriptor", bonsai.LDAPModOp.REPLACE, new_sec_desc.to_binary()
)
uac.properties["accountdisable"] = False
entry.change_attribute("userAccountControl", bonsai.LDAPModOp.REPLACE, uac.value)
entry.modify()
Upvotes: 0