def __init__(self, filename): _d = ud.function('S4Cache.%s' % func_name()) # noqa: F841 self.filename = filename self._dbcon = sqlite3.connect(self.filename) self.s4cache = {} self.__create_tables()
def s4_srv_record_create(s4connector, object): _d=ud.function('s4_srv_record_create') dnsRecords=[] zoneDn, zoneName=__create_default_s4_zone_dn(s4connector, object) relativeDomainName=object['attributes'].get('relativeDomainName') relativeDomainName=univention.s4connector.s4.compatible_list(relativeDomainName) # ucr set connector/s4/mapping/dns/srv_record/_ldap._tcp.test.local/location='100 0 389 foobar.test.local.' # ucr set connector/s4/mapping/dns/srv_record/_ldap._tcp.test.local/location='100 0 389 foobar.test.local. 100 0 389 foobar2.test.local.' ucr_locations = s4connector.configRegistry.get('connector/s4/mapping/dns/srv_record/%s.%s/location' % (relativeDomainName[0].lower(),zoneName[0].lower())) ud.debug(ud.LDAP, ud.INFO, 's4_srv_record_create: ucr_locations for connector/s4/mapping/dns/srv_record/%s.%s/location: %s' % (relativeDomainName[0].lower(),zoneName[0].lower(),ucr_locations)) if ucr_locations: if ucr_locations.lower() == 'ignore': return # Convert ucr variable priority=None; weight=None; port=None; target=None for v in ucr_locations.split(' '): # Check explicit for None, because the int values may be 0 if priority == None: priority=int(v) elif weight == None: weight=int(v) elif port == None: port=int(v) elif not target: target=__remove_dot(v) if priority != None and weight != None and port != None and target: ud.debug(ud.LDAP, ud.INFO, 'priority=%d weight=%d port=%d target=%s' % (priority,weight,port,target)) s=SRVRecord(target, port, priority, weight) dnsRecords.append(ndr_pack(s)) priority=None; weight=None; port=None; target=None else: __pack_sRVrecord(object, dnsRecords) dnsNodeDn=s4_dns_node_base_create(s4connector, object, dnsRecords)
def get_entry(self, guid): _d = ud.function('ADCache.%s' % func_name()) entry = {} guid_id = self._get_guid_id(guid) if not guid_id: return None # The SQLite python module should do the escaping, that's # the reason why we use the tuple ? syntax. # I've choosen the str call because I want to make sure # that we use the same SQL value as before switching # to the tuple ? syntax sql_commands = [("SELECT ATTRIBUTES.attribute,data.value from data \ inner join ATTRIBUTES ON data.attribute_id=attributes.id where guid_id = ?;", (str(guid_id), ))] rows = self.__execute_sql_commands(sql_commands, fetch_result=True) if not rows: return None for line in rows: if not entry.get(line[0]): entry[str(line[0])] = [] entry[line[0]].append(b64decode(line[1])) return entry
def ucs_srv_record_delete(s4connector, object): _d = ud.function('ucs_srv_record_delete') ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_delete: object: %s' % object) zoneName, relativeDomainName = __split_s4_dn(object['dn']) searchResult = s4connector.lo.search( filter='(&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName), unique=1) if len(searchResult) > 0: superordinate = s4connector_get_superordinate('dns/srv_record', s4connector.lo, searchResult[0][0]) newRecord = univention.admin.handlers.dns.srv_record.object( None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=superordinate, attributes=[], update_zone=False) newRecord.open() newRecord.delete() else: ud.debug( ud.LDAP, ud.INFO, 'ucs_srv_record_delete: Object was not found, filter was: ((&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName)) return True
def to_mailAlternativeAddress(s4connector, key, object): _d = ud.function('proxyAddesses.to_mailAlternativeAddress') # noqa: F841 new_ucs_values = [] for value in object['attributes'].get('proxyAddresses', []): if value.startswith('smtp:'): new_ucs_values.append(value[5:]) return new_ucs_values
def password_sync_kinit(connector, key, ucs_object): _d = ud.function('ldap.ad.password_sync_kinit') # noqa: F841 connector._object_mapping(key, ucs_object, 'ucs') attr = { 'userPassword': '******', 'sambaNTPassword': '******', 'sambaLMPassword': '******' } ucs_result = connector.lo.search(base=ucs_object['dn'], attr=attr.keys()) modlist = [] for attribute in attr.keys(): expected_value = attr[attribute] if attribute in ucs_result[0][1]: userPassword = ucs_result[0][1][attribute][0] if userPassword != expected_value: modlist.append((ldap.MOD_REPLACE, attribute, expected_value)) if modlist: connector.lo.lo.modify_s( univention.connector.ad.compatible_modstring(ucs_object['dn']), modlist)
def s4_dns_node_base_create(s4connector, object, dnsRecords): _d = ud.function('s4_dns_node_base_create') zoneDn, zoneName = __create_default_s4_zone_dn(s4connector, object) relativeDomainNames = object['attributes'].get('relativeDomainName') relativeDomainNames = univention.s4connector.s4.compatible_list( relativeDomainNames) old_dnsRecords = [] # Create dnsNode object dnsNodeDn = 'DC=%s,%s' % (relativeDomainNames[0], zoneDn) try: searchResult = s4connector.lo_s4.lo.search_s(dnsNodeDn, ldap.SCOPE_BASE, '(objectClass=*)') if searchResult and searchResult[0][1]: old_dnsRecords = searchResult[0][1].get('dnsRecord') except ldap.NO_SUCH_OBJECT: __create_s4_dns_node(s4connector, dnsNodeDn, relativeDomainNames, dnsRecords) else: res = s4connector.lo_s4.modify( dnsNodeDn, [('dnsRecord', old_dnsRecords, dnsRecords)]) return dnsNodeDn
def __init__(self, filename): _d = ud.function('LockingDB.%s' % func_name()) self.filename = filename self._dbcon = sqlite3.connect(self.filename) self.s4cache = {} self.__create_tables()
def ucs_zone_delete(s4connector, object, dns_type): _d = ud.function('ucs_zone_delete') zoneName, relativeDomainName = __split_s4_dn(object['dn']) if relativeDomainName == '@': searchResult = s4connector.lo.search( filter='(&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName), unique=1) if len(searchResult) > 0: if dns_type == 'forward_zone': zone = univention.admin.handlers.dns.forward_zone.object( None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=None, attributes=[], update_zone=False) elif dns_type == 'reverse_zone': zone = univention.admin.handlers.dns.reverse_zone.object( None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=None, attributes=[], update_zone=False) zone.open() zone.delete()
def set_password_in_ad(connector, samaccountname, pwd): _d=ud.function('ldap.ad.set_password_in_ad') compatible_modstring = univention.connector.ad.compatible_modstring a = array.array('c') _append ( a, univention.connector.ad.explode_unicode_dn(connector.lo_ad.binddn,1)[0] ) _append ( a, connector.lo_ad.bindpw ) a.append ( 'S' ) # The copypwd utility on the windows side needs the # username as iso8859 string. See Bug #8516 # _append ( a, compatible_modstring(samaccountname) ) _append ( a, samaccountname.encode(connector.baseConfig.get('connector/password/service/encoding', 'iso8859-15'))) _append ( a, str(pwd) ) package = array.array('c') _append_array( package, a) # Create Socket and send package s = socket.socket( socket.AF_INET, socket.SOCK_STREAM ); s.connect ( (connector.lo_ad.host, 6670) ) ssl=ssl_init(s.fileno()) M2Crypto.__m2crypto.ssl_write(ssl, package) return M2Crypto.__m2crypto.ssl_read(ssl, 8192)
def ucs_cname_create(s4connector, object): _d=ud.function('ucs_cname_create') ud.debug(ud.LDAP, ud.INFO, 'ucs_cname_create: object: %s' % object) zoneName, relativeDomainName=__split_s4_dn(object['dn']) # unpack the host record c=__unpack_cName(object) # Does a host record for this zone already exist? searchResult=s4connector.lo.search(filter='(&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName), unique=1) if len(searchResult) > 0: superordinate=s4connector_get_superordinate('dns/alias', s4connector.lo, searchResult[0][0]) newRecord= univention.admin.handlers.dns.alias.object(None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=superordinate, attributes=[], update_zone=False) newRecord.open() if set(newRecord['cname']) != set(c): newRecord['cname']=c[0] newRecord.modify() else: ud.debug(ud.LDAP, ud.INFO, 'ucs_cname_create: do not modify host record') else: zoneDN='zoneName=%s,%s' % (zoneName, s4connector.property['dns'].ucs_default_dn) superordinate=s4connector_get_superordinate('dns/alias', s4connector.lo, zoneDN) ud.debug(ud.LDAP, ud.INFO, 'ucs_cname_create: superordinate: %s' % superordinate) position=univention.admin.uldap.position(zoneDN) newRecord= univention.admin.handlers.dns.alias.object(None, s4connector.lo, position, dn=None, superordinate=superordinate, attributes=[], update_zone=False) newRecord.open() newRecord['name']=relativeDomainName newRecord['cname']=c[0] newRecord.create()
def _create_attr(self, attr): _d = ud.function('ADCache.%s' % func_name()) sql_commands = [("INSERT INTO ATTRIBUTES(attribute) VALUES(?);", (str(attr), ))] self.__execute_sql_commands(sql_commands, fetch_result=False)
def s4_cname_create(s4connector, object): _d = ud.function('s4_cname_create') dnsRecords = [] __pack_cName(object, dnsRecords) dnsNodeDn = s4_dns_node_base_create(s4connector, object, dnsRecords)
def ucs2ad_givenName(connector, key, object): _d = ud.function("mapping.ucs2ad_givenName") if object.has_key("firstname") and object.has_key("lastname"): return "%s %s" % (object["firstname"], object["lastname"]) elif object.has_key("firstname"): return object["firstname"] elif object.has_key("lastname"): return object["lastname"]
def s4_cname_create(s4connector, object): _d=ud.function('s4_cname_create') dnsRecords=[] __pack_cName(object, dnsRecords) dnsNodeDn=s4_dns_node_base_create(s4connector, object, dnsRecords)
def _get_attr_id_and_create_if_not_exists(self, attr): _d = ud.function('S4Cache.%s' % func_name()) attr_id = self._get_attr_id(attr) if not attr_id: self._create_attr(attr) attr_id = self._get_attr_id(attr) return attr_id
def ucs2s4_givenName(s4connector, key, object): _d=ud.function('mapping.ucs2s4_givenName') if object.has_key('firstname') and object.has_key('lastname'): return '%s %s' % (object['firstname'], object['lastname']) elif object.has_key('firstname'): return object['firstname'] elif object.has_key('lastname'): return object['lastname']
def ucs2ad_givenName(connector, key, object): _d = ud.function('mapping.ucs2ad_givenName') # noqa: F841 if 'firstname' in object and 'lastname' in object: return '%s %s' % (object['firstname'], object['lastname']) elif 'firstname' in object: return object['firstname'] elif 'lastname' in object: return object['lastname']
def add_entry(self, guid, entry): _d = ud.function('S4Cache.%s' % func_name()) if not self._guid_exists(guid): self._add_entry(guid, entry) else: self._update_entry(guid, entry) self.s4cache[guid] = entry
def ucs2s4_givenName(s4connector, key, object): _d = ud.function('mapping.ucs2s4_givenName') if object.has_key('firstname') and object.has_key('lastname'): return '%s %s' % (object['firstname'], object['lastname']) elif object.has_key('firstname'): return object['firstname'] elif object.has_key('lastname'): return object['lastname']
def ucs_host_record_create(s4connector, object): _d = ud.function('ucs_host_record_create') ud.debug(ud.LDAP, ud.INFO, 'ucs_host_record_create: object: %s' % object) zoneName, relativeDomainName = __split_s4_dn(object['dn']) # unpack the host record a = __unpack_aRecord(object) # Does a host record for this zone already exist? searchResult = s4connector.lo.search( filter='(&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName), unique=1) if len(searchResult) > 0: superordinate = s4connector_get_superordinate('dns/host_record', s4connector.lo, searchResult[0][0]) newRecord = univention.admin.handlers.dns.host_record.object( None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=superordinate, attributes=[], update_zone=False) newRecord.open() if set(newRecord['a']) != set(a): newRecord['a'] = a newRecord.modify() else: ud.debug(ud.LDAP, ud.INFO, 'ucs_host_record_create: do not modify host record') else: zoneDN = 'zoneName=%s,%s' % ( zoneName, s4connector.property['dns'].ucs_default_dn) ud.debug(ud.LDAP, ud.INFO, 'ucs_host_record_create: zoneDN: %s' % zoneDN) superordinate = s4connector_get_superordinate('dns/host_record', s4connector.lo, zoneDN) ud.debug(ud.LDAP, ud.INFO, 'ucs_host_record_create: superordinate: %s' % superordinate) position = univention.admin.uldap.position(zoneDN) newRecord = univention.admin.handlers.dns.host_record.object( None, s4connector.lo, position, dn=None, superordinate=superordinate, attributes=[], update_zone=False) newRecord.open() newRecord['name'] = relativeDomainName newRecord['a'] = a newRecord.create()
def con2ucs (s4connector, key, object): _d=ud.function('dns: con2ucs') ud.debug(ud.LDAP, ud.INFO, 'dc con2ucs: Object (%s): %s' % (object['dn'], object)) # Search sambaDomainname object via sambaSID sambadomainnameObject = univention.admin.handlers.settings.sambadomain.lookup(None, s4connector.lo, 'sambaSID=%s' % object['attributes'].get('objectSid', [])[0]) if len(sambadomainnameObject) > 1: ud.debug(ud.LDAP, ud.WARN, 'dc con2ucs: Found more than one sambaDomainname object with sambaSID %s' % object['attributes'].get('objectSid', [])[0]) elif len(sambadomainnameObject) == 1: # Use the first sambaDomain sambadomainnameObject = sambadomainnameObject[0] # Do we modify this UCS object modify = False sync_times = [ ('maxPasswordAge', 'maxPwdAge'), ('minPasswordAge', 'minPwdAge'), ('lockoutDuration', 'lockoutDuration') ] for (ucs_attr, s4_attr) in sync_times: ucs_time = _unixTimeInverval2seconds(sambadomainnameObject.get(ucs_attr, 0)) s4_time = _nano2s(long(object['attributes'].get(s4_attr, [0])[0]) * -1) if ucs_time != s4_time: sambadomainnameObject[ucs_attr] = [str(s4_time), 'seconds'] modify = True sync_integers = [ ('passwordHistory', 'pwdHistoryLength'), ('passwordLength', 'minPwdLength') ] for (ucs_attr, s4_attr) in sync_integers: ucs_val = sambadomainnameObject.get(ucs_attr, 0) s4_val = object['attributes'].get(s4_attr, [None])[0] if ucs_val != s4_val: sambadomainnameObject[ucs_attr] = s4_val modify = True if modify: sambadomainnameObject.modify() if s4connector.configRegistry.is_true('connector/s4/mapping/gpo', True): # Search DC object via ldap search dn,attr = s4connector.lo.search('objectClass=*', scope='base')[0] ml = [] ucs_val = attr.get('msGPOLink') s4_val = object['attributes'].get('gPLink') if ucs_val != s4_val: if not 'msGPO' in attr.get('objectClass', []): ml.append(('objectClass', '', 'msGPO')) ml.append(('msGPOLink', ucs_val, s4_val)) if ml: s4connector.lo.modify(dn, ml) return True
def unlock_s4(self, guid): _d = ud.function('LockingDB.%s' % func_name()) if not guid: return None sql_commands = [("DELETE FROM S4_LOCK WHERE guid = ?;", (str(guid), ))] self.__execute_sql_commands(sql_commands, fetch_result=False)
def identify(dn, attr, canonical=0): _d = ud.function('dns: identify') return univention.admin.handlers.dns.forward_zone.identify(dn, attr) or\ univention.admin.handlers.dns.reverse_zone.identify(dn, attr) or\ univention.admin.handlers.dns.alias.identify(dn, attr) or\ univention.admin.handlers.dns.host_record.identify(dn, attr) or\ univention.admin.handlers.dns.srv_record.identify(dn, attr) or\ univention.admin.handlers.dns.ptr_record.identify(dn, attr)
def identify(dn, attr, canonical=0): _d=ud.function('dns: identify') return univention.admin.handlers.dns.forward_zone.identify(dn, attr) or\ univention.admin.handlers.dns.reverse_zone.identify(dn, attr) or\ univention.admin.handlers.dns.alias.identify(dn, attr) or\ univention.admin.handlers.dns.host_record.identify(dn, attr) or\ univention.admin.handlers.dns.srv_record.identify(dn, attr) or\ univention.admin.handlers.dns.ptr_record.identify(dn, attr)
def s4_zone_create(s4connector, object): _d=ud.function('s4_zone_create') zoneDn, zoneName=__create_default_s4_zone_dn(s4connector, object) # Create the forward zone in S4 if it does not exist try: searchResult=s4connector.lo_s4.lo.search_s(zoneDn, ldap.SCOPE_BASE, '(objectClass=*)',['dn']) except ldap.NO_SUCH_OBJECT: __create_s4_forward_zone(s4connector, zoneDn, zoneName) # Create @ object zoneDnAt='DC=@,%s' % zoneDn old_dnsRecords=[] try: searchResult=s4connector.lo_s4.lo.search_s(zoneDnAt, ldap.SCOPE_BASE, '(objectClass=*)') if searchResult and searchResult[0][1]: old_dnsRecords=searchResult[0][1].get('dnsRecord') except ldap.NO_SUCH_OBJECT: __create_s4_forward_zone_at(s4connector, zoneDnAt, zoneName) dnsRecords=[] __pack_nsRecord(object, dnsRecords) __pack_soaRecord(object, dnsRecords) # The IP address of the DNS forward zone will be used to determine the # sysvol share. On a selective replicated DC only a short list of DCs # should be returned aRecords = s4connector.configRegistry.get('connector/s4/mapping/dns/forward_zone/%s/static/ipv4' % zoneName[0].lower()) aAAARecords = s4connector.configRegistry.get('connector/s4/mapping/dns/forward_zone/%s/static/ipv6' % zoneName[0].lower()) if aRecords or aAAARecords: #IPv4 if aRecords: for a in aRecords.split(' '): a=univention.s4connector.s4.compatible_modstring(a) a_record=ARecord(a) dnsRecords.append(ndr_pack(a_record)) #IPv6 if aAAARecords: for a in aAAARecords.split(' '): a=univention.s4connector.s4.compatible_modstring(a) a_record=AAAARecord(a) dnsRecords.append(ndr_pack(a_record)) else: __pack_aRecord(object, dnsRecords) __pack_mxRecord(object, dnsRecords) s4connector.lo_s4.modify(zoneDnAt, [('dnsRecord', old_dnsRecords, dnsRecords)]) return True
def s4_ptr_record_create(s4connector, object): _d=ud.function('s4_ptr_record_create') dnsRecords=[] __pack_ptrRecord(object, dnsRecords) dnsNodeDn=s4_dns_node_base_create(s4connector, object, dnsRecords) return True
def lock_s4(self, guid): _d = ud.function('LockingDB.%s' % func_name()) if not guid: return None sql_commands = [("INSERT INTO S4_LOCK(guid) VALUES(?);", (str(guid), )) ] self.__execute_sql_commands(sql_commands, fetch_result=False)
def s4_ptr_record_create(s4connector, object): _d = ud.function('s4_ptr_record_create') dnsRecords = [] __pack_ptrRecord(object, dnsRecords) dnsNodeDn = s4_dns_node_base_create(s4connector, object, dnsRecords) return True
def unlock_ucs(self, uuid): _d = ud.function('LockingDB.%s' % func_name()) # noqa: F841 if not uuid: return None sql_commands = [("DELETE FROM UCS_LOCK WHERE uuid = ?;", (str(uuid), )) ] self.__execute_sql_commands(sql_commands, fetch_result=False)
def ucs_srv_record_create(s4connector, object): _d=ud.function('ucs_srv_record_create') ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_create: object: %s' % object) zoneName, relativeDomainName=__split_s4_dn(object['dn']) # unpack the host record srv=__unpack_sRVrecord(object) # ucr set connector/s4/mapping/dns/srv_record/_ldap._tcp.test.local/location='100 0 389 foobar.test.local. 100 0 389 foobar2.test.local.' ucr_locations = s4connector.configRegistry.get('connector/s4/mapping/dns/srv_record/%s.%s/location' % (relativeDomainName.lower(),zoneName.lower())) ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_create: ucr_locations for connector/s4/mapping/dns/srv_record/%s.%s/location: %s' % (relativeDomainName.lower(),zoneName.lower(),ucr_locations)) if ucr_locations and ucr_locations.lower() == 'ignore': return # Does a host record for this zone already exist? searchResult=s4connector.lo.search(filter='(&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName), unique=1) if len(searchResult) > 0: superordinate=s4connector_get_superordinate('dns/srv_record', s4connector.lo, searchResult[0][0]) newRecord= univention.admin.handlers.dns.srv_record.object(None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=superordinate, attributes=[], update_zone=False) newRecord.open() if ucr_locations: ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_create: do not write SRV record back from S4 to UCS because location of SRV record have been overwritten by UCR') else: ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_create: location: %s' % newRecord['location']) ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_create: srv : %s' % srv) srv.sort() newRecord['location'].sort() if srv != newRecord['location']: newRecord['location']=srv newRecord.modify() else: ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_create: do not modify host record') else: zoneDN='zoneName=%s,%s' % (zoneName, s4connector.property['dns'].ucs_default_dn) superordinate=s4connector_get_superordinate('dns/srv_record', s4connector.lo, zoneDN) ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_create: superordinate: %s' % superordinate) position=univention.admin.uldap.position(zoneDN) newRecord= univention.admin.handlers.dns.srv_record.object(None, s4connector.lo, position, dn=None, superordinate=superordinate, attributes=[], update_zone=False) newRecord.open() # Make syntax UDM compatible service=string.join(relativeDomainName.split('.')[:-1], '.') if service.startswith('_'): service=service[1:] protocol=relativeDomainName.split('.')[-1] if protocol.startswith('_'): protocol=protocol[1:] ud.debug(ud.LDAP, ud.INFO, 'SRV create: service="%s" protocol="%s"' % (service, protocol)) newRecord['name']=[service, protocol] newRecord['location']=srv newRecord.create()
def _get_guid_id(self, guid): _d = ud.function('S4Cache.%s' % func_name()) sql_commands = [("SELECT id FROM GUIDS WHERE guid=?;", (str(guid), ))] rows = self.__execute_sql_commands(sql_commands, fetch_result=True) if rows: return rows[0][0] return None
def __create_tables(self): _d = ud.function('LockingDB.%s' % func_name()) sql_commands = [ "CREATE TABLE IF NOT EXISTS S4_LOCK (id INTEGER PRIMARY KEY, guid TEXT);", "CREATE TABLE IF NOT EXISTS UCS_LOCK (id INTEGER PRIMARY KEY, uuid TEXT);", "CREATE INDEX IF NOT EXISTS s4_lock_guid ON s4_lock(guid);", "CREATE INDEX IF NOT EXISTS ucs_lock_uuid ON ucs_lock(uuid);", ] self.__execute_sql_commands(sql_commands, fetch_result=False)
def diff_entry(self, old_entry, new_entry): _d = ud.function('S4Cache.%s' % func_name()) result = {'added': None, 'removed': None, 'changed': None} diff = EntryDiff(old_entry, new_entry) result['added'] = diff.added() result['removed'] = diff.removed() result['changed'] = diff.changed() return result
def get_password_from_ad(connector, user_dn): _d = ud.function('ldap.ad.get_password_from_ad') ud.debug(ud.LDAP, ud.INFO, "get_password_from_ad: Read password from AD: %s" % user_dn) nt_hash = None if not connector.drs: connector.open_drs_connection() req8 = drsuapi.DsGetNCChangesRequest8() req8.destination_dsa_guid = misc.GUID(connector.computer_guid) req8.source_dsa_invocation_id = misc.GUID(connector.computer_guid) req8.naming_context = drsuapi.DsReplicaObjectIdentifier() req8.naming_context.dn = user_dn req8.replica_flags = 0 req8.max_object_count = 402 req8.max_ndr_size = 402116 req8.extended_op = drsuapi.DRSUAPI_EXOP_REPL_SECRET req8.fsmo_info = 0 while True: (level, ctr) = connector.drs.DsGetNCChanges(connector.drsuapi_handle, 8, req8) rid = None unicode_blob = None if ctr.first_object is None: break for i in ctr.first_object.object.attribute_ctr.attributes: if str(i.attid) == "589970": # DRSUAPI_ATTID_objectSid if i.value_ctr.values: for j in i.value_ctr.values: sid = ndr_unpack(security.dom_sid, j.blob) _tmp, rid = sid.split() if str(i.attid) == "589914": # DRSUAPI_ATTID_unicodePwd if i.value_ctr.values: for j in i.value_ctr.values: unicode_blob = j.blob ud.debug( ud.LDAP, ud.INFO, "get_password_from_ad: Found unicodePwd blob") if rid and unicode_blob: nt_hash = decrypt(connector.drs.user_session_key, unicode_blob, rid).upper() if ctr.more_data == 0: break ud.debug(ud.LDAP, ud.INFO, "get_password_from_ad: AD Hash: %s" % nt_hash) return nt_hash
def _get_attr_id(self, attr): _d = ud.function('S4Cache.%s' % func_name()) sql_commands = [("SELECT id FROM ATTRIBUTES WHERE attribute=?;", (str(attr), ))] rows = self.__execute_sql_commands(sql_commands, fetch_result=True) if rows: return rows[0][0] return None
def remove_entry(self, guid): _d = ud.function('S4Cache.%s' % func_name()) guid_id = self._get_guid_id(guid) if not guid_id: return None sql_commands = [("DELETE FROM data WHERE guid_id=?;", (str(guid_id), )), ("DELETE FROM guids WHERE id=?;", (str(guid_id), ))] self.__execute_sql_commands(sql_commands, fetch_result=False)
def __create_tables(self): _d = ud.function('S4Cache.%s' % func_name()) sql_commands = [ "CREATE TABLE IF NOT EXISTS GUIDS (id INTEGER PRIMARY KEY, guid TEXT);", "CREATE TABLE IF NOT EXISTS ATTRIBUTES (id INTEGER PRIMARY KEY, attribute TEXT);", "CREATE TABLE IF NOT EXISTS DATA (id INTEGER PRIMARY KEY, guid_id INTEGER, attribute_id INTEGER, value TEXT);", "CREATE INDEX IF NOT EXISTS data_foreign_keys ON data(guid_id, attribute_id);", "CREATE INDEX IF NOT EXISTS attributes_attribute ON attributes(attribute);", "CREATE INDEX IF NOT EXISTS guids_guid ON guids(guid);", ] self.__execute_sql_commands(sql_commands, fetch_result=False)
def lockout_sync_s4_to_ucs(s4connector, key, ucs_object): """ Sync account locking *state* from Samba/AD to OpenLDAP: sync Samba/AD (lockoutTime != 0) -> OpenLDAP sambaAcctFlags ("L") and Samba/AD badPasswordTime -> OpenLDAP sambaBadPasswordTime """ function_name = 'lockout_sync_s4_to_ucs' _d = ud.function('ldap.s4.%s' % function_name) ud.debug(ud.LDAP, ud.INFO, "%s called" % function_name) if ucs_object['modtype'] not in ('modify', 'add'): return modlist = [] try: ucs_object_attributes = s4connector.lo.get(ucs_object['dn'], ['sambaAcctFlags', 'sambaBadPasswordTime'], required=True) except ldap.NO_SUCH_OBJECT: ud.debug(ud.LDAP, ud.WARN, "%s: The UCS object (%s) was not found. The object was removed." % (function_name, ucs_object['dn'])) return sambaAcctFlags = ucs_object_attributes.get('sambaAcctFlags', [''])[0] sambaBadPasswordTime = ucs_object_attributes.get('sambaBadPasswordTime', ["0"])[0] lockoutTime = ucs_object['attributes'].get('lockoutTime', ['0'])[0] if lockoutTime != "0": if "L" not in sambaAcctFlags: acctFlags = univention.admin.samba.acctFlags(sambaAcctFlags) new_sambaAcctFlags = acctFlags.set('L') ud.debug(ud.LDAP, ud.PROCESS, "%s: Marking Samba account as locked in OpenLDAP" % (function_name,)) modlist.append(('sambaAcctFlags', sambaAcctFlags, new_sambaAcctFlags)) badPasswordTime = ucs_object['attributes'].get('badPasswordTime', ["0"])[0] if badPasswordTime != sambaBadPasswordTime: ud.debug(ud.LDAP, ud.PROCESS, "%s: Copying badPasswordTime from S4: %s" % (function_name, badPasswordTime)) if sambaBadPasswordTime: ud.debug(ud.LDAP, ud.INFO, "%s: Old sambaBadPasswordTime: %s" % (function_name, sambaBadPasswordTime)) modlist.append(('sambaBadPasswordTime', sambaBadPasswordTime, badPasswordTime)) else: if "L" in sambaAcctFlags: acctFlags = univention.admin.samba.acctFlags(sambaAcctFlags) new_sambaAcctFlags = acctFlags.unset('L') ud.debug(ud.LDAP, ud.PROCESS, "%s: Marking Samba account as unlocked in OpenLDAP" % (function_name,)) modlist.append(('sambaAcctFlags', sambaAcctFlags, new_sambaAcctFlags)) if sambaBadPasswordTime and sambaBadPasswordTime != "0": ud.debug(ud.LDAP, ud.PROCESS, "%s: Unsetting sambaBadPasswordTime: %s" % (function_name, sambaBadPasswordTime)) modlist.append(('sambaBadPasswordTime', sambaBadPasswordTime, "0")) if modlist: ud.debug(ud.LDAP, ud.ALL, "%s: modlist: %s" % (function_name, modlist)) s4connector.lo.lo.modify(ucs_object['dn'], modlist)
def ucs2con(s4connector, key, object): _d = ud.function('dns: ucs2con') dns_type = _identify_dns_ucs_object(s4connector, object) if not dns_type: # unknown object -> ignore ud.debug(ud.LDAP, ud.INFO, 'dns ucs2con: Ignore unkown dns object: %s' % object['dn']) return True ud.debug( ud.LDAP, ud.INFO, 'dns ucs2con: Object (%s) is from type %s' % (object['dn'], dns_type)) if dns_type == 'forward_zone' or dns_type == 'reverse_zone': if object['modtype'] in ['add', 'modify']: s4_zone_create(s4connector, object) elif object['modtype'] in ['delete']: s4_zone_delete(s4connector, object) # ignore move elif dns_type == 'host_record': if object['modtype'] in ['add', 'modify']: s4_host_record_create(s4connector, object) elif object['modtype'] in ['delete']: s4_dns_node_base_delete(s4connector, object) # ignore move elif dns_type == 'alias': if object['modtype'] in ['add', 'modify']: s4_cname_create(s4connector, object) elif object['modtype'] in ['delete']: s4_dns_node_base_delete(s4connector, object) # ignore move elif dns_type == 'srv_record': if object['modtype'] in ['add', 'modify']: s4_srv_record_create(s4connector, object) elif object['modtype'] in ['delete']: s4_dns_node_base_delete(s4connector, object) # ignore move elif dns_type == 'ptr_record': if object['modtype'] in ['add', 'modify']: s4_ptr_record_create(s4connector, object) elif object['modtype'] in ['delete']: s4_dns_node_base_delete(s4connector, object) # ignore move return True
def ucs_zone_delete(s4connector, object, dns_type): _d=ud.function('ucs_zone_delete') zoneName, relativeDomainName=__split_s4_dn(object['dn']) if relativeDomainName == '@': searchResult=s4connector.lo.search(filter='(&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName), unique=1) if len(searchResult) > 0: if dns_type == 'forward_zone': zone= univention.admin.handlers.dns.forward_zone.object(None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=None, attributes=[], update_zone=False) elif dns_type == 'reverse_zone': zone= univention.admin.handlers.dns.reverse_zone.object(None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=None, attributes=[], update_zone=False) zone.open() zone.delete()
def to_proxyAddresses(s4connector, key, object): _d = ud.function('proxyAddesses.ucs_to_ad_mapping') new_con_values = [] mailPrimaryAddress = object['attributes'].get('mailPrimaryAddress', [None])[0] if mailPrimaryAddress: new_con_value = 'SMTP:' + mailPrimaryAddress new_con_values.append(new_con_value) for v in object['attributes'].get('mailAlternativeAddress', []): if v == mailPrimaryAddress: continue new_con_value = 'smtp:' + v new_con_values.append(new_con_value) return new_con_values
def s4_dns_node_base_delete(s4connector, object): _d=ud.function('s4_dns_node_base_delete') zoneDn, zoneName=__create_default_s4_zone_dn(s4connector, object) relativeDomainNames=object['attributes'].get('relativeDomainName') relativeDomainNames=univention.s4connector.s4.compatible_list(relativeDomainNames) dnsNodeDn='DC=%s,%s' % (relativeDomainNames[0],zoneDn) try: res=s4connector.lo_s4.lo.delete_s(dnsNodeDn) except ldap.NO_SUCH_OBJECT: pass #the object was already removed return True
def ucs2con (s4connector, key, object): _d=ud.function('dns: ucs2con') dns_type=_identify_dns_ucs_object(s4connector, object) if not dns_type: # unknown object -> ignore ud.debug(ud.LDAP, ud.INFO, 'dns ucs2con: Ignore unkown dns object: %s' % object['dn']) return True ud.debug(ud.LDAP, ud.INFO, 'dns ucs2con: Object (%s) is from type %s' % (object['dn'], dns_type)) if dns_type == 'forward_zone' or dns_type == 'reverse_zone': if object['modtype'] in ['add', 'modify']: s4_zone_create(s4connector, object) elif object['modtype'] in ['delete']: s4_zone_delete(s4connector, object) # ignore move elif dns_type == 'host_record': if object['modtype'] in ['add', 'modify']: s4_host_record_create(s4connector, object) elif object['modtype'] in ['delete']: s4_dns_node_base_delete(s4connector, object) # ignore move elif dns_type == 'alias': if object['modtype'] in ['add', 'modify']: s4_cname_create(s4connector, object) elif object['modtype'] in ['delete']: s4_dns_node_base_delete(s4connector, object) # ignore move elif dns_type == 'srv_record': if object['modtype'] in ['add', 'modify']: s4_srv_record_create(s4connector, object) elif object['modtype'] in ['delete']: s4_dns_node_base_delete(s4connector, object) # ignore move elif dns_type == 'ptr_record': if object['modtype'] in ['add', 'modify']: s4_ptr_record_create(s4connector, object) elif object['modtype'] in ['delete']: s4_dns_node_base_delete(s4connector, object) # ignore move return True
def ucs_srv_record_delete(s4connector, object): _d=ud.function('ucs_srv_record_delete') ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_delete: object: %s' % object) zoneName, relativeDomainName=__split_s4_dn(object['dn']) searchResult=s4connector.lo.search(filter='(&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName), unique=1) if len(searchResult) > 0: superordinate=s4connector_get_superordinate('dns/srv_record', s4connector.lo, searchResult[0][0]) newRecord= univention.admin.handlers.dns.srv_record.object(None, s4connector.lo, position=None, dn=searchResult[0][0], superordinate=superordinate, attributes=[], update_zone=False) newRecord.open() newRecord.delete() else: ud.debug(ud.LDAP, ud.INFO, 'ucs_srv_record_delete: Object was not found, filter was: ((&(relativeDomainName=%s)(zoneName=%s))' % (relativeDomainName, zoneName)) return True
def con2ucs (s4connector, key, object): _d=ud.function('dns: con2ucs') ud.debug(ud.LDAP, ud.INFO, 'dns con2ucs: Object (%s): %s' % (object['dn'], object)) dns_type=_identify_dns_con_object(s4connector, object) if not dns_type: # unknown object -> ignore ud.debug(ud.LDAP, ud.INFO, 'dns con2ucs: Ignore unkown dns object: %s' % object['dn']) return True ud.debug(ud.LDAP, ud.INFO, 'dns con2ucs: Object (%s) is from type %s' % (object['dn'], dns_type)) if dns_type == 'host_record': if object['modtype'] in ['add', 'modify']: ucs_host_record_create(s4connector, object) elif object['modtype'] in ['delete']: ucs_host_record_delete(s4connector, object) # ignore move elif dns_type == 'ptr_record': if object['modtype'] in ['add', 'modify']: ucs_ptr_record_create(s4connector, object) elif object['modtype'] in ['delete']: ucs_ptr_record_create(s4connector, object) # ignore move elif dns_type == 'alias': if object['modtype'] in ['add', 'modify']: ucs_cname_create(s4connector, object) elif object['modtype'] in ['delete']: ucs_cname_create(s4connector, object) # ignore move elif dns_type == 'srv_record': if object['modtype'] in ['add', 'modify']: ucs_srv_record_create(s4connector, object) elif object['modtype'] in ['delete']: ucs_srv_record_delete(s4connector, object) # ignore move if dns_type in ['forward_zone', 'reverse_zone']: if object['modtype'] in ['add', 'modify']: ucs_zone_create(s4connector, object, dns_type) elif object['modtype'] in ['delete']: ucs_zone_delete(s4connector, object, dns_type) # ignore move return True
def s4_zone_delete(s4connector, object): _d=ud.function('s4_zone_delete') zoneDn, zoneName=__create_default_s4_zone_dn(s4connector, object) zoneDnAt='DC=@,%s' % zoneDn try: res=s4connector.lo_s4.lo.delete_s(zoneDnAt) except ldap.NO_SUCH_OBJECT: pass #the object was already removed try: res=s4connector.lo_s4.lo.delete_s(zoneDn) except ldap.NO_SUCH_OBJECT: pass #the object was already removed return True
def _identify_dns_con_object(s4connector, object): _d=ud.function('_identify_dns_con_object') if object.get('attributes'): oc=object['attributes'].get('objectClass') dc=object['attributes'].get('dc') if oc and 'dnsZone' in oc: # forward or reverse zone if dc and dc[0].endswith('in-addr.arpa'): return 'reverse_zone' else: return 'forward_zone' if oc and 'dnsNode' in oc: if dc and dc[0] == '@': zone_type='forward_zone' split_dn=object['dn'].split(',')[1:] for rdn in split_dn: rdn=rdn.lower() if rdn.startswith('dc=') and rdn.endswith('in-addr.arpa'): zone_type='reverse_zone' break return zone_type else: dnsRecords=object['attributes'].get('dnsRecord') if not dnsRecords: return None dns_types=[] for dnsRecord in dnsRecords: dnsRecord=dnsRecord.encode('latin1') dnsRecord_DnssrvRpcRecord=ndr_unpack(dnsp.DnssrvRpcRecord, dnsRecord) dns_types.append(dnsRecord_DnssrvRpcRecord.wType) if dnsp.DNS_TYPE_PTR in dns_types: return 'ptr_record' elif dnsp.DNS_TYPE_CNAME in dns_types: return 'alias' elif dnsp.DNS_TYPE_SRV in dns_types: return 'srv_record' elif dnsp.DNS_TYPE_A in dns_types or dnsp.DNS_TYPE_AAAA: return 'host_record' return None
def ucs2con (s4connector, key, object): _d=ud.function('dc: ucs2con') ud.debug(ud.LDAP, ud.INFO, 'dc ucs2con: Object (%s): %s' % (object['dn'], object)) s4base_dn,s4base_attr = s4connector.lo_s4.lo.search_s(s4connector.s4_ldap_base, ldap.SCOPE_BASE, '(objectClass=*)')[0] ud.debug(ud.LDAP, ud.INFO, 'dc ucs2con: S4 object: %s' % (s4base_dn)) ud.debug(ud.LDAP, ud.INFO, 'dc ucs2con: S4 object: %s' % (s4base_attr)) if 'univentionBase' in object['attributes'].get('objectClass'): # DC object → sync GPO if s4connector.configRegistry.is_true('connector/s4/mapping/gpo', True): ucs_val = object['attributes'].get('msGPOLink', [None])[0] # msGPOLink is a single value s4_val = s4base_attr.get('msGPOLink') if ucs_val != s4_val: s4connector.lo_s4.lo.modify_s(s4connector.s4_ldap_base, [(ldap.MOD_REPLACE, 'gPLink', univention.s4connector.s4.compatible_modstring(ucs_val))]) elif 'sambaDomain' in object['attributes'].get('objectClass'): # Samba Domain object ml = [] sync_times = [ ('sambaMaxPwdAge', 'maxPwdAge'), ('sambaMinPwdAge', 'minPwdAge'), ('sambaLockoutDuration', 'lockoutDuration') ] for (ucs_attr, s4_attr) in sync_times: ucs_time = long(object['attributes'].get(ucs_attr, [0])[0]) s4_time = _nano2s(long(s4base_attr.get(s4_attr, [0])[0]) * -1) ud.debug(ud.LDAP, ud.INFO, 'dc ucs2con: ucs_time (%s): %s' % (ucs_attr, ucs_time)) ud.debug(ud.LDAP, ud.INFO, 'dc ucs2con: s4-time (%s): %s' % (s4_attr, s4_time)) if ucs_time != s4_time: ml.append( (ldap.MOD_REPLACE, s4_attr, [ str(_s2nano(ucs_time) * -1) ] ) ) sync_integers = [ ('sambaPwdHistoryLength', 'pwdHistoryLength'), ('sambaMinPwdLength', 'minPwdLength') ] for (ucs_attr, s4_attr) in sync_integers: ucs_val = object['attributes'].get(ucs_attr, str(0)) s4_val = s4base_attr.get(s4_attr, [0])[0] if ucs_val != s4_val: ml.append( (ldap.MOD_REPLACE, s4_attr, ucs_val ) ) if ml: ud.debug(ud.LDAP, ud.INFO, 'dc ucs2con: S4 object modlist: %s' % (ml)) s4connector.lo_s4.lo.modify_s(s4connector.s4_ldap_base, univention.s4connector.s4.compatible_modlist(ml)) return True
def get_password_from_ad(connector, rid): _d=ud.function('ldap.ad.get_password_from_ad') a = array.array('c') _append ( a, univention.connector.ad.explode_unicode_dn(connector.lo_ad.binddn,1)[0] ) _append ( a, connector.lo_ad.bindpw ) a.append ( 'G' ) _append(a, rid) package = array.array('c') _append_array( package, a) # Create Socket and send package s = socket.socket( socket.AF_INET, socket.SOCK_STREAM ); s.connect ( (connector.lo_ad.host, 6670) ) ssl=ssl_init(s.fileno()) M2Crypto.__m2crypto.ssl_write(ssl, package) return M2Crypto.__m2crypto.ssl_read(ssl, 8192)
def s4_dns_node_base_create(s4connector, object, dnsRecords): _d=ud.function('s4_dns_node_base_create') zoneDn, zoneName=__create_default_s4_zone_dn(s4connector, object) relativeDomainNames=object['attributes'].get('relativeDomainName') relativeDomainNames=univention.s4connector.s4.compatible_list(relativeDomainNames) old_dnsRecords=[] # Create dnsNode object dnsNodeDn='DC=%s,%s' % (relativeDomainNames[0],zoneDn) try: searchResult=s4connector.lo_s4.lo.search_s(dnsNodeDn, ldap.SCOPE_BASE, '(objectClass=*)') if searchResult and searchResult[0][1]: old_dnsRecords=searchResult[0][1].get('dnsRecord') except ldap.NO_SUCH_OBJECT: __create_s4_dns_node(s4connector, dnsNodeDn, relativeDomainNames, dnsRecords) else: res=s4connector.lo_s4.modify(dnsNodeDn, [('dnsRecord', old_dnsRecords, dnsRecords)]) return dnsNodeDn
def s42ucs_sambaGroupType(s4connector, key, object): _d=ud.function('mapping.s42ucs_sambaGroupType -- not implemented') pass
def s42ucs_dn_string(dn): _d=ud.function('mapping.s42ucs_dn_string') return string.replace(dn,configRegistry['connector/s4/ldap/base'],configRegistry['ldap/base'])
def s42ucs_dn(s4connector, key, object): _d=ud.function('mapping.s42ucs_dn') return s42ucs_dn_string(object.dn)
def ucs2s4_user_dn(s4connector, key, object): _d=ud.function('mapping.ucs2s4_user_dn') return string.replace(ucs2s4_dn(s4connector, key, object),"uid=","cn=")
def s42ucs_user_dn(s4connector, key, object): _d=ud.function('mapping.s42ucs_user_dn') return string.replace(s42ucs_dn(s4connector, key, object),"cn=","uid=")
def ucs2s4_sambaGroupType(s4connector, key, object): _d=ud.function('mapping.ucs2s4_sambaGroupType -- not implemented') return "-2147483644"
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 ])
def password_sync_s4_to_ucs(s4connector, key, ucs_object, modifyUserPassword=True): _d=ud.function('ldap.s4.password_sync_s4_to_ucs') ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs called") object=s4connector._object_mapping(key, ucs_object, 'ucs') res=s4connector.lo_s4.lo.search_s(univention.s4connector.s4.compatible_modstring(object['dn']), ldap.SCOPE_BASE, '(objectClass=*)',['objectSid','pwdLastSet']) pwdLastSet = None if res[0][1].has_key('pwdLastSet'): pwdLastSet = long(res[0][1]['pwdLastSet'][0]) ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: pwdLastSet from S4: %s (%s)" % (pwdLastSet,res)) objectSid = univention.s4connector.s4.decode_sid(res[0][1]['objectSid'][0]) # rid = None # if res[0][1].has_key('objectSid'): # rid = str(univention.s4connector.s4.decode_sid(res[0][1]['objectSid'][0]).split('-')[-1]) res=s4connector.lo_s4.lo.search_s(s4connector.lo_s4.base, ldap.SCOPE_SUBTREE, univention.s4connector.s4.compatible_modstring('(objectSid=%s)' % objectSid), ['unicodePwd', 'supplementalCredentials', 'msDS-KeyVersionNumber', 'dBCSPwd']) unicodePwd_attr = res[0][1].get('unicodePwd', [None])[0] if unicodePwd_attr: ntPwd = binascii.b2a_hex(unicodePwd_attr).upper() lmPwd = '' dBCSPwd = res[0][1].get('dBCSPwd', [None])[0] if dBCSPwd: lmPwd = binascii.b2a_hex(dBCSPwd).upper() supplementalCredentials = res[0][1].get('supplementalCredentials', [None])[0] msDS_KeyVersionNumber = res[0][1].get('msDS-KeyVersionNumber', [0])[0] ntPwd_ucs = '' lmPwd_ucs = '' krb5Principal = '' userPassword = '' modlist=[] res=s4connector.lo.search(base=ucs_object['dn'], attr=['sambaPwdMustChange', 'sambaPwdLastSet','sambaNTPassword', 'sambaLMPassword', 'krb5PrincipalName', 'krb5Key', 'krb5KeyVersionNumber', 'userPassword', 'shadowLastChange', 'shadowMax', 'krb5PasswordEnd']) if res[0][1].has_key('sambaNTPassword'): ntPwd_ucs = res[0][1]['sambaNTPassword'][0] if res[0][1].has_key('sambaLMPassword'): lmPwd_ucs = res[0][1]['sambaLMPassword'][0] if res[0][1].has_key('krb5PrincipalName'): krb5Principal=res[0][1]['krb5PrincipalName'][0] if res[0][1].has_key('userPassword'): userPassword=res[0][1]['userPassword'][0] sambaPwdLastSet = None if res[0][1].has_key('sambaPwdLastSet'): sambaPwdLastSet=res[0][1]['sambaPwdLastSet'][0] ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: sambaPwdLastSet: %s" % sambaPwdLastSet) sambaPwdMustChange = '' if res[0][1].has_key('sambaPwdMustChange'): sambaPwdMustChange=res[0][1]['sambaPwdMustChange'][0] ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: sambaPwdMustChange: %s" % sambaPwdMustChange) krb5Key_ucs=res[0][1].get('krb5Key', []) userPassword_ucs=res[0][1].get('userPassword', [None])[0] krb5KeyVersionNumber=res[0][1].get('krb5KeyVersionNumber', [None])[0] pwd_changed = False if ntPwd != ntPwd_ucs: pwd_changed = True modlist.append(('sambaNTPassword', ntPwd_ucs, str(ntPwd))) if lmPwd != lmPwd_ucs: pwd_changed = True modlist.append(('sambaLMPassword', lmPwd_ucs, str(lmPwd))) if pwd_changed: if krb5Principal: ## decoding of Samba4 supplementalCredentials krb5Key_new = calculate_krb5key(unicodePwd_attr, supplementalCredentials, int(msDS_KeyVersionNumber)) modlist.append(('krb5Key', krb5Key_ucs, krb5Key_new)) if int(msDS_KeyVersionNumber) != int(krb5KeyVersionNumber): modlist.append(('krb5KeyVersionNumber', krb5KeyVersionNumber, msDS_KeyVersionNumber)) ## Append modification as well to modlist, to apply in one transaction if modifyUserPassword: modlist.append(('userPassword', userPassword_ucs, '{K5KEY}')) # Remove the POSIX and Kerberos password expiry interval if res[0][1].has_key('shadowLastChange'): modlist.append(('shadowLastChange', res[0][1]['shadowLastChange'][0], None)) if res[0][1].has_key('shadowMax'): modlist.append(('shadowMax', res[0][1]['shadowMax'][0], None)) if res[0][1].has_key('krb5PasswordEnd'): modlist.append(('krb5PasswordEnd', res[0][1]['krb5PasswordEnd'][0], None)) else: ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: No password change to sync to UCS") if pwd_changed and (pwdLastSet or pwdLastSet == 0): newSambaPwdMustChange = sambaPwdMustChange if pwdLastSet == 0: # pwd change on next login newSambaPwdMustChange = str(pwdLastSet) newSambaPwdLastSet = str(pwdLastSet) else: newSambaPwdLastSet = str(univention.s4connector.s4.s42samba_time(pwdLastSet)) userobject = s4connector.get_ucs_object('user', ucs_object['dn']) if not userobject: ud.debug(ud.LDAP, ud.ERROR, "password_sync_s4_to_ucs: couldn't get user-object from UCS") return False sambaPwdMustChange=sambaPwdMustChange.strip() if not sambaPwdMustChange.isdigit(): pass elif pwd_changed or (long(sambaPwdMustChange) < time.time() and not pwdLastSet == 0): pwhistoryPolicy = userobject.loadPolicyObject('policies/pwhistory') try: expiryInterval=int(pwhistoryPolicy['expiryInterval']) newSambaPwdMustChange = str(long(newSambaPwdLastSet)+(expiryInterval*3600*24) ) except: # FIXME: which exception is to be caught? # expiryInterval is empty or no legal int-string pwhistoryPolicy['expiryInterval']='' expiryInterval=-1 newSambaPwdMustChange = '' ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: pwhistoryPolicy: expiryInterval: %s" % expiryInterval) if sambaPwdLastSet: if sambaPwdLastSet != newSambaPwdLastSet: modlist.append(('sambaPwdLastSet', sambaPwdLastSet, newSambaPwdLastSet)) ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: sambaPwdLastSet in modlist (replace): %s" % newSambaPwdLastSet) else: modlist.append(('sambaPwdLastSet', '', newSambaPwdLastSet )) ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: sambaPwdLastSet in modlist (set): %s" % newSambaPwdLastSet) if sambaPwdMustChange != newSambaPwdMustChange: # change if password has changed or "change pwd on next login" is not set # set sambaPwdMustChange regarding to the univention-policy if sambaPwdMustChange: modlist.append(('sambaPwdMustChange', sambaPwdMustChange, newSambaPwdMustChange)) ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: sambaPwdMustChange in modlist (replace): %s" % newSambaPwdMustChange) else: modlist.append(('sambaPwdMustChange', '', newSambaPwdMustChange)) ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: sambaPwdMustChange in modlist (set): %s" % newSambaPwdMustChange) if len(modlist)>0: ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: modlist: %s" % modlist) s4connector.lo.lo.modify(ucs_object['dn'], modlist) else: ud.debug(ud.LDAP, ud.WARN, "password_sync_ucs_s4_to_ucs: Failed to get Password-Hash from S4")
def identify(dn, attr, canonical=0): _d=ud.function('dc: identify') return 'univentionBase' in attr.get('objectClass', []) or 'sambaDomain' in attr.get('objectClass', [])