def set_attribute_with_provision_ctrl(self, dn, key, value): LDB_CONTROL_PROVISION_OID = '1.3.6.1.4.1.7165.4.3.16' DSDB_CONTROL_REPLICATED_UPDATE_OID = '1.3.6.1.4.1.7165.4.3.3' ctrls = [ LDAPControl(LDB_CONTROL_PROVISION_OID, criticality=0), LDAPControl(DSDB_CONTROL_REPLICATED_UPDATE_OID, criticality=0), ] + self.serverctrls_for_add_and_modify self.lo.modify_ext_s(dn, [(ldap.MOD_REPLACE, key, value)], serverctrls=ctrls)
def __init__(self, criticality=True, flags=0, maxattributecount=-1, cookie=None): LDAPControl.__init__(self, DirSyncCtrl.controlType, criticality) self.flags = flags self.maxattributecount = maxattributecount self.cookie = cookie self.controlValue = None
def connect(self, no_starttls=False): self.ldapdeleteControl = LDAPControl('1.2.840.113556.1.4.417', criticality=1) self.serverctrls_for_add_and_modify = [] if 'univention_samaccountname_ldap_check' in baseConfig.get( 'samba4/ldb/sam/module/prepend', '').split(): ## The S4 connector must bypass this LDB module if it is activated via samba4/ldb/sam/module/prepend ## The OID of the 'bypass_samaccountname_ldap_check' control is defined in ldb.h ldb_ctrl_bypass_samaccountname_ldap_check = LDAPControl( '1.3.6.1.4.1.10176.1004.0.4.1', criticality=0) self.serverctrls_for_add_and_modify.append( ldb_ctrl_bypass_samaccountname_ldap_check) self.timeout = 5 use_starttls = 2 if no_starttls: use_starttls = 0 if self.pw_file: fp = open(self.pw_file, 'r') login_pw = fp.readline() if login_pw[-1] == '\n': login_pw = login_pw[:-1] fp.close() try: tls_mode = 2 if self.ssl == "no" or use_starttls == 0: tls_mode = 0 if self.protocol == 'ldapi': import urllib socket = urllib.quote(self.socket, '') ldapuri = "%s://%s" % (self.protocol, socket) else: ldapuri = "%s://%s:%d" % (self.protocol, self.adldapbase, int(self.port)) # lo=univention.uldap.access(host=self.host, port=int(self.port), base=self.adldapbase, binddn=self.login_dn , bindpw=self.pw_file, start_tls=tls_mode, ca_certfile=self.ca_file, decode_ignorelist=['objectSid', 'objectGUID', 'repsFrom', 'replUpToDateVector', 'ipsecData', 'logonHours', 'userCertificate', 'dNSProperty', 'dnsRecord', 'member'], uri=ldapuri) self.lo = ldap.initialize(ldapuri) if tls_mode > 0: self.lo.start_tls_s() self.lo.set_option(ldap.OPT_REFERRALS, 0) except: ex = 'LDAP Connection to "%s:%s" as "%s" with password "%s" failed (TLS: %s)\n' % ( self.host, self.port, self.login_dn, login_pw, not no_starttls) import traceback raise Exception(ex + traceback.format_exc())
def set_attribute_with_provision_ctrl(self, dn, key, value): LDB_CONTROL_PROVISION_OID = '1.3.6.1.4.1.7165.4.3.16' ctrls = [LDAPControl(LDB_CONTROL_PROVISION_OID, criticality=0) ] + self.serverctrls_for_add_and_modify self.lo.modify_ext_s(s4.compatible_modstring(unicode(dn)), [(ldap.MOD_REPLACE, key, value)], serverctrls=ctrls)
def connect(self, no_starttls=False): self.ldapdeleteControl = LDAPControl('1.2.840.113556.1.4.417', criticality=1) self.timeout = 5 use_starttls = 2 if no_starttls: use_starttls = 0 fp = open(self.pw_file, 'r') login_pw = fp.readline() if login_pw[-1] == '\n': login_pw = login_pw[:-1] fp.close() try: self.lo = ldap.initialize(uri="ldap://%s:%s" % (self.host, self.port)) if self.ca_file: ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.ca_file) if use_starttls: self.lo.start_tls_s() self.lo.simple_bind_s(self.login_dn, login_pw) except: ex = 'LDAP Connection to "%s:%s" as "%s" with password "%s" failed (TLS: %s, Certificate: %s)\n' % ( self.host, self.port, self.login_dn, login_pw, not no_starttls, self.ca_file) import traceback raise Exception(ex + traceback.format_exc()) self.lo.set_option(ldap.OPT_REFERRALS, 0)
def sid_to_s4(s4connector, key, object): ud.debug(ud.LDAP, ud.INFO, "sid_to_s4 object: %s" % object) sidAttribute = 'sambaSID' if s4connector.configRegistry.is_false('connector/s4/mapping/sid', False): ud.debug( ud.LDAP, ud.INFO, 'sid_to_s4: SID mapping is disabled via UCR: connector/s4/mapping/sid' ) sidAttribute = 'univentionSamba4SID' else: # This case will be handled by direct mapping return # object dn was already mapped to the s4 DN: s4_dn = object['dn'] modlist = [] # search the ucs object via if not object['attributes'].has_key(sidAttribute): ud.debug(ud.LDAP, ud.INFO, 'sid_to_s4: UCS object does not have a %s' % sidAttribute) return sambaSID = object['attributes'][sidAttribute] # get the ad sid (s4_dn, s4_attributes) = s4connector.lo_s4.lo.search_s(s4_dn, ldap.SCOPE_BASE, '(objectSid=*)', ['objectSid'])[0] objectSid = s4_attributes.get('objectSid') if objectSid: # decoded_s4_sid = univention.s4connector.s4.decode_sid(objectSid[0]) s4_objectSid = ndr_unpack(security.dom_sid, objectSid[0]) decoded_s4_sid = str(s4_objectSid) if decoded_s4_sid == sambaSID[0]: ud.debug(ud.LDAP, ud.INFO, 'sid_to_s4: objectSid and %s are equal' % sidAttribute) return ### change objectSID # http://serverfault.com/questions/53717/how-can-i-change-the-sid-of-a-user-account-in-the-active-directory # http://technet.microsoft.com/en-us/library/cc961998.aspx ud.debug( ud.LDAP, ud.INFO, 'sid_to_s4: changing objectSid from %s to %s' % (decoded_s4_sid, sambaSID[0])) new_objectSid_ndr = ndr_pack(security.dom_sid(sambaSID[0])) modlist.append((ldap.MOD_REPLACE, 'objectSid', new_objectSid_ndr)) # objectSid modification for an Samba4 object is only possible with the "provision" control: LDB_CONTROL_PROVISION_OID = '1.3.6.1.4.1.7165.4.3.16' controls = [LDAPControl(LDB_CONTROL_PROVISION_OID, criticality=0)] s4connector.lo_s4.lo.modify_ext_s(s4_dn, modlist, serverctrls=controls) pass
def connect(self, no_starttls=False): self.ldapdeleteControl = LDAPControl('1.2.840.113556.1.4.417', criticality=1) self.timeout = 5 use_starttls = 2 if no_starttls: use_starttls = 0 fp = open(self.pw_file, 'r') login_pw = fp.readline() if login_pw[-1] == '\n': login_pw = login_pw[:-1] fp.close() try: self.lo = ldap.initialize(uri="ldap://%s:%s" % (self.host, self.port)) if self.ca_file: ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.ca_file) if use_starttls: self.lo.start_tls_s() except Exception: ex = 'LDAP Connection to "%s:%s" failed (TLS: %s, Certificate: %s)\n' % ( self.host, self.port, not no_starttls, self.ca_file) import traceback raise Exception(ex + traceback.format_exc()) try: if self.kerberos: os.environ['KRB5CCNAME'] = '/tmp/ucs-test-ldap-glue.cc' self.get_kerberos_ticket() auth = ldap.sasl.gssapi("") self.lo.sasl_interactive_bind_s("", auth) else: self.lo.simple_bind_s(self.login_dn, login_pw) except Exception: if self.kerberos: cred_msg = '"%s" with Kerberos password "%s"' (self.principal, login_pw) else: cred_msg = '"%s" with simplebind password "%s"' % ( self.login_dn, login_pw) ex = 'LDAP Bind as %s failed over connection to "%s:%s" (TLS: %s, Certificate: %s)\n' % ( self.login_dn, cred_msg, self.host, self.port, not no_starttls, self.ca_file) import traceback raise Exception(ex + traceback.format_exc()) self.lo.set_option(ldap.OPT_REFERRALS, 0)
def __get_server_controls(self): """Create the proxy user server control. The control has the form 0x04 = Octet String 4|0x80 sets the length of the string length field at 4 bytes the struct() gets us the length in bytes of string self.proxydn self.proxydn is the proxy dn to send""" if self.proxydn is not None: proxydn = chr(0x04) + chr(4|0x80) + struct.pack('l', socket.htonl(len(self.proxydn))) + self.proxydn; # Create the proxy control sctrl=[] sctrl.append(LDAPControl('2.16.840.1.113730.3.4.18',True,proxydn)) else: sctrl=None return sctrl
def connect(self, no_starttls=False): self.ldapdeleteControl = LDAPControl('1.2.840.113556.1.4.417', criticality=1) self.timeout = 5 use_starttls = 2 if no_starttls: use_starttls = 0 if self.pw_file: fp = open(self.pw_file, 'r') login_pw = fp.readline() if login_pw[-1] == '\n': login_pw = login_pw[:-1] fp.close() try: tls_mode = 2 if self.ssl == "no" or use_starttls == 0: tls_mode = 0 if self.protocol == 'ldapi': import urllib socket = urllib.quote(self.socket, '') ldapuri = "%s://%s" % (self.protocol, socket) else: ldapuri = "%s://%s:%d" % (self.protocol, self.adldapbase, int(self.port)) # lo=univention.uldap.access(host=self.host, port=int(self.port), base=self.adldapbase, binddn=self.login_dn , bindpw=self.pw_file, start_tls=tls_mode, ca_certfile=self.ca_file, decode_ignorelist=['objectSid', 'objectGUID', 'repsFrom', 'replUpToDateVector', 'ipsecData', 'logonHours', 'userCertificate', 'dNSProperty', 'dnsRecord', 'member'], uri=ldapuri) self.lo = ldap.initialize(ldapuri) if tls_mode > 0: self.lo.start_tls_s() self.lo.set_option(ldap.OPT_REFERRALS, 0) except: ex = 'LDAP Connection to "%s:%s" as "%s" with password "%s" failed (TLS: %s)\n' % ( self.host, self.port, self.login_dn, login_pw, not no_starttls) import traceback raise Exception(ex + traceback.format_exc())
def __init__(self, criticality, controlValue=None, encodedControlValue=None): LDAPControl.__init__(self, self.controlType, criticality, controlValue, encodedControlValue)
def __init__(self, criticality, authzId=None): LDAPControl.__init__(self, '1.3.6.1.4.1.42.2.27.9.5.2', criticality, authzId)
def __init__(self, derefspeclist, criticality=True): LDAPControl.__init__(self, DerefCtrl.controlType, criticality, derefspeclist)
def __init__(self,criticality=True,flags=0,maxattributecount=-1,cookie=None): LDAPControl.__init__(self,DirSyncCtrl.controlType,criticality) self.flags = flags self.maxattributecount = maxattributecount self.cookie = cookie self.controlValue = None
def __init__(self, criticality=True): LDAPControl.__init__(self, TestCtrl.controlType, criticality)
def __init__(self,criticality=False,derefSpecs=None): LDAPControl.__init__(self,self.controlType,criticality) self.derefSpecs = derefSpecs or {}
USER_FILTER = "(&(objectClass=person)(primaryGroupID=7235))" USER_BASE = "ou=Special Peeps,ou=My Users,dc=host,dc=com" PAGE_SIZE = 10 # LDAP connection try: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, 0) ldap_connection = ldap.initialize(LDAP_SERVER) ldap_connection.simple_bind_s(BIND_DN, BIND_PASS) except ldap.LDAPError as e: sys.stderr.write('Error connecting to LDAP server: ' + str(e) + '\n') sys.exit(1) # Lookup usernames from LDAP via paged search control = LDAPControl() paged_results_control = SimplePagedResultsControl( ldap.LDAP, True, (PAGE_SIZE, '')) accounts = [] pages = 0 while True: serverctrls = [paged_results_control] try: msgid = ldap_connection.search_ext(USER_BASE, ldap.SCOPE_ONELEVEL, USER_FILTER, attrlist=['employeeID', 'sAMAccountName'], serverctrls=serverctrls) except ldap.LDAPError as e: sys.stderr.write('Error performing user paged search: ' +
print(60 * '#') pprint.pprint(l.get_option(ldap.OPT_SERVER_CONTROLS)) l.manage_dsa_it(1, 1) pprint.pprint(l.get_option(ldap.OPT_SERVER_CONTROLS)) print(60 * '#') # Search with ManageDsaIT control (which has no value) pprint.pprint( l.search_ext_s( 'cn=Test-Referral,ou=Testing,dc=stroeder,dc=de', ldap.SCOPE_BASE, '(objectClass=*)', ['*', '+'], serverctrls=[LDAPControl('2.16.840.1.113730.3.4.2', 1, None)], )) print(60 * '#') # Search with Subentries control (which has boolean value) pprint.pprint( l.search_ext_s( 'dc=stroeder,dc=de', ldap.SCOPE_SUBTREE, '(objectClass=subentry)', ['*', '+'], serverctrls=[BooleanControl('1.3.6.1.4.1.4203.1.10.1', 1, 1)], )) print(60 * '#')
def __init__(self,criticality=True): LDAPControl.__init__(self,TestCtrl.controlType,criticality)
def __init__(self, criticality=True, deref=None): LDAPControl.__init__(self, CONTROL_DEREF, criticality) self.deref = deref
def password_sync_ucs_to_s4(s4connector, key, object): _d = ud.function('ldap.s4.password_sync_ucs_to_s4') ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4 called") modify = False old_ucs_object = object.get('old_ucs_object', {}) new_ucs_object = object.get('new_ucs_object', {}) if old_ucs_object or new_ucs_object: for attr in ['sambaLMPassword', 'sambaNTPassword', 'sambaPwdLastSet', 'sambaPwdMustChange', 'krb5PrincipalName', 'krb5Key', 'shadowLastChange', 'shadowMax', 'krb5PasswordEnd', 'univentionService']: old_values = set(old_ucs_object.get(attr, [])) new_values = set(new_ucs_object.get(attr, [])) if old_values != new_values: modify = True break else: # add mode modify = True if not modify: ud.debug(ud.LDAP, ud.INFO, 'password_sync_ucs_to_s4: the password for %s has not been changed. Skipping password sync.' % (object['dn'])) return try: ud.debug(ud.LDAP, ud.INFO, "Object DN=%s" % object['dn']) except: # FIXME: which exception is to be caught? ud.debug(ud.LDAP, ud.INFO, "Object DN not printable") ucs_object = s4connector._object_mapping(key, object, 'con') try: ud.debug(ud.LDAP, ud.INFO, " UCS DN = %s" % ucs_object['dn']) except: # FIXME: which exception is to be caught? ud.debug(ud.LDAP, ud.INFO, " UCS DN not printable") try: ucs_object_attributes = s4connector.lo.get(ucs_object['dn'], ['sambaLMPassword', 'sambaNTPassword', 'sambaPwdLastSet', 'sambaPwdMustChange', 'krb5PrincipalName', 'krb5Key', 'shadowLastChange', 'shadowMax', 'krb5PasswordEnd', 'univentionService'], required=True) except ldap.NO_SUCH_OBJECT: ud.debug(ud.LDAP, ud.PROCESS, "password_sync_ucs_to_s4: The UCS object (%s) was not found. The object was removed." % ucs_object['dn']) return services = ucs_object_attributes.get('univentionService', []) if 'Samba 4' in services: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: %s is a S4 server, skip password sync" % ucs_object['dn']) return sambaPwdLastSet = None if 'sambaPwdLastSet' in ucs_object_attributes: sambaPwdLastSet = long(ucs_object_attributes['sambaPwdLastSet'][0]) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaPwdLastSet: %s" % sambaPwdLastSet) if 'sambaPwdMustChange' in ucs_object_attributes: sambaPwdMustChange = long(ucs_object_attributes['sambaPwdMustChange'][0]) ud.debug(ud.LDAP, ud.WARN, "password_sync_ucs_to_s4: Ignoring sambaPwdMustChange: %s" % sambaPwdMustChange) ucsLMhash = ucs_object_attributes.get('sambaLMPassword', [None])[0] ucsNThash = ucs_object_attributes.get('sambaNTPassword', [None])[0] krb5Principal = ucs_object_attributes.get('krb5PrincipalName', [None])[0] krb5Key = ucs_object_attributes.get('krb5Key', []) if not ucsNThash: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaNTPassword missing in UCS LDAP, trying krb5Key") ucsNThash = extract_NThash_from_krb5key(krb5Key) if not ucsNThash: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get NT Password-Hash from UCS LDAP") # ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Password-Hash from UCS: %s" % ucsNThash) s4_object_attributes = s4connector.lo_s4.get(compatible_modstring(object['dn']), ['pwdLastSet', 'objectSid']) pwdLastSet = None if 'pwdLastSet' in s4_object_attributes: pwdLastSet = long(s4_object_attributes['pwdLastSet'][0]) objectSid = univention.s4connector.s4.decode_sid(s4_object_attributes['objectSid'][0]) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdLastSet from S4 : %s" % pwdLastSet) # rid = None # if s4_object_attributes.has_key('objectSid'): # rid = str(univention.s4connector.s4.decode_sid(s4_object_attributes['objectSid'][0]).split('-')[-1]) pwd_set = False filter_expr = format_escaped('(objectSid={0!e})', objectSid) res = s4connector.lo_s4.search(filter=filter_expr, attr=['unicodePwd', 'userPrincipalName', 'supplementalCredentials', 'msDS-KeyVersionNumber', 'dBCSPwd']) s4_search_attributes = res[0][1] unicodePwd_attr = s4_search_attributes.get('unicodePwd', [None])[0] dBCSPwd_attr = s4_search_attributes.get('dBCSPwd', [None])[0] userPrincipalName_attr = s4_search_attributes.get('userPrincipalName', [None])[0] supplementalCredentials = s4_search_attributes.get('supplementalCredentials', [None])[0] msDS_KeyVersionNumber = s4_search_attributes.get('msDS-KeyVersionNumber', [0])[0] # ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Password-Hash from S4: %s" % unicodePwd_attr) s4NThash = None if unicodePwd_attr: s4NThash = binascii.b2a_hex(unicodePwd_attr).upper() else: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get NT Password-Hash from S4") s4LMhash = None if dBCSPwd_attr: s4LMhash = binascii.b2a_hex(dBCSPwd_attr).upper() else: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get LM Password-Hash from S4") modlist = [] if krb5Principal != userPrincipalName_attr: if krb5Principal: if not userPrincipalName_attr: # new and not old modlist.append((ldap.MOD_ADD, 'userPrincipalName', krb5Principal)) else: # new and old differ if krb5Principal.lower() != userPrincipalName_attr.lower(): ud.debug(ud.LDAP, ud.WARN, "password_sync_ucs_to_s4: userPrincipalName != krb5Principal: '%s' != '%s'" % (userPrincipalName_attr, krb5Principal)) modlist.append((ldap.MOD_REPLACE, 'userPrincipalName', krb5Principal)) else: if userPrincipalName_attr: # old and not new modlist.append((ldap.MOD_DELETE, 'userPrincipalName', userPrincipalName_attr)) if not ucsNThash == s4NThash: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: NT Hash S4: %s NT Hash UCS: %s" % (s4NThash, ucsNThash)) # Now if ucsNThash is empty there should at least some timestamp in UCS, # otherwise it's probably not a good idea to remove the unicodePwd. # Usecase: LDB module on ucs_3.0-0-ucsschool slaves creates XP computers/windows in UDM without password if ucsNThash or sambaPwdLastSet: pwd_set = True unicodePwd_new = None if ucsNThash: try: unicodePwd_new = binascii.a2b_hex(ucsNThash) except TypeError as exc: if ucsNThash.startswith("NO PASSWORD"): pwd_set = False else: raise if pwd_set: if unicodePwd_attr: modlist.append((ldap.MOD_DELETE, 'unicodePwd', unicodePwd_attr)) if unicodePwd_new: modlist.append((ldap.MOD_ADD, 'unicodePwd', unicodePwd_new)) if not ucsLMhash == s4LMhash: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: LM Hash S4: %s LM Hash UCS: %s" % (s4LMhash, ucsLMhash)) pwd_set = True if dBCSPwd_attr: modlist.append((ldap.MOD_DELETE, 'dBCSPwd', dBCSPwd_attr)) if ucsLMhash: dBCSPwd_new = binascii.a2b_hex(ucsLMhash) modlist.append((ldap.MOD_ADD, 'dBCSPwd', dBCSPwd_new)) if pwd_set or not supplementalCredentials: if krb5Principal: # encoding of Samba4 supplementalCredentials if supplementalCredentials: modlist.append((ldap.MOD_DELETE, 'supplementalCredentials', supplementalCredentials)) if krb5Key: supplementalCredentials_new = calculate_supplementalCredentials(krb5Key, supplementalCredentials) if supplementalCredentials_new: modlist.append((ldap.MOD_ADD, 'supplementalCredentials', supplementalCredentials_new)) else: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: no supplementalCredentials_new") # if supplementalCredentials: # modlist.append((ldap.MOD_REPLACE, 'msDS-KeyVersionNumber', krb5KeyVersionNumber)) # else: # modlist.append((ldap.MOD_ADD, 'msDS-KeyVersionNumber', krb5KeyVersionNumber)) if sambaPwdLastSet is None: sambaPwdLastSet = int(time.time()) newpwdlastset = str(univention.s4connector.s4.samba2s4_time(sambaPwdLastSet)) elif sambaPwdLastSet in [0, 1]: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: samba pwd expired, set newpwdLastSet to 0") newpwdlastset = 0 else: newpwdlastset = univention.s4connector.s4.samba2s4_time(sambaPwdLastSet) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdLastSet in modlist: %s" % newpwdlastset) modlist.append((ldap.MOD_REPLACE, 'pwdLastSet', str(newpwdlastset))) modlist.append((ldap.MOD_REPLACE, 'badPwdCount', '0')) modlist.append((ldap.MOD_REPLACE, 'badPasswordTime', '0')) modlist.append((ldap.MOD_REPLACE, 'lockoutTime', '0')) else: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: No password change to sync to S4 ") # check pwdLastSet if sambaPwdLastSet is not None: if sambaPwdLastSet in [0, 1]: newpwdlastset = 0 else: newpwdlastset = univention.s4connector.s4.samba2s4_time(sambaPwdLastSet) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaPwdLastSet: %d" % sambaPwdLastSet) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: newpwdlastset : %s" % newpwdlastset) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdLastSet (AD): %s" % pwdLastSet) if newpwdlastset != pwdLastSet and abs(newpwdlastset - pwdLastSet) >= 10000000: modlist.append((ldap.MOD_REPLACE, 'pwdLastSet', str(newpwdlastset))) # TODO: Password History ctrl_bypass_password_hash = LDAPControl('1.3.6.1.4.1.7165.4.3.12', criticality=0) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: modlist: %s" % modlist) if modlist: s4connector.lo_s4.lo.modify_ext_s(compatible_modstring(object['dn']), modlist, serverctrls=[ctrl_bypass_password_hash])
def __init__(self, criticality=False, derefSpecs=None): LDAPControl.__init__(self, self.controlType, criticality) self.derefSpecs = derefSpecs or {}
def password_sync_ucs_to_s4(s4connector, key, object): _d = ud.function('ldap.s4.password_sync_ucs_to_s4') ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4 called") compatible_modstring = univention.s4connector.s4.compatible_modstring try: ud.debug(ud.LDAP, ud.INFO, "Object DN=%s" % object['dn']) except: # FIXME: which exception is to be caught? ud.debug(ud.LDAP, ud.INFO, "Object DN not printable") ucs_object = s4connector._object_mapping(key, object, 'con') try: ud.debug(ud.LDAP, ud.INFO, " UCS DN = %s" % ucs_object['dn']) except: # FIXME: which exception is to be caught? ud.debug(ud.LDAP, ud.INFO, " UCS DN not printable") try: res = s4connector.lo.lo.search( base=ucs_object['dn'], scope='base', attr=[ 'sambaLMPassword', 'sambaNTPassword', 'sambaPwdLastSet', 'sambaPwdMustChange', 'krb5PrincipalName', 'krb5Key', 'shadowLastChange', 'shadowMax', 'krb5PasswordEnd', 'univentionService' ]) except ldap.NO_SUCH_OBJECT: ud.debug( ud.LDAP, ud.PROCESS, "password_sync_ucs_to_s4: The UCS object (%s) was not found. The object was removed." % ucs_object['dn']) return services = res[0][1].get('univentionService', []) if 'Samba 4' in services: ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: %s is a S4 server, skip password sync" % ucs_object['dn']) return sambaPwdLastSet = None if res[0][1].has_key('sambaPwdLastSet'): sambaPwdLastSet = long(res[0][1]['sambaPwdLastSet'][0]) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaPwdLastSet: %s" % sambaPwdLastSet) sambaPwdMustChange = -1 if res[0][1].has_key('sambaPwdMustChange'): sambaPwdMustChange = long(res[0][1]['sambaPwdMustChange'][0]) ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaPwdMustChange: %s" % sambaPwdMustChange) ucsLMhash = res[0][1].get('sambaLMPassword', [None])[0] ucsNThash = res[0][1].get('sambaNTPassword', [None])[0] krb5Principal = res[0][1].get('krb5PrincipalName', [None])[0] krb5Key = res[0][1].get('krb5Key', []) if not ucsNThash: ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaNTPassword missing in UCS LDAP, trying krb5Key" ) ucsNThash = extract_NThash_from_krb5key(krb5Key) if not ucsNThash: ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get NT Password-Hash from UCS LDAP" ) # ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Password-Hash from UCS: %s" % ucsNThash) res = s4connector.lo_s4.lo.search_s( univention.s4connector.s4.compatible_modstring(object['dn']), ldap.SCOPE_BASE, '(objectClass=*)', ['pwdLastSet', 'objectSid']) pwdLastSet = None if res[0][1].has_key('pwdLastSet'): pwdLastSet = long(res[0][1]['pwdLastSet'][0]) objectSid = univention.s4connector.s4.decode_sid(res[0][1]['objectSid'][0]) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdLastSet from S4 : %s" % pwdLastSet) # rid = None # if res[0][1].has_key('objectSid'): # rid = str(univention.s4connector.s4.decode_sid(res[0][1]['objectSid'][0]).split('-')[-1]) pwd_set = False res = s4connector.lo_s4.lo.search_s( s4connector.lo_s4.base, ldap.SCOPE_SUBTREE, compatible_modstring('(objectSid=%s)' % objectSid), [ 'unicodePwd', 'userPrincipalName', 'supplementalCredentials', 'msDS-KeyVersionNumber', 'dBCSPwd' ]) unicodePwd_attr = res[0][1].get('unicodePwd', [None])[0] dBCSPwd_attr = res[0][1].get('dBCSPwd', [None])[0] userPrincipalName_attr = res[0][1].get('userPrincipalName', [None])[0] supplementalCredentials = res[0][1].get('supplementalCredentials', [None])[0] msDS_KeyVersionNumber = res[0][1].get('msDS-KeyVersionNumber', [0])[0] # ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Password-Hash from S4: %s" % unicodePwd_attr) s4NThash = None if unicodePwd_attr: s4NThash = binascii.b2a_hex(unicodePwd_attr).upper() else: ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get NT Password-Hash from S4") s4LMhash = None if dBCSPwd_attr: s4LMhash = binascii.b2a_hex(dBCSPwd_attr).upper() else: ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get LM Password-Hash from S4") modlist = [] if krb5Principal != userPrincipalName_attr: if krb5Principal: if not userPrincipalName_attr: ## new and not old modlist.append( (ldap.MOD_ADD, 'userPrincipalName', krb5Principal)) else: ## new and old differ if krb5Principal.lower() != userPrincipalName_attr.lower(): ud.debug( ud.LDAP, ud.WARN, "password_sync_ucs_to_s4: userPrincipalName != krb5Principal: '%s' != '%s'" % (userPrincipalName_attr, krb5Principal)) modlist.append( (ldap.MOD_REPLACE, 'userPrincipalName', krb5Principal)) else: if userPrincipalName_attr: ## old and not new modlist.append((ldap.MOD_DELETE, 'userPrincipalName', userPrincipalName_attr)) if not ucsNThash == s4NThash: ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: NT Hash S4: %s NT Hash UCS: %s" % (s4NThash, ucsNThash)) ## Now if ucsNThash is empty there should at least some timestamp in UCS, ## otherwise it's probably not a good idea to remove the unicodePwd. ## Usecase: LDB module on ucs_3.0-0-ucsschool slaves creates XP computers/windows in UDM without password if ucsNThash or sambaPwdLastSet: pwd_set = True if unicodePwd_attr: modlist.append( (ldap.MOD_DELETE, 'unicodePwd', unicodePwd_attr)) if ucsNThash: unicodePwd_new = binascii.a2b_hex(ucsNThash) modlist.append((ldap.MOD_ADD, 'unicodePwd', unicodePwd_new)) if not ucsLMhash == s4LMhash: ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: LM Hash S4: %s LM Hash UCS: %s" % (s4LMhash, ucsLMhash)) pwd_set = True if dBCSPwd_attr: modlist.append((ldap.MOD_DELETE, 'dBCSPwd', dBCSPwd_attr)) if ucsLMhash: dBCSPwd_new = binascii.a2b_hex(ucsLMhash) modlist.append((ldap.MOD_ADD, 'dBCSPwd', dBCSPwd_new)) if pwd_set or not supplementalCredentials: if krb5Principal: ## encoding of Samba4 supplementalCredentials if supplementalCredentials: modlist.append((ldap.MOD_DELETE, 'supplementalCredentials', supplementalCredentials)) if krb5Key: supplementalCredentials_new = calculate_supplementalCredentials( krb5Key, supplementalCredentials) if supplementalCredentials_new: modlist.append((ldap.MOD_ADD, 'supplementalCredentials', supplementalCredentials_new)) else: ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: no supplementalCredentials_new" ) #if supplementalCredentials: # modlist.append((ldap.MOD_REPLACE, 'msDS-KeyVersionNumber', krb5KeyVersionNumber)) #else: # modlist.append((ldap.MOD_ADD, 'msDS-KeyVersionNumber', krb5KeyVersionNumber)) if sambaPwdMustChange >= 0 and sambaPwdMustChange < time.time(): # password expired, must be changed on next login ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: samba pwd expired, set newpwdLastSet to 0" ) newpwdlastset = "0" else: if sambaPwdLastSet == None: sambaPwdLastSet = int(time.time()) newpwdlastset = str( univention.s4connector.s4.samba2s4_time(sambaPwdLastSet)) elif sambaPwdLastSet in [0, 1]: newpwdlastset = "0" else: newpwdlastset = str( univention.s4connector.s4.samba2s4_time(sambaPwdLastSet)) ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdlastset in modlist: %s" % newpwdlastset) modlist.append((ldap.MOD_REPLACE, 'pwdlastset', newpwdlastset)) else: ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: No password change to sync to S4 ") # check pwdLastSet if sambaPwdLastSet != None: newpwdlastset = str( univention.s4connector.s4.samba2s4_time(sambaPwdLastSet)) ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaPwdLastSet: %d" % sambaPwdLastSet) ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: newpwdlastset : %s" % newpwdlastset) ud.debug( ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdLastSet (AD): %s" % pwdLastSet) if sambaPwdLastSet in [0, 1]: modlist.append((ldap.MOD_REPLACE, 'pwdlastset', "0")) elif pwdLastSet != newpwdlastset: modlist.append((ldap.MOD_REPLACE, 'pwdlastset', newpwdlastset)) ## TODO: Password History ctrl_bypass_password_hash = LDAPControl('1.3.6.1.4.1.7165.4.3.12', criticality=0) ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: modlist: %s" % modlist) if modlist: s4connector.lo_s4.lo.modify_ext_s( compatible_modstring(object['dn']), modlist, serverctrls=[ctrl_bypass_password_hash])