Пример #1
0
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)
Пример #2
0
def __create_s4_forward_zone(s4connector, zoneDn, zoneName):
	al=[]
	al.append(('objectClass', ['top', 'dnsZone']))
	al.append(('DC', univention.s4connector.s4.compatible_list(zoneName)))

	ud.debug(ud.LDAP, ud.INFO, '_dns_zone_forward_con_create: dn: %s' % zoneDn)
	ud.debug(ud.LDAP, ud.INFO, '_dns_zone_forward_con_create: al: %s' % al)
	s4connector.lo_s4.lo.add_s(zoneDn, al)
Пример #3
0
Файл: dc.py Проект: B-Rich/smart
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
Пример #4
0
def __pack_mxRecord(object, dnsRecords):
	for mXRecord in object['attributes'].get('mXRecord', []):
		if mXRecord:
			ud.debug(ud.LDAP, ud.INFO, '__pack_mxRecord: %s' % mXRecord)
			mXRecord=univention.s4connector.s4.compatible_modstring(mXRecord)
			mx=mXRecord.split(' ')
			priority=mx[0]
			name=mx[1]
			mx_record=MXRecord(name, int(priority))
			dnsRecords.append(ndr_pack(mx_record))
			ud.debug(ud.LDAP, ud.INFO, '__pack_mxRecord: %s' % ndr_pack(mx_record))
Пример #5
0
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()
Пример #6
0
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
Пример #7
0
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
Пример #8
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
Пример #9
0
def sid_to_s4_mapping(s4connector, key, object):
	ud.debug(ud.LDAP, ud.INFO, "sid_to_s4_mapping")
	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'

	sambaSID = object['attributes'][sidAttribute]
		
	# Two diffrent cases are possible, the user sid contains the
	# domain sid or not.
	if sambaSID[0].startswith('S-'):
		new_objectSid_ndr = ndr_pack(security.dom_sid('%s' % (sambaSID[0])))
	else:
		new_objectSid_ndr = ndr_pack(security.dom_sid('%s-%s' % (s4connector.s4_sid, sambaSID[0])))

	return [new_objectSid_ndr]
Пример #10
0
Файл: dc.py Проект: B-Rich/smart
def _unixTimeInverval2seconds(unixTime):
	if type(unixTime) != type([]):
		return unixTime

	if len(unixTime) != 2:
		ud.debug(ud.LDAP, ud.WARN, 'dc _unixTimeInverval2seconds: Not a valid time format: %s' % unixTime)
		return 0

	if unixTime[1] == 'seconds':
		return unixTime[0]
	elif unixTime[1] == 'minutes':
		return unixTime[0] * 60
	elif unixTime[1] == 'hours':
		return unixTime[0] * 3600 # 60 * 60
	elif unixTime[1] == 'days':
		return unixTime[0] * 86400 # 60 * 60 * 24
	else:
		ud.debug(ud.LDAP, ud.WARN, 'dc _unixTimeInverval2seconds: Not a valid time unit: %s' % unixTime)
		return 0
Пример #11
0
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
Пример #12
0
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 = int(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 = int(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 = int(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 and unicodePwd_new:
				modlist.append((ldap.MOD_REPLACE, '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 ucsLMhash:
			dBCSPwd_new = binascii.a2b_hex(ucsLMhash)
			modlist.append((ldap.MOD_REPLACE, 'dBCSPwd', dBCSPwd_new))
		else:
			ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: dBCSPwd should be removed in Samba 4 which is no longer possible, see Bug https://forge.univention.org/bugzilla/show_bug.cgi?id=49905")
			# modlist.append((ldap.MOD_DELETE, 'dBCSPwd', dBCSPwd_attr))

	if pwd_set or not supplementalCredentials:
		if krb5Principal:
			# encoding of Samba4 supplementalCredentials
			if krb5Key:
				supplementalCredentials_new = calculate_supplementalCredentials(krb5Key, supplementalCredentials)
				if supplementalCredentials_new:
					modlist.append((ldap.MOD_REPLACE, '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])
Пример #13
0
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 test_debug_closed():
    ud.debug(ud.MAIN, ud.ALL, "No crash")
    assert True
Пример #15
0
def sid_to_ucs_mapping(s4connector, key, s4_object):
	ud.debug(ud.LDAP, ud.INFO, "sid_to_ucs_mapping")
	object_sid=s4_object['attributes']['objectSid'][0]
	return object_sid.split('-')[-1]
Пример #16
0
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.

import univention.debug2 as ud

ud.init('/tmp/univention.debug2.log', 1, 1)
ud.set_level(ud.PROCESS, ud.ERROR)
ud.set_level(ud.LISTENER, ud.WARN)
ud.set_level(ud.NETWORK, ud.PROCESS)
ud.set_level(ud.LDAP, ud.INFO)
ud.set_level(ud.ADMIN, ud.ALL)

for lvl in [ud.ERROR, ud.WARN, ud.PROCESS, ud.INFO, ud.ALL]:
    for mod in [ud.ADMIN, ud.PROCESS, ud.LISTENER, ud.NETWORK, ud.LDAP]:
        ud.debug(mod, lvl, '==> send msg to %s with level %s' % (mod, lvl))

ud.set_level(ud.ADMIN, ud.ERROR)
ud.debug(ud.ADMIN, ud.ERROR, '==> admin error')
ud.debug(ud.ADMIN, ud.WARN, '==> admin warn')
ud.debug(ud.ADMIN, ud.PROCESS, '==> admin process')
ud.debug(ud.ADMIN, ud.INFO, '==> admin info')
ud.debug(ud.ADMIN, ud.ALL, '==> admin all')

ud.set_level(ud.LDAP, ud.INFO)
ud.debug(ud.LDAP, ud.ERROR, '==> ldap error')
ud.debug(ud.LDAP, ud.WARN, '==> ldap warn')
ud.debug(ud.LDAP, ud.PROCESS, '==> ldap process')
ud.debug(ud.LDAP, ud.INFO, '==> ldap info')
ud.debug(ud.LDAP, ud.ALL, '==> ldap all')
Пример #17
0
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)
Пример #18
0
def sid_to_ucs(s4connector, key, s4_object):
	ud.debug(ud.LDAP, ud.INFO, "sid_to_ucs S4 object: %s" % s4_object)
	ud.debug(ud.LDAP, ud.INFO, "sid_to_ucs S4 key: %s" % key)

	sidAttribute='sambaSID'
	if s4connector.configRegistry.is_false('connector/s4/mapping/sid', False):
		ud.debug(ud.LDAP, ud.INFO, 'sid_to_ucs: SID mapping is disabled via UCR: connector/s4/mapping/sid')
		sidAttribute='univentionSamba4SID'
	else:
		# This case will be handled by direct mapping
		return

	# modlist
	ml = []

	# object dn is already mapped to the UCS DN:
	if not s4_object.get('dn'):
		return # ignore
	ucs_dn = s4_object['dn']
	ud.debug(ud.LDAP, ud.INFO, "sid_to_s4: UCS DN %s" % ucs_dn)
	
	if s4_object.has_key('attributes') and s4_object['attributes'].has_key('objectSid'):
		ud.debug(ud.LDAP, ud.INFO, 'sid_to_ucs: objectSid found: %s' % s4_object['attributes']['objectSid'])
	else:
		ud.debug(ud.LDAP, ud.INFO, 'sid_to_ucs: objectSid not found in attributes!')
		return

	(ucs_dn, ucs_attributes) = s4connector.lo.lo.search(base=ucs_dn, scope='base', attr=[sidAttribute, 'objectClass'])[0]

	if not ucs_dn:
		ud.debug(ud.LDAP, ud.WARN, 'sid_to_ucs: UCS object (%s) not found' % ucs_dn)
		return

	objectSid = s4_object['attributes'].get('objectSid')
	sambaSID = ucs_attributes.get(sidAttribute)
	if not sambaSID or objectSid != sambaSID:
		ml.append((sidAttribute, sambaSID, s4_object['attributes'].get('objectSid')))
		if 'user' in s4_object['attributes'].get('objectClass', []):
			if not 'sambaSamAccount' in ucs_attributes.get('objectClass'):
				ml.append(('objectClass',ucs_attributes.get('objectClass'), ucs_attributes.get('objectClass')+['sambaSamAccount']))
		if 'group' in s4_object['attributes'].get('objectClass', []):
			if not 'sambaGroupMapping' in ucs_attributes.get('objectClass'):
				ml.append(('objectClass',ucs_attributes.get('objectClass'), ucs_attributes.get('objectClass')+['sambaGroupMapping']))
	if ml:
		ud.debug(ud.LDAP, ud.INFO, 'sid_to_ucs: modlist = %s' % ml)
		s4connector.lo.lo.modify(ucs_dn, ml)

	return
Пример #19
0
def password_sync_ucs(connector, key, object):
	_d=ud.function('ldap.ad.password_sync_ucs')
	# externes Programm zum Überptragen des Hash aufrufen
	# per ldapmodify pwdlastset auf -1 setzen
	
	compatible_modstring = univention.connector.ad.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 = connector._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 = connector.lo.lo.search(base=ucs_object['dn'], scope='base', attr=['sambaLMPassword', 'sambaNTPassword','sambaPwdLastSet'])
	except ldap.NO_SUCH_OBJECT:
		ud.debug(ud.LDAP, ud.PROCESS, "password_sync_ucs: The UCS object (%s) was not found. The object was removed." % 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: sambaPwdLastSet: %s" % sambaPwdLastSet)
	
	pwd = None
	if res[0][1].has_key('sambaNTPassword'):
		pwd=res[0][1]['sambaNTPassword'][0]
	else:
		pwd='NO PASSWORDXXXXXX'
		ud.debug(ud.LDAP, ud.WARN, "password_sync_ucs: Failed to get NT Hash from UCS")

	if res[0][1].has_key('sambaLMPassword'):
		pwd+=res[0][1]['sambaLMPassword'][0]
	else:
		pwd+='NO PASSWORDXXXXX'
		ud.debug(ud.LDAP, ud.WARN, "password_sync_ucs: Failed to get LM Hash from UCS")

	res=connector.lo_ad.lo.search_s(univention.connector.ad.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])
	ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs: pwdLastSet from AD : %s" % pwdLastSet)
	rid = None
	if res[0][1].has_key('objectSid'):
		rid = str(univention.connector.ad.decode_sid(res[0][1]['objectSid'][0]).split('-')[-1])

	# Only sync passwords from UCS to AD when the password timestamp in UCS is newer
	if connector.baseConfig.is_true('%s/ad/password/timestamp/check' % connector.CONFIGBASENAME, False):
		ad_password_last_set = 0
		# If sambaPwdLast was set to 1 the password must be changed on next login. In this
		# case the timestamp is ignored and the password will be synced. This behaviour can
		# be disbled by setting connector/ad/password/timestamp/syncreset/ucs to false. This
		# might be necessary if the connector is configured in read mode and the password will be
		# synced in two ways: Bug #22653
		if sambaPwdLastSet > 1 or ( sambaPwdLastSet <= 2 and connector.baseConfig.is_false('%s/ad/password/timestamp/syncreset/ucs' % connector.CONFIGBASENAME, False)):
			ad_password_last_set = univention.connector.ad.ad2samba_time(pwdLastSet)
			if sambaPwdLastSet:
				if long(ad_password_last_set) >= long(sambaPwdLastSet):
					# skip
					ud.debug(ud.LDAP, ud.PROCESS, "password_sync: Don't sync the password from UCS to AD because the AD password equal or is newer.")
					ud.debug(ud.LDAP, ud.INFO, "password_sync:  AD pwdlastset: %s (original (%s))" % (ad_password_last_set, pwdLastSet))
					ud.debug(ud.LDAP, ud.INFO, "password_sync: UCS pwdlastset: %s" % (sambaPwdLastSet))
					return

		ud.debug(ud.LDAP, ud.INFO, "password_sync: Sync the passwords from UCS to AD.")
		ud.debug(ud.LDAP, ud.INFO, "password_sync:  AD pwdlastset: %s (original (%s))" % (ad_password_last_set, pwdLastSet))
		ud.debug(ud.LDAP, ud.INFO, "password_sync: UCS pwdlastset: %s" % (sambaPwdLastSet))
	
	pwd_set = False
	pwd_ad_res = get_password_from_ad(connector, rid)
	pwd_ad = ''
	if len(pwd_ad_res) >3 and _get_integer(pwd_ad_res[4:]) == 0:
		pwd_ad = pwd_ad_res[12:].split(':')[1].strip().upper()
	else:
		ud.debug(ud.LDAP, ud.WARN, "password_sync_ucs: Failed to get Password-Hash from AD")
	res = ''

	ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs: Hash AD: %s Hash UCS: %s"%(pwd_ad,pwd))
	if not pwd == pwd_ad:
		pwd_set = True
		res = set_password_in_ad(connector, object['attributes']['sAMAccountName'][0], pwd)

	if not pwd_set or len(res) >3 and _get_integer(res[4:]) == 0 :
		newpwdlastset = "-1" # if pwd was set in ad we need to set pwdlastset to -1 or it will be 0		
		#if sambaPwdMustChange >= 0 and sambaPwdMustChange < time.time():
		#	# password expired, must be changed on next login
		#	ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs: samba pwd expired, set newpwdLastSet to 0")
		#	newpwdlastset = "0"
		if sambaPwdLastSet <= 1:
			newpwdlastset = "0" # User must change his password
		elif pwdLastSet and int(pwdLastSet) > 0 and not pwd_set:
			newpwdlastset = "1"
		if long(newpwdlastset) != 1:
			ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs: pwdlastset in modlist: %s" % newpwdlastset)
			connector.lo_ad.lo.modify_s(compatible_modstring(object['dn']), [(ldap.MOD_REPLACE, 'pwdlastset', newpwdlastset)])
		else:
			ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs: don't modify pwdlastset")
	else:
		ud.debug(ud.LDAP, ud.ERROR, "password_sync_ucs: Failed to sync Password from AD ")
Пример #20
0
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")
Пример #21
0
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()
Пример #22
0
def password_sync(connector, key, ucs_object):
	_d=ud.function('ldap.ad.password_sync')
	# externes Programm zum holen des Hash aufrufen
	# "kerberos_now"

	object=connector._object_mapping(key, ucs_object, 'ucs')
	res=connector.lo_ad.lo.search_s(univention.connector.ad.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: pwdLastSet from AD: %s (%s)" % (pwdLastSet,res))

	rid = None
	if res[0][1].has_key('objectSid'):
		rid = str(univention.connector.ad.decode_sid(res[0][1]['objectSid'][0]).split('-')[-1])

	ucs_result=connector.lo.search(base=ucs_object['dn'], attr=['sambaPwdLastSet','sambaNTPassword', 'sambaLMPassword', 'krb5PrincipalName', 'shadowLastChange', 'shadowMax', 'krb5PasswordEnd'])

	sambaPwdLastSet = None
	if ucs_result[0][1].has_key('sambaPwdLastSet'):
		sambaPwdLastSet=ucs_result[0][1]['sambaPwdLastSet'][0]
	ud.debug(ud.LDAP, ud.INFO, "password_sync: sambaPwdLastSet: %s" % sambaPwdLastSet)

	if connector.baseConfig.is_true('%s/ad/password/timestamp/check' % connector.CONFIGBASENAME, False):
		# Only sync the passwords from AD to UCS when the pwdLastSet timestamps in AD are newer
		ad_password_last_set = 0

		# If pwdLastSet was set to 0 the password must be changed on next login. In this
		# case the timestamp is ignored and the password will be synced. This behaviour can
		# be disabled by setting connector/ad/password/timestamp/syncreset/ad to false. This
		# might be necessary if the connector is configured in read mode and the password will be
		# synced in two ways: Bug #22653
		if (pwdLastSet > 1) or (pwdLastSet in [0,1] and connector.baseConfig.is_false('%s/ad/password/timestamp/syncreset/ad' % connector.CONFIGBASENAME, False)):
			ad_password_last_set = univention.connector.ad.ad2samba_time(pwdLastSet)
			if sambaPwdLastSet:
				if long(sambaPwdLastSet) >= long(ad_password_last_set) and long(sambaPwdLastSet) != 1:
					# skip
					ud.debug(ud.LDAP, ud.PROCESS, "password_sync: Don't sync the passwords from AD to UCS because the UCS password is equal or newer.")
					ud.debug(ud.LDAP, ud.INFO, "password_sync:  AD pwdlastset: %s (original (%s))" % (ad_password_last_set, pwdLastSet))
					ud.debug(ud.LDAP, ud.INFO, "password_sync: UCS pwdlastset: %s" % (sambaPwdLastSet))
					return

		ud.debug(ud.LDAP, ud.INFO, "password_sync: Sync the passwords from AD to UCS.")
		ud.debug(ud.LDAP, ud.INFO, "password_sync:  AD pwdlastset: %s (original (%s))" % (ad_password_last_set, pwdLastSet))
		ud.debug(ud.LDAP, ud.INFO, "password_sync: UCS pwdlastset: %s" % (sambaPwdLastSet))

	res = get_password_from_ad(connector, rid)

	if len(res) >3 and _get_integer(res[4:]) == 0:
		ntPwd_ucs = ''
		lmPwd_ucs = ''
		krb5Principal = ''
		userPassword = ''

		data = res[12:].split(':')[1].strip()
		ntPwd = data[:32]
		lmPwd = data[32:]
		modlist=[]

		if ucs_result[0][1].has_key('sambaLMPassword'):
			lmPwd_ucs = ucs_result[0][1]['sambaLMPassword'][0]
		if ucs_result[0][1].has_key('sambaNTPassword'):
			ntPwd_ucs = ucs_result[0][1]['sambaNTPassword'][0]
		if ucs_result[0][1].has_key('krb5PrincipalName'):
			krb5Principal=ucs_result[0][1]['krb5PrincipalName'][0]
		if ucs_result[0][1].has_key('userPassword'):
			userPassword=ucs_result[0][1]['userPassword'][0]

		pwd_changed = False

 		if lmPwd.upper() != lmPwd_ucs.upper():
			if not lmPwd in ['00000000000000000000000000000000', 'NO PASSWORD*********************']:
				pwd_changed = True
				modlist.append(('sambaLMPassword', lmPwd_ucs, str(lmPwd.upper())))
		if ntPwd.upper() != ntPwd_ucs.upper():
			if ntPwd in ['00000000000000000000000000000000', 'NO PASSWORD*********************']:
				ud.debug(ud.LDAP, ud.WARN, "password_sync: AD connector password daemon retured 0 for the nt hash. Please check the AD settings.")
			else:
				ud.debug(ud.LDAP, ud.WARN, "password_sync: %s" % ntPwd)
				pwd_changed = True
				modlist.append(('sambaNTPassword', ntPwd_ucs, str(ntPwd.upper())))
				if krb5Principal:
					connector.lo.lo.lo.modify_s(univention.connector.ad.compatible_modstring(ucs_object['dn']),
									[(ldap.MOD_REPLACE, 'krb5Key', nt_password_to_arcfour_hmac_md5(ntPwd.upper()))])
		if pwd_changed:
			connector.lo.lo.lo.modify_s(univention.connector.ad.compatible_modstring(ucs_object['dn']), [(ldap.MOD_REPLACE, 'userPassword', '{K5KEY}')])
			# Remove the POSIX and Kerberos password expiry interval
			if ucs_result[0][1].has_key('shadowLastChange'):
				modlist.append(('shadowLastChange', ucs_result[0][1]['shadowLastChange'][0], None))
			if ucs_result[0][1].has_key('shadowMax'):
				modlist.append(('shadowMax', ucs_result[0][1]['shadowMax'][0], None))
			if ucs_result[0][1].has_key('krb5PasswordEnd'):
				modlist.append(('krb5PasswordEnd', ucs_result[0][1]['krb5PasswordEnd'][0], None))

			if pwdLastSet or pwdLastSet == 0:
				newSambaPwdLastSet = str(univention.connector.ad.ad2samba_time(pwdLastSet))

				if sambaPwdLastSet:
					if sambaPwdLastSet != newSambaPwdLastSet:
						modlist.append(('sambaPwdLastSet', sambaPwdLastSet, newSambaPwdLastSet))
						ud.debug(ud.LDAP, ud.INFO, "password_sync: sambaPwdLastSet in modlist (replace): %s" %
											newSambaPwdLastSet)
				else:
					modlist.append(('sambaPwdLastSet', '', newSambaPwdLastSet ))
					ud.debug(ud.LDAP, ud.INFO, "password_sync: sambaPwdLastSet in modlist (set): %s" %
										newSambaPwdLastSet)

		if len(modlist)>0:	
			connector.lo.lo.modify(ucs_object['dn'], modlist)


	else:
		ud.debug(ud.LDAP, ud.ERROR, "password_sync: sync failed, no result from AD" )
Пример #23
0
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()
Пример #24
0
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])
Пример #25
0
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")
Пример #26
0
def calculate_krb5key(unicodePwd, supplementalCredentials, kvno=0):
	up_blob = unicodePwd
	sc_blob = supplementalCredentials

	keys = []
	keytypes = []
	context = heimdal.context()

	if up_blob:
		# ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: up_blob: %s" % binascii.b2a_base64(up_blob))
		assert len(up_blob) == 16
		key = heimdal.keyblock_raw(context, 23, up_blob)
		keys.append(heimdal.asn1_encode_key(key, None, kvno))

	if sc_blob:
		# ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: sc_blob: %s" % binascii.b2a_base64(sc_blob))
		try:
			sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, sc_blob)
			for p in sc.sub.packages:
				krb = None
				ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: parsing %s blob" % p.name)
				if p.name == "Primary:Kerberos":
					krb_blob = binascii.unhexlify(p.data)
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 3

					for k in krb.ctr.keys:
						if k.keytype not in keytypes:
							ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ctr3.key.keytype: %s" % k.keytype)
							try:
								key = heimdal.keyblock_raw(context, k.keytype, k.value)
								krb5SaltObject = heimdal.salt_raw(context, krb.ctr.salt.string)
								keys.append(heimdal.asn1_encode_key(key, krb5SaltObject, kvno))
								keytypes.append(k.keytype)
							except:
								if k.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) for this
									if k.value == up_blob:  # the known case
										ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ignoring arc4 NThash with special keytype %s in %s" % (k.keytype, p.name))
									else:  # unknown special case
										ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ignoring unknown key with special keytype %s in %s" % (k.keytype, p.name))
								else:
									traceback.print_exc()
									ud.debug(ud.LDAP, ud.ERROR, "calculate_krb5key: krb5Key with keytype %s could not be parsed in %s. Ignoring this keytype." % (k.keytype, p.name))

				elif p.name == "Primary:Kerberos-Newer-Keys":
					krb_blob = binascii.unhexlify(p.data)
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 4

					for k in krb.ctr.keys:
						if k.keytype not in keytypes:
							ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ctr4.key.keytype: %s" % k.keytype)
							try:
								key = heimdal.keyblock_raw(context, k.keytype, k.value)
								krb5SaltObject = heimdal.salt_raw(context, krb.ctr.salt.string)
								keys.append(heimdal.asn1_encode_key(key, krb5SaltObject, kvno))
								keytypes.append(k.keytype)
							except:
								if k.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) for this
									if k.value == up_blob:  # the known case
										ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ignoring arc4 NThash with special keytype %s in %s" % (k.keytype, p.name))
									else:  # unknown special case
										ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ignoring unknown key with special keytype %s in %s" % (k.keytype, p.name))
								else:
									traceback.print_exc()
									ud.debug(ud.LDAP, ud.ERROR, "calculate_krb5key: krb5Key with keytype %s could not be parsed in %s. Ignoring this keytype." % (k.keytype, p.name))

		except Exception:
			import sys
			exc = sys.exc_info()[1]
			if isinstance(exc.args, type(())) and len(exc.args) == 2 and exc.args[1] == 'Buffer Size Error':
				ud.debug(ud.LDAP, ud.WARN, "calculate_krb5key: '%s' while unpacking supplementalCredentials:: %s" % (exc, binascii.b2a_base64(sc_blob)))
				ud.debug(ud.LDAP, ud.WARN, "calculate_krb5key: the krb5Keys from the PrimaryKerberosBlob could not be parsed. Continuing anyway.")
			else:
				traceback.print_exc()
				ud.debug(ud.LDAP, ud.ERROR, "calculate_krb5key: the krb5Keys from the PrimaryKerberosBlob could not be parsed. Continuing anyway.")

	return keys
def password_sync(connector, key, ucs_object):
    _d = ud.function('ldap.ad.password_sync')  # noqa: F841
    # externes Programm zum holen des Hash aufrufen
    # "kerberos_now"

    object = connector._object_mapping(key, ucs_object, 'ucs')
    res = connector.lo_ad.lo.search_s(
        univention.connector.ad.compatible_modstring(object['dn']),
        ldap.SCOPE_BASE, '(objectClass=*)', ['objectSid', 'pwdLastSet'])

    if connector.isInCreationList(object['dn']):
        connector.removeFromCreationList(object['dn'])
        ud.debug(
            ud.LDAP, ud.INFO,
            "password_sync: Synchronisation of password has been canceled. Object was just created."
        )
        return

    pwdLastSet = None
    if 'pwdLastSet' in res[0][1]:
        pwdLastSet = int(res[0][1]['pwdLastSet'][0])
    ud.debug(ud.LDAP, ud.INFO,
             "password_sync: pwdLastSet from AD: %s (%s)" % (pwdLastSet, res))

    if 'objectSid' in res[0][1]:
        str(
            univention.connector.ad.decode_sid(
                res[0][1]['objectSid'][0]).split('-')[-1])

    ucs_result = connector.lo.search(base=ucs_object['dn'],
                                     attr=[
                                         'sambaPwdLastSet', 'sambaNTPassword',
                                         'krb5PrincipalName', 'krb5Key',
                                         'shadowLastChange', 'shadowMax',
                                         'krb5PasswordEnd'
                                     ])

    sambaPwdLastSet = None
    if 'sambaPwdLastSet' in ucs_result[0][1]:
        sambaPwdLastSet = ucs_result[0][1]['sambaPwdLastSet'][0]
    ud.debug(ud.LDAP, ud.INFO,
             "password_sync: sambaPwdLastSet: %s" % sambaPwdLastSet)

    if connector.baseConfig.is_true(
            '%s/ad/password/timestamp/check' % connector.CONFIGBASENAME,
            False):
        # Only sync the passwords from AD to UCS when the pwdLastSet timestamps in AD are newer
        ad_password_last_set = 0

        # If pwdLastSet was set to 0 the password must be changed on next login. In this
        # case the timestamp is ignored and the password will be synced. This behavior can
        # be disabled by setting connector/ad/password/timestamp/syncreset/ad to false. This
        # might be necessary if the connector is configured in read mode and the password will be
        # synced in two ways: Bug #22653
        if (pwdLastSet > 1) or (pwdLastSet in [0, 1]
                                and connector.baseConfig.is_false(
                                    '%s/ad/password/timestamp/syncreset/ad' %
                                    connector.CONFIGBASENAME, False)):
            ad_password_last_set = univention.connector.ad.ad2samba_time(
                pwdLastSet)
            if sambaPwdLastSet:
                if int(sambaPwdLastSet) >= int(ad_password_last_set) and int(
                        sambaPwdLastSet) != 1:
                    # skip
                    ud.debug(
                        ud.LDAP, ud.PROCESS,
                        "password_sync: Don't sync the passwords from AD to UCS because the UCS password is equal or newer."
                    )
                    ud.debug(
                        ud.LDAP, ud.INFO,
                        "password_sync:  AD pwdlastset: %s (original (%s))" %
                        (ad_password_last_set, pwdLastSet))
                    ud.debug(
                        ud.LDAP, ud.INFO, "password_sync: UCS pwdlastset: %s" %
                        (sambaPwdLastSet))
                    return

        ud.debug(ud.LDAP, ud.INFO,
                 "password_sync: Sync the passwords from AD to UCS.")
        ud.debug(
            ud.LDAP, ud.INFO,
            "password_sync:  AD pwdlastset: %s (original (%s))" %
            (ad_password_last_set, pwdLastSet))
        ud.debug(ud.LDAP, ud.INFO,
                 "password_sync: UCS pwdlastset: %s" % (sambaPwdLastSet))

    try:
        nt_hash, krb5Key = get_password_from_ad(
            connector,
            univention.connector.ad.compatible_modstring(object['dn']))
    except Exception as e:
        ud.debug(
            ud.LDAP, ud.PROCESS,
            "password_sync: get_password_from_ad failed with %s, retry with reconnect"
            % str(e))
        nt_hash, krb5Key = get_password_from_ad(
            connector,
            univention.connector.ad.compatible_modstring(object['dn']),
            reconnect=True)

    old_krb5end = ucs_result[0][1].get('krb5PasswordEnd', [None])[0]
    old_shadowMax = ucs_result[0][1].get('shadowMax', [None])[0]
    old_shadowLastChange = ucs_result[0][1].get('shadowLastChange', [None])[0]
    modlist = []

    if nt_hash:
        ntPwd_ucs = ''
        krb5Principal = ''

        ntPwd = nt_hash

        if 'sambaNTPassword' in ucs_result[0][1]:
            ntPwd_ucs = ucs_result[0][1]['sambaNTPassword'][0]
        if 'krb5PrincipalName' in ucs_result[0][1]:
            krb5Principal = ucs_result[0][1]['krb5PrincipalName'][0]

        pwd_changed = False

        if ntPwd.upper() != ntPwd_ucs.upper():
            if ntPwd in [
                    '00000000000000000000000000000000',
                    'NO PASSWORD*********************'
            ]:
                ud.debug(
                    ud.LDAP, ud.WARN,
                    "password_sync: AD connector password daemon returned 0 for the nt hash. Please check the AD settings."
                )
            else:
                pwd_changed = True
                modlist.append(
                    ('sambaNTPassword', ntPwd_ucs, str(ntPwd.upper())))
                if krb5Principal:
                    connector.lo.lo.modify_s(
                        univention.connector.ad.compatible_modstring(
                            ucs_object['dn']),
                        [(ldap.MOD_REPLACE, 'krb5Key',
                          nt_password_to_arcfour_hmac_md5(ntPwd.upper()))])

        if pwd_changed:
            if krb5Key:
                krb5Key_ucs = ucs_result[0][1]['krb5Key'][0]
                modlist.append(('krb5Key', krb5Key_ucs, krb5Key))

            connector.lo.lo.modify_s(
                univention.connector.ad.compatible_modstring(ucs_object['dn']),
                [(ldap.MOD_REPLACE, 'userPassword', '{K5KEY}')])

            # update shadowLastChange
            new_shadowLastChange = str(int(time.time()) / 3600 / 24)
            if pwdLastSet != 0:
                modlist.append(('shadowLastChange', old_shadowLastChange,
                                new_shadowLastChange))
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: update shadowLastChange to %s for %s" %
                    (new_shadowLastChange, ucs_object['dn']))

            # get pw policy
            new_shadowMax = None
            new_krb5end = None
            policies = connector.lo.getPolicies(ucs_object['dn'])
            policy = policies.get('univentionPolicyPWHistory',
                                  {}).get('univentionPWExpiryInterval')
            if policy:
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: password expiry for %s is %s" %
                    (ucs_object['dn'], policy))
                policy_value = policy.get('value', [None])[0]
                if policy_value:
                    new_shadowMax = policy_value
                    new_krb5end = time.strftime(
                        "%Y%m%d000000Z",
                        time.gmtime((int(time.time()) +
                                     (int(policy_value) * 3600 * 24))))

            # update shadowMax (set to value of univentionPWExpiryInterval, otherwise delete) and
            # krb5PasswordEnd (set to today + univentionPWExpiryInterval, otherwise delete)
            if (old_shadowMax or new_shadowMax) and (pwdLastSet != 0):
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: update shadowMax to %s for %s" %
                    (new_shadowMax, ucs_object['dn']))
                modlist.append(('shadowMax', old_shadowMax, new_shadowMax))
            if (old_krb5end or new_krb5end) and (pwdLastSet != 0):
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: update krb5PasswordEnd to %s for %s" %
                    (new_krb5end, ucs_object['dn']))
                modlist.append(('krb5PasswordEnd', old_krb5end, new_krb5end))
    else:
        ud.debug(ud.LDAP, ud.ERROR,
                 "password_sync: sync failed, no result from AD")

    # update sambaPwdLastSet
    if pwdLastSet or pwdLastSet == 0:
        newSambaPwdLastSet = str(
            univention.connector.ad.ad2samba_time(pwdLastSet))
        if sambaPwdLastSet:
            if sambaPwdLastSet != newSambaPwdLastSet:
                modlist.append(
                    ('sambaPwdLastSet', sambaPwdLastSet, newSambaPwdLastSet))
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: sambaPwdLastSet in modlist (replace): %s" %
                    newSambaPwdLastSet)
        else:
            modlist.append(('sambaPwdLastSet', '', newSambaPwdLastSet))
            ud.debug(
                ud.LDAP, ud.INFO,
                "password_sync: sambaPwdLastSet in modlist (set): %s" %
                newSambaPwdLastSet)
        if pwdLastSet == 0:
            expiry = int(time.time())
            new_krb5end = time.strftime("%Y%m%d000000Z", time.gmtime(expiry))
            if old_krb5end:
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: krb5PasswordEnd in modlist (replace): %s" %
                    new_krb5end)
                modlist.append(('krb5PasswordEnd', old_krb5end, new_krb5end))
            else:
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: krb5PasswordEnd in modlist (set): %s" %
                    new_krb5end)
                modlist.append(('krb5PasswordEnd', '', new_krb5end))
            if old_shadowMax:
                ud.debug(ud.LDAP, ud.INFO,
                         "password_sync: shadowMax in modlist (replace): 0")
                modlist.append(('shadowMax', old_shadowMax, '1'))
            else:
                ud.debug(ud.LDAP, ud.INFO,
                         "password_sync: shadowMax in modlist (set): 0")
                modlist.append(('shadowMax', '', '1'))
            two_days_ago = long(time.time()) - (86400 * 2)
            new_shadowLastChange = str(two_days_ago / 3600 / 24)
            if old_shadowLastChange:
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: shadowLastChange in modlist (replace): %s"
                    % new_shadowLastChange)
                modlist.append(('shadowLastChange', old_shadowLastChange,
                                new_shadowLastChange))
            else:
                ud.debug(
                    ud.LDAP, ud.INFO,
                    "password_sync: shadowMax in modlist (set): %s" %
                    new_shadowLastChange)
                modlist.append(('shadowLastChange', '', new_shadowLastChange))

    if len(modlist) > 0:
        connector.lo.lo.modify(ucs_object['dn'], modlist)
Пример #28
0
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")

	if ucs_object['modtype'] == 'modify':
		if 'pwdLastSet' not in ucs_object.get('changed_attributes', []):
			ud.debug(ud.LDAP, ud.INFO, 'password_sync_s4_to_ucs: the password for %s has not been changed. Skipping password sync.' % (ucs_object['dn']))
			return

	object = s4connector._object_mapping(key, ucs_object, 'ucs')
	s4_object_attributes = s4connector.lo_s4.get(compatible_modstring(object['dn']), ['objectSid', 'pwdLastSet'])

	if s4connector.isInCreationList(object['dn']):
		s4connector.removeFromCreationList(object['dn'])
		ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: Synchronisation of password has been canceled. Object was just created.")
		return

	pwdLastSet = None
	if 'pwdLastSet' in s4_object_attributes:
		pwdLastSet = int(s4_object_attributes['pwdLastSet'][0])
	ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: pwdLastSet from S4: %s (%s)" % (pwdLastSet, s4_object_attributes))
	objectSid = univention.s4connector.s4.decode_sid(s4_object_attributes['objectSid'][0])

	# rid = None
	# if s4_object_attributes.has_key('objectSid'):
	# 	rid = str(univention.s4connector.s4.decode_sid(s4_object_attributes['objectSid'][0]).split('-')[-1])

	filter_expr = format_escaped('(objectSid={0!e})', objectSid)
	res = s4connector.lo_s4.search(filter=filter_expr, attr=['unicodePwd', 'supplementalCredentials', 'msDS-KeyVersionNumber', 'dBCSPwd'])
	s4_search_attributes = res[0][1]

	unicodePwd_attr = s4_search_attributes.get('unicodePwd', [None])[0]
	if unicodePwd_attr:
		ntPwd = binascii.b2a_hex(unicodePwd_attr).upper()

		lmPwd = ''
		dBCSPwd = s4_search_attributes.get('dBCSPwd', [None])[0]
		if dBCSPwd:
			lmPwd = binascii.b2a_hex(dBCSPwd).upper()

		supplementalCredentials = s4_search_attributes.get('supplementalCredentials', [None])[0]
		msDS_KeyVersionNumber = s4_search_attributes.get('msDS-KeyVersionNumber', [0])[0]

		ntPwd_ucs = ''
		lmPwd_ucs = ''
		krb5Principal = ''
		userPassword = ''
		modlist = []
		ucs_object_attributes = s4connector.lo.get(ucs_object['dn'], ['sambaPwdMustChange', 'sambaPwdLastSet', 'sambaNTPassword', 'sambaLMPassword', 'krb5PrincipalName', 'krb5Key', 'krb5KeyVersionNumber', 'userPassword', 'shadowLastChange', 'shadowMax', 'krb5PasswordEnd', 'univentionService'])

		services = ucs_object_attributes.get('univentionService', [])
		if 'S4 SlavePDC' in services:
			ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: %s is a S4 SlavePDC server, skip password sync" % ucs_object['dn'])
			return

		if 'sambaNTPassword' in ucs_object_attributes:
			ntPwd_ucs = ucs_object_attributes['sambaNTPassword'][0]
		if 'sambaLMPassword' in ucs_object_attributes:
			lmPwd_ucs = ucs_object_attributes['sambaLMPassword'][0]
		if 'krb5PrincipalName' in ucs_object_attributes:
			krb5Principal = ucs_object_attributes['krb5PrincipalName'][0]
		if 'userPassword' in ucs_object_attributes:
			userPassword = ucs_object_attributes['userPassword'][0]
		sambaPwdLastSet = None
		if 'sambaPwdLastSet' in ucs_object_attributes:
			sambaPwdLastSet = ucs_object_attributes['sambaPwdLastSet'][0]
		ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: sambaPwdLastSet: %s" % sambaPwdLastSet)
		sambaPwdMustChange = ''
		if 'sambaPwdMustChange' in ucs_object_attributes:
			sambaPwdMustChange = ucs_object_attributes['sambaPwdMustChange'][0]
			ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: Found sambaPwdMustChange: %s" % sambaPwdMustChange)
		krb5Key_ucs = ucs_object_attributes.get('krb5Key', [])
		userPassword_ucs = ucs_object_attributes.get('userPassword', [None])[0]
		krb5KeyVersionNumber = ucs_object_attributes.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}'))
		else:
			ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: No password change to sync to UCS")

		try:
			old_pwdLastSet = object['old_s4_object']['pwdLastSet'][0]
		except (KeyError, IndexError):
			old_pwdLastSet = None

		if pwdLastSet != old_pwdLastSet:
			ud.debug(ud.LDAP, ud.ALL, "password_sync_s4_to_ucs: updating shadowLastChange")
			old_shadowLastChange = ucs_object_attributes.get('shadowLastChange', [None])[0]
			new_shadowLastChange = old_shadowLastChange

			# shadowMax (set to value of univentionPWExpiryInterval, otherwise delete)
			# krb5PasswordEnd (set to today + univentionPWExpiryInterval, otherwise delete)
			old_shadowMax = ucs_object_attributes.get('shadowMax', [None])[0]
			new_shadowMax = old_shadowMax
			old_krb5end = ucs_object_attributes.get('krb5PasswordEnd', [None])[0]
			new_krb5end = old_krb5end

			pwdLastSet_unix = univention.s4connector.s4.s42samba_time(pwdLastSet)
			newSambaPwdLastSet = str(pwdLastSet_unix)

			if pwdLastSet == 0:  # pwd change on next login
				new_shadowMax = '1'
				expiry = int(time.time())
				new_krb5end = time.strftime("%Y%m%d000000Z", time.gmtime(expiry))
			else:                # not pwd change on next login
				new_shadowLastChange = str(pwdLastSet_unix / 3600 / 24)
				userobject = s4connector.get_ucs_object(key, 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

				pwhistoryPolicy = userobject.loadPolicyObject('policies/pwhistory')
				try:
					expiryInterval = int(pwhistoryPolicy['expiryInterval'])
				except (TypeError, ValueError):
					# expiryInterval is empty or no legal int-string
					pwhistoryPolicy['expiryInterval'] = ''
					expiryInterval = -1

				ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: password expiryInterval for %s is %s" % (ucs_object['dn'], expiryInterval))
				if expiryInterval in (-1, 0):
					new_shadowMax = ''
					new_krb5end = ''
				else:
					new_shadowMax = str(expiryInterval)
					new_krb5end = time.strftime("%Y%m%d000000Z", time.gmtime((pwdLastSet_unix + (int(expiryInterval) * 3600 * 24))))

			if new_shadowLastChange != old_shadowLastChange:
				ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: update shadowLastChange to %s for %s" % (new_shadowLastChange, ucs_object['dn']))
				modlist.append(('shadowLastChange', old_shadowLastChange, new_shadowLastChange))
			if new_shadowMax != old_shadowMax:
				ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: update shadowMax to %s for %s" % (new_shadowMax, ucs_object['dn']))
				modlist.append(('shadowMax', old_shadowMax, new_shadowMax))
			if new_krb5end != old_krb5end:
				ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: update krb5PasswordEnd to %s for %s" % (new_krb5end, ucs_object['dn']))
				modlist.append(('krb5PasswordEnd', old_krb5end, new_krb5end))

			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:
				modlist.append(('sambaPwdMustChange', sambaPwdMustChange, ''))
				ud.debug(ud.LDAP, ud.INFO, "password_sync_s4_to_ucs: Removing sambaPwdMustChange")

		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 calculate_krb5keys(supplementalCredentialsblob):
    spl = supplementalCredentialsblob
    #cleartext_hex = None
    keys = []
    keytypes = []
    kvno = 0
    context = heimdal.context()
    #	for i in range(0, spl.sub.num_packages):
    #		pkg = spl.sub.packages[i]
    #		if pkg.name != "Primary:CLEARTEXT":
    #			continue
    #		cleartext_hex = pkg.data

    krb5_old_hex = None

    for i in range(0, spl.sub.num_packages):
        pkg = spl.sub.packages[i]
        if pkg.name != "Primary:Kerberos":
            continue
        krb5_old_hex = pkg.data

    if krb5_old_hex is not None:
        krb5_old_raw = binascii.a2b_hex(krb5_old_hex)
        krb5_old = ndr_unpack(drsblobs.package_PrimaryKerberosBlob,
                              krb5_old_raw,
                              allow_remaining=True)
        assert krb5_old.version == 3
        for k in krb5_old.ctr.keys:
            if k.keytype not in keytypes:
                ud.debug(ud.LDAP, ud.INFO,
                         "calculate_krb5key: ctr3.key.keytype: %s" % k.keytype)
                try:
                    key = heimdal.keyblock_raw(context, k.keytype, k.value)
                    krb5SaltObject = heimdal.salt_raw(context,
                                                      krb5_old.ctr.salt.string)
                    keys.append(
                        heimdal.asn1_encode_key(key, krb5SaltObject, kvno))
                    keytypes.append(k.keytype)
                except:
                    if k.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) for this
                        ud.debug(
                            ud.LDAP, ud.INFO,
                            "calculate_krb5key: ignoring unknown key with special keytype %s in %s"
                            % (k.keytype, pkg.name))
                    else:
                        traceback.print_exc()
                        ud.debug(
                            ud.LDAP, ud.ERROR,
                            "calculate_krb5key: krb5Key with keytype %s could not be parsed in %s. Ignoring this keytype."
                            % (k.keytype, pkg.name))

    krb5_new_hex = None

    for i in range(0, spl.sub.num_packages):
        pkg = spl.sub.packages[i]
        if pkg.name != "Primary:Kerberos-Newer-Keys":
            continue
        krb5_new_hex = pkg.data

    if krb5_new_hex is not None:
        krb_blob = binascii.unhexlify(krb5_new_hex)
        krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
        assert krb.version == 4

        for k in krb.ctr.keys:
            if k.keytype not in keytypes:
                ud.debug(ud.LDAP, ud.INFO,
                         "calculate_krb5key: ctr4.key.keytype: %s" % k.keytype)
                try:
                    key = heimdal.keyblock_raw(context, k.keytype, k.value)
                    krb5SaltObject = heimdal.salt_raw(context,
                                                      krb.ctr.salt.string)
                    keys.append(
                        heimdal.asn1_encode_key(key, krb5SaltObject, kvno))
                    keytypes.append(k.keytype)
                except:
                    if k.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) for this
                        ud.debug(
                            ud.LDAP, ud.INFO,
                            "calculate_krb5key: ignoring unknown key with special keytype %s in %s"
                            % (k.keytype, pkg.name))
                    else:
                        traceback.print_exc()
                        ud.debug(
                            ud.LDAP, ud.ERROR,
                            "calculate_krb5key: krb5Key with keytype %s could not be parsed in %s. Ignoring this keytype."
                            % (k.keytype, pkg.name))
    return keys
Пример #30
0
def lockout_sync_ucs_to_s4(s4connector, key, object):
	"""
	Sync unlock *modification* from OpenLDAP to Samba/AD:
		sync OpenLDAP ("L" not in sambaAcctFlags) ->  Samba/AD lockoutTime = 0

		sync OpenLDAP ("L" in sambaAcctFlags) ->  Samba/AD lockoutTime = sambaBadPasswordTime
		and  OpenLDAP sambaBadPasswordTime    ->  Samba/AD badPasswordTime
	"""
	function_name = 'lockout_sync_ucs_to_s4'
	_d = ud.function('ldap.s4.%s' % function_name)
	ud.debug(ud.LDAP, ud.INFO, "%s called" % function_name)

	if object['modtype'] not in ('modify', 'add'):
		return

	new_ucs_object = object.get('new_ucs_object', {})
	if not new_ucs_object:
		# only set by sync_from_ucs in MODIFY case
		return

	old_ucs_object = object.get('old_ucs_object', {})
	if not old_ucs_object:
		# only set by sync_from_ucs in MODIFY case
		return

	new_sambaAcctFlags = new_ucs_object.get('sambaAcctFlags', [''])[0]
	is_locked = "L" in new_sambaAcctFlags

	old_sambaAcctFlags = old_ucs_object.get('sambaAcctFlags', [''])[0]
	was_locked = "L" in old_sambaAcctFlags

	if is_locked == was_locked:
		# Require a change in the pickled state
		return

	modlist = []
	if not is_locked:
		s4_object_attributes = s4connector.lo_s4.get(compatible_modstring(object['dn']), ['lockoutTime', 'badPasswordTime'])
		if 'lockoutTime' not in s4_object_attributes:
			return

		lockoutTime = s4_object_attributes['lockoutTime'][0]
		if lockoutTime == "0":
			return

		# Now object.get('new_ucs_object') may be a stale pickled state, so let's lookup the current OpenLDAP object state
		# Unfortunately "object" doesn't hold the current OpenLDAP DN, so we need to map back first
		ucs_object = s4connector._object_mapping(key, object)
		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]

		if "L" in sambaAcctFlags:
			## currently locked again
			return

		sambaBadPasswordTime = ucs_object_attributes.get('sambaBadPasswordTime', [''])[0]
		if sambaBadPasswordTime and sambaBadPasswordTime != "0":
			ud.debug(ud.LDAP, ud.ERROR, "%s: The UCS object (%s) is unlocked, but sambaBadPasswordTime is set." % (function_name, ucs_object['dn']))
			return

		# Ok here we have:
		# 1. Account currently not locked in OpenLDAP but in Samba/AD
		# 2. Lockout state has changed to unlocked at some pickled point in the past
		modlist.append((ldap.MOD_REPLACE, "lockoutTime", "0"))
		modlist.append((ldap.MOD_REPLACE, "badPasswordTime", "0"))
		ud.debug(ud.LDAP, ud.PROCESS, "%s: Marking account as unlocked in Samba/AD" % (function_name,))
	else:
		s4_object_attributes = s4connector.lo_s4.get(compatible_modstring(object['dn']), ['lockoutTime', 'badPasswordTime'])
		lockoutTime = s4_object_attributes.get('lockoutTime', ['0'])[0]

		# Now object.get('new_ucs_object') may be a stale pickled state, so let's lookup the current OpenLDAP object state
		# Unfortunately "object" doesn't hold the current OpenLDAP DN, so we need to map back first
		ucs_object = s4connector._object_mapping(key, object)
		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]
		if "L" not in sambaAcctFlags:
			## currently not locked any longer
			return

		sambaBadPasswordTime = ucs_object_attributes.get('sambaBadPasswordTime', [''])[0]
		if not sambaBadPasswordTime:
			ud.debug(ud.LDAP, ud.ERROR, "%s: The UCS object (%s) is locked, but sambaBadPasswordTime is missing." % (function_name, ucs_object['dn']))
			return
		if sambaBadPasswordTime == "0":
			ud.debug(ud.LDAP, ud.ERROR, "%s: The UCS object (%s) is locked, but sambaBadPasswordTime is 0." % (function_name, ucs_object['dn']))
			return
		if sambaBadPasswordTime == lockoutTime:
			## already locked
			return

		# Ok here we have:
		# 1. Account currently locked in OpenLDAP but not in Samba/AD
		# 2. Lockout state has changed to locked at some pickled point in the past
		modlist.append((ldap.MOD_REPLACE, "lockoutTime", sambaBadPasswordTime))
		modlist.append((ldap.MOD_REPLACE, "badPasswordTime", sambaBadPasswordTime))
		ud.debug(ud.LDAP, ud.PROCESS, "%s: Marking account as locked in Samba/AD" % (function_name,))
		ud.debug(ud.LDAP, ud.INFO, "%s: Setting lockoutTime to the value of sambaBadPasswordTime: %s" % (function_name, sambaBadPasswordTime))

	if modlist:
		ud.debug(ud.LDAP, ud.ALL, "%s: modlist: %s" % (function_name, modlist))
		s4connector.lo_s4.lo.modify_ext_s(compatible_modstring(object['dn']), modlist)
Пример #31
0
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:
                if ucs_time > 0:
                    s4_time = str(_s2nano(ucs_time) * -1)
                else:
                    s4_time = "0"
                ml.append((ldap.MOD_REPLACE, s4_attr, [s4_time]))

        sync_integers = [('sambaPwdHistoryLength', 'pwdHistoryLength'),
                         ('sambaMinPwdLength', 'minPwdLength'),
                         ('univentionSamba4pwdProperties', 'pwdProperties')]
        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 password_sync_ucs(connector, key, object):
    _d = ud.function('ldap.ad.password_sync_ucs')  # noqa: F841
    # externes Programm zum Überptragen des Hash aufrufen
    # per ldapmodify pwdlastset auf -1 setzen

    compatible_modstring = univention.connector.ad.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 = connector._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 = connector.lo.lo.search(
            base=ucs_object['dn'],
            scope='base',
            attr=['sambaLMPassword', 'sambaNTPassword', 'sambaPwdLastSet'])
    except ldap.NO_SUCH_OBJECT:
        ud.debug(
            ud.LDAP, ud.PROCESS,
            "password_sync_ucs: The UCS object (%s) was not found. The object was removed."
            % ucs_object['dn'])
        return

    sambaPwdLastSet = None
    if 'sambaPwdLastSet' in res[0][1]:
        sambaPwdLastSet = int(res[0][1]['sambaPwdLastSet'][0])
    ud.debug(ud.LDAP, ud.INFO,
             "password_sync_ucs: sambaPwdLastSet: %s" % sambaPwdLastSet)

    pwd = None
    if 'sambaNTPassword' in res[0][1]:
        pwd = res[0][1]['sambaNTPassword'][0]
    else:
        pwd = 'NO PASSWORDXXXXXX'
        ud.debug(ud.LDAP, ud.WARN,
                 "password_sync_ucs: Failed to get NT Hash from UCS")

    if pwd in ['NO PASSWORDXXXXXX', 'NO PASSWORD*********************']:
        ud.debug(
            ud.LDAP, ud.PROCESS,
            "The sambaNTPassword hash is set to %s. Skip the synchronisation of this hash to AD."
            % pwd)

    res = connector.lo_ad.lo.search_s(
        univention.connector.ad.compatible_modstring(object['dn']),
        ldap.SCOPE_BASE, '(objectClass=*)', ['pwdLastSet', 'objectSid'])
    pwdLastSet = None
    if 'pwdLastSet' in res[0][1]:
        pwdLastSet = int(res[0][1]['pwdLastSet'][0])
    ud.debug(ud.LDAP, ud.INFO,
             "password_sync_ucs: pwdLastSet from AD : %s" % pwdLastSet)
    if 'objectSid' in res[0][1]:
        str(
            univention.connector.ad.decode_sid(
                res[0][1]['objectSid'][0]).split('-')[-1])

    # Only sync passwords from UCS to AD when the password timestamp in UCS is newer
    if connector.baseConfig.is_true(
            '%s/ad/password/timestamp/check' % connector.CONFIGBASENAME,
            False):
        ad_password_last_set = 0
        # If sambaPwdLast was set to 1 the password must be changed on next login. In this
        # case the timestamp is ignored and the password will be synced. This behavior can
        # be disabled by setting connector/ad/password/timestamp/syncreset/ucs to false. This
        # might be necessary if the connector is configured in read mode and the password will be
        # synced in two ways: Bug #22653
        if sambaPwdLastSet > 1 or (
                sambaPwdLastSet <= 2 and connector.baseConfig.is_false(
                    '%s/ad/password/timestamp/syncreset/ucs' %
                    connector.CONFIGBASENAME, False)):
            ad_password_last_set = univention.connector.ad.ad2samba_time(
                pwdLastSet)
            if sambaPwdLastSet:
                if int(ad_password_last_set) >= int(sambaPwdLastSet):
                    # skip
                    ud.debug(
                        ud.LDAP, ud.PROCESS,
                        "password_sync: Don't sync the password from UCS to AD because the AD password equal or is newer."
                    )
                    ud.debug(
                        ud.LDAP, ud.INFO,
                        "password_sync:  AD pwdlastset: %s (original (%s))" %
                        (ad_password_last_set, pwdLastSet))
                    ud.debug(
                        ud.LDAP, ud.INFO, "password_sync: UCS pwdlastset: %s" %
                        (sambaPwdLastSet))
                    return

        ud.debug(ud.LDAP, ud.INFO,
                 "password_sync: Sync the passwords from UCS to AD.")
        ud.debug(
            ud.LDAP, ud.INFO,
            "password_sync:  AD pwdlastset: %s (original (%s))" %
            (ad_password_last_set, pwdLastSet))
        ud.debug(ud.LDAP, ud.INFO,
                 "password_sync: UCS pwdlastset: %s" % (sambaPwdLastSet))

    pwd_set = False
    try:
        nt_hash, krb5Key = get_password_from_ad(
            connector,
            univention.connector.ad.compatible_modstring(object['dn']))
    except NTSTATUSError as e:
        ud.debug(
            ud.LDAP, ud.PROCESS,
            "password_sync_ucs: get_password_from_ad failed with %s, retry with reconnect"
            % str(e))
        nt_hash, krb5Key = get_password_from_ad(
            connector,
            univention.connector.ad.compatible_modstring(object['dn']),
            reconnect=True)

    if not nt_hash:
        ud.debug(ud.LDAP, ud.INFO,
                 "password_sync_ucs: No password hash could be read from AD")
    res = ''

    ud.debug(ud.LDAP, ud.INFO,
             "password_sync_ucs: Hash AD: %s Hash UCS: %s" % (nt_hash, pwd))
    if not pwd == nt_hash:
        ud.debug(ud.LDAP, ud.INFO,
                 "password_sync_ucs: Hash AD and Hash UCS differ")
        pwd_set = True

        try:
            res = set_password_in_ad(connector,
                                     object['attributes']['sAMAccountName'][0],
                                     pwd)
        except NTSTATUSError as e:
            ud.debug(
                ud.LDAP, ud.PROCESS,
                "password_sync: set_password_in_ad failed with %s, retry with reconnect"
                % str(e))
            res = set_password_in_ad(connector,
                                     object['attributes']['sAMAccountName'][0],
                                     pwd,
                                     reconnect=True)

    newpwdlastset = "-1"  # if pwd was set in ad we need to set pwdlastset to -1 or it will be 0
    # if sambaPwdMustChange >= 0 and sambaPwdMustChange < time.time():
    # password expired, must be changed on next login
    #	ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs: samba pwd expired, set newpwdLastSet to 0")
    #	newpwdlastset = "0"
    if sambaPwdLastSet <= 1:
        newpwdlastset = "0"  # User must change his password
    elif pwdLastSet and int(pwdLastSet) > 0 and not pwd_set:
        newpwdlastset = "1"
    if int(newpwdlastset) != 1:
        ud.debug(
            ud.LDAP, ud.INFO,
            "password_sync_ucs: pwdlastset in modlist: %s" % newpwdlastset)
        connector.lo_ad.lo.modify_s(compatible_modstring(
            object['dn']), [(ldap.MOD_REPLACE, 'pwdlastset', newpwdlastset)])
    else:
        ud.debug(ud.LDAP, ud.INFO,
                 "password_sync_ucs: don't modify pwdlastset")
Пример #33
0
def sid_to_ucs(s4connector, key, s4_object):
    ud.debug(ud.LDAP, ud.INFO, "sid_to_ucs S4 object: %s" % s4_object)
    ud.debug(ud.LDAP, ud.INFO, "sid_to_ucs S4 key: %s" % key)

    sidAttribute = 'sambaSID'
    if s4connector.configRegistry.is_false('connector/s4/mapping/sid', False):
        ud.debug(
            ud.LDAP, ud.INFO,
            'sid_to_ucs: SID mapping is disabled via UCR: connector/s4/mapping/sid'
        )
        sidAttribute = 'univentionSamba4SID'
    else:
        # This case will be handled by direct mapping
        return

    # modlist
    ml = []

    # object dn is already mapped to the UCS DN:
    if not s4_object.get('dn'):
        return  # ignore
    ucs_dn = s4_object['dn']
    ud.debug(ud.LDAP, ud.INFO, "sid_to_s4: UCS DN %s" % ucs_dn)

    if 'attributes' in s4_object and 'objectSid' in s4_object['attributes']:
        ud.debug(
            ud.LDAP, ud.INFO, 'sid_to_ucs: objectSid found: %s' %
            s4_object['attributes']['objectSid'])
    else:
        ud.debug(ud.LDAP, ud.INFO,
                 'sid_to_ucs: objectSid not found in attributes!')
        return

    (ucs_dn, ucs_attributes) = s4connector.lo.lo.search(
        base=ucs_dn, scope='base', attr=[sidAttribute, 'objectClass'])[0]

    if not ucs_dn:
        ud.debug(ud.LDAP, ud.WARN,
                 'sid_to_ucs: UCS object (%s) not found' % ucs_dn)
        return

    objectSid = s4_object['attributes'].get('objectSid')
    sambaSID = ucs_attributes.get(sidAttribute)
    if not sambaSID or objectSid != sambaSID:
        ml.append(
            (sidAttribute, sambaSID, s4_object['attributes'].get('objectSid')))
        if 'user' in s4_object['attributes'].get('objectClass', []):
            if 'sambaSamAccount' not in ucs_attributes.get('objectClass'):
                ml.append(
                    ('objectClass', ucs_attributes.get('objectClass'),
                     ucs_attributes.get('objectClass') + ['sambaSamAccount']))
        if 'group' in s4_object['attributes'].get('objectClass', []):
            if 'sambaGroupMapping' not in ucs_attributes.get('objectClass'):
                ml.append(('objectClass', ucs_attributes.get('objectClass'),
                           ucs_attributes.get('objectClass') +
                           ['sambaGroupMapping']))
    if ml:
        ud.debug(ud.LDAP, ud.INFO, 'sid_to_ucs: modlist = %s' % ml)
        s4connector.lo.lo.modify(ucs_dn, ml)

    return
def get_password_from_ad(connector, user_dn, reconnect=False):
    _d = ud.function('ldap.ad.get_password_from_ad')  # noqa: F841
    ud.debug(ud.LDAP, ud.INFO,
             "get_password_from_ad: Read password from AD: %s" % user_dn)
    nt_hash = None

    if not connector.drs or reconnect:
        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
        keys = []
        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 i.attid == drsuapi.DRSUAPI_ATTID_supplementalCredentials and connector.baseConfig.is_true(
                    '%s/ad/mapping/user/password/kerberos/enabled' %
                    connector.CONFIGBASENAME, False):
                if i.value_ctr.values:
                    for j in i.value_ctr.values:
                        ud.debug(
                            ud.LDAP, ud.INFO,
                            "get_password_from_ad: Found supplementalCredentials blob"
                        )
                        spl = decrypt_supplementalCredentials(
                            connector, j.blob)
                        keys = calculate_krb5keys(spl)

        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, keys
Пример #35
0
def sid_to_ucs_mapping(s4connector, key, s4_object):
    ud.debug(ud.LDAP, ud.INFO, "sid_to_ucs_mapping")
    object_sid = s4_object['attributes']['objectSid'][0]
    return object_sid.split('-')[-1]
Пример #36
0
def calculate_supplementalCredentials(ucs_krb5key, old_supplementalCredentials):

	old_krb = {}
	if old_supplementalCredentials:
		sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, old_supplementalCredentials)

		for p in sc.sub.packages:
			ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: parsing %s blob" % p.name)
			if p.name == "Primary:Kerberos":
				krb_blob = binascii.unhexlify(p.data)
				try:
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 3
					old_krb['ctr3'] = krb.ctr
					for k in krb.ctr.keys:	
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: ctr3.key.keytype: %s" % k.keytype)
				except:
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: ndr_unpack of S4 Primary:Kerberos blob failed. Traceback:")
					traceback.print_exc()
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: Continuing anyway, Primary:Kerberos (DES keys) blob will be missing in supplementalCredentials ctr3.old_keys.")
			elif p.name == "Primary:Kerberos-Newer-Keys":
				krb_blob = binascii.unhexlify(p.data)
				try:
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 4
					old_krb['ctr4'] = krb.ctr
					for k in krb.ctr.keys:	
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: ctr4.key.keytype: %s" % k.keytype)
				except:
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: ndr_unpack of S4 Primary:Kerberos-Newer-Keys blob failed. Traceback:")
					traceback.print_exc()
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: Continuing anyway, Primary:Kerberos-Newer-Keys (AES and DES keys) blob will be missing in supplementalCredentials ctr4.old_keys.")

	krb5_aes256 = ''
	krb5_aes128 = ''
	krb5_des_md5 = ''
	krb5_des_crc = ''
	krb_ctr3_salt = ''
	krb_ctr4_salt = ''
	for k in ucs_krb5key:
		(keyblock, salt, kvno) = heimdal.asn1_decode_key(k)

		key_data = keyblock.keyvalue()
		saltstring = salt.saltvalue()
		enctype = keyblock.keytype()
		enctype_id = enctype.toint()
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: krb5_keytype: %s (%d)" % (enctype, enctype_id))
		if enctype_id == 18:
			krb5_aes256 = key_data
			if not krb_ctr4_salt:
				krb_ctr4_salt = saltstring
		elif enctype_id == 17:
			krb5_aes128 = key_data
			if not krb_ctr4_salt:
				krb_ctr4_salt = saltstring
		elif enctype_id == 3:
			krb5_des_md5 = key_data
			if not krb_ctr3_salt:
				krb_ctr3_salt = saltstring
		elif enctype_id == 1:
			krb5_des_crc = key_data
			if not krb_ctr3_salt:
				krb_ctr3_salt = saltstring

	## build new drsblobs.supplementalCredentialsBlob

	sc_blob = None
	cred_List = []
	package_names = []
	
	## Primary:Kerberos-Newer-Keys : AES keys
	if krb5_aes256 or krb5_aes128:
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: building Primary:Kerberos-Newer-Keys blob")
		kerberosKey4list = []
		
		if krb5_aes256:
			assert len(krb5_aes256) == 32
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 18
			next_key.value = krb5_aes256
			next_key.value_len = len(krb5_aes256)
			kerberosKey4list.append(next_key)
		if krb5_aes128:
			assert len(krb5_aes128) == 16
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 17
			next_key.value = krb5_aes128
			next_key.value_len = len(krb5_aes128)
			kerberosKey4list.append(next_key)
		if krb5_des_md5:
			assert len(krb5_des_md5) == 8
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 3
			next_key.value = krb5_des_md5
			next_key.value_len = len(krb5_des_md5)
			kerberosKey4list.append(next_key)
		if krb5_des_crc:
			assert len(krb5_des_crc) == 8
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 1
			next_key.value = krb5_des_crc
			next_key.value_len = len(krb5_des_crc)
			kerberosKey4list.append(next_key)

		salt4 = drsblobs.package_PrimaryKerberosString()
		salt4.string = krb_ctr4_salt

		ctr4 = drsblobs.package_PrimaryKerberosCtr4()
		ctr4.salt = salt4
		ctr4.num_keys = len(kerberosKey4list)
		ctr4.keys = kerberosKey4list

		if old_krb.get('ctr4'):
			## Backup old_keys to s4_old_keys
			s4_num_old_keys = old_krb['ctr4'].num_old_keys
			s4_old_keys = []
			for key in old_krb['ctr4'].old_keys:
				s4_old_keys.append(key)

			## keys -> old_keys
			if len(old_krb['ctr4'].keys) != ctr4.num_keys:
				cleaned_old_keys = []
				for key in old_krb['ctr4'].keys:
					if key.keytype == 4294967156:	## in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys filtering keytype %s from old_keys" % key.keytype)
						continue
					else:	# TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_old_keys.append(key)
					
				ctr4.old_keys = cleaned_old_keys
				ctr4.num_old_keys = len(cleaned_old_keys)
			else:
				ctr4.old_keys = old_krb['ctr4'].keys
				ctr4.num_old_keys = old_krb['ctr4'].num_keys

			## s4_old_keys -> older_keys
			if ctr4.num_old_keys != ctr4.num_older_keys:
				cleaned_older_keys = []
				for key in s4_old_keys:
					if key.keytype == 4294967156:	## in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys filtering keytype %s from older_keys" % key.keytype)
						continue
					else:	# TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_older_keys.append(key)
					
				ctr4.older_keys = cleaned_older_keys
				ctr4.num_older_keys = len(cleaned_older_keys)
			else:
				ctr4.older_keys = s4_old_keys
				ctr4.num_older_keys = s4_num_old_keys

		if ctr4.num_old_keys != 0 and ctr4.num_old_keys != ctr4.num_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_keys = %s" % ctr4.num_keys)
			for k in ctr4.keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_old_keys = %s" % ctr4.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.old_key.keytype: %s" % k.keytype)

		if ctr4.num_older_keys != 0 and ctr4.num_older_keys != ctr4.num_old_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_old_keys = %s" % ctr4.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.old_key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_older_keys = %s" % ctr4.num_older_keys)
			for k in ctr4.older_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.older_key.keytype: %s" % k.keytype)

		krb_Primary_Kerberos_Newer = drsblobs.package_PrimaryKerberosBlob()
		krb_Primary_Kerberos_Newer.version = 4
		krb_Primary_Kerberos_Newer.ctr = ctr4 

		krb_blob_Primary_Kerberos_Newer = ndr_pack(krb_Primary_Kerberos_Newer)
		creddata_Primary_Kerberos_Newer = binascii.hexlify(krb_blob_Primary_Kerberos_Newer)
		credname_Primary_Kerberos_Newer = "Primary:Kerberos-Newer-Keys"

		cred_Primary_Kerberos_Newer = drsblobs.supplementalCredentialsPackage()
		cred_Primary_Kerberos_Newer.name = credname_Primary_Kerberos_Newer
		cred_Primary_Kerberos_Newer.name_len = len(credname_Primary_Kerberos_Newer)
		cred_Primary_Kerberos_Newer.data = creddata_Primary_Kerberos_Newer
		cred_Primary_Kerberos_Newer.data_len = len(creddata_Primary_Kerberos_Newer)
		cred_Primary_Kerberos_Newer.reserved = 1
		cred_List.append(cred_Primary_Kerberos_Newer)
		package_names.append('Kerberos-Newer-Keys')

	## Primary:Kerberos : MD5 and CRC keys
	if krb5_des_md5 or krb5_des_crc:
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: building Primary:Kerberos blob")
		kerberosKey3list = []
		
		if krb5_des_md5:
			next_key = drsblobs.package_PrimaryKerberosKey3()
			next_key.keytype = 3
			next_key.value = krb5_des_md5
			next_key.value_len = len(krb5_des_md5)
			kerberosKey3list.append(next_key)
		if krb5_des_crc:
			next_key = drsblobs.package_PrimaryKerberosKey3()
			next_key.keytype = 1
			next_key.value = krb5_des_crc
			next_key.value_len = len(krb5_des_crc)
			kerberosKey3list.append(next_key)

		salt = drsblobs.package_PrimaryKerberosString()
		salt.string = krb_ctr3_salt

		ctr3 = drsblobs.package_PrimaryKerberosCtr3()
		ctr3.salt = salt
		ctr3.num_keys = len(kerberosKey3list)
		ctr3.keys = kerberosKey3list

		if old_krb.get('ctr3'):
			## keys -> old_keys
			if len(old_krb['ctr3'].keys) != ctr3.num_keys:
				cleaned_ctr3_old_keys = []
				for key in old_krb['ctr3'].keys:
					if key.keytype == 4294967156:	## in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos filtering keytype %s from old_keys" % key.keytype)
						continue
					else:	# TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_ctr3_old_keys.append(key)
					
				ctr3.old_keys = cleaned_ctr3_old_keys
				ctr3.num_old_keys = len(cleaned_ctr3_old_keys)
			else:
				ctr3.old_keys = old_krb['ctr3'].keys
				ctr3.num_old_keys = old_krb['ctr3'].num_keys

		if ctr3.num_old_keys != 0 and ctr3.num_old_keys != ctr3.num_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos num_keys = %s" % ctr3.num_keys)
			for k in ctr4.keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr3.key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos num_old_keys = %s" % ctr3.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr3.old_key.keytype: %s" % k.keytype)

		krb = drsblobs.package_PrimaryKerberosBlob()
		krb.version = 3
		krb.ctr = ctr3 
		krb3_blob = ndr_pack(krb)

		creddata_Primary_Kerberos = binascii.hexlify(krb3_blob)
		credname_Primary_Kerberos = "Primary:Kerberos"

		cred_Primary_Kerberos = drsblobs.supplementalCredentialsPackage()
		cred_Primary_Kerberos.name = credname_Primary_Kerberos
		cred_Primary_Kerberos.name_len = len(credname_Primary_Kerberos)
		cred_Primary_Kerberos.data = creddata_Primary_Kerberos
		cred_Primary_Kerberos.data_len = len(creddata_Primary_Kerberos)
		cred_Primary_Kerberos.reserved = 1
		cred_List.append(cred_Primary_Kerberos)
		package_names.append('Kerberos')

	if package_names:
		package_names_carray = (ctypes.c_char_p * len(package_names))(*package_names)
		package_names_PyCObject = _PyCObject_FromVoidPtr(ctypes.cast(package_names_carray, ctypes.POINTER(ctypes.c_char_p)), None) 
		krb_Packages = drsblobs.package_PackagesBlob() 
		krb_Packages.names = package_names_PyCObject
		krb_blob_Packages = ndr_pack(krb_Packages)
		# krb_blob_Packages = '\0'.join(package_names).encode('utf-16le')       # this pretty much simulates it
		cred_PackagesBlob_data = binascii.hexlify(krb_blob_Packages).upper()
		cred_PackagesBlob_name = "Packages"
		cred_PackagesBlob = drsblobs.supplementalCredentialsPackage()
		cred_PackagesBlob.name = cred_PackagesBlob_name
		cred_PackagesBlob.name_len = len(cred_PackagesBlob_name)
		cred_PackagesBlob.data = cred_PackagesBlob_data
		cred_PackagesBlob.data_len = len(cred_PackagesBlob_data)
		cred_PackagesBlob.reserved = 2
		cred_List.insert(-1, cred_PackagesBlob)

		sub = drsblobs.supplementalCredentialsSubBlob()
		sub.num_packages = len(cred_List)
		sub.packages = cred_List
		sub.signature = drsblobs.SUPPLEMENTAL_CREDENTIALS_SIGNATURE
		sub.prefix = drsblobs.SUPPLEMENTAL_CREDENTIALS_PREFIX

		sc = drsblobs.supplementalCredentialsBlob()
		sc.sub = sub
		sc_blob = ndr_pack(sc)

	return sc_blob
Пример #37
0
def calculate_supplementalCredentials(ucs_krb5key, old_supplementalCredentials):

	old_krb = {}
	if old_supplementalCredentials:
		sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, old_supplementalCredentials)

		for p in sc.sub.packages:
			ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: parsing %s blob" % p.name)
			if p.name == "Primary:Kerberos":
				krb_blob = binascii.unhexlify(p.data)
				try:
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 3
					old_krb['ctr3'] = krb.ctr
					for k in krb.ctr.keys:
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: ctr3.key.keytype: %s" % k.keytype)
				except:
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: ndr_unpack of S4 Primary:Kerberos blob failed. Traceback:")
					traceback.print_exc()
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: Continuing anyway, Primary:Kerberos (DES keys) blob will be missing in supplementalCredentials ctr3.old_keys.")
			elif p.name == "Primary:Kerberos-Newer-Keys":
				krb_blob = binascii.unhexlify(p.data)
				try:
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 4
					old_krb['ctr4'] = krb.ctr
					for k in krb.ctr.keys:
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: ctr4.key.keytype: %s" % k.keytype)
				except:
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: ndr_unpack of S4 Primary:Kerberos-Newer-Keys blob failed. Traceback:")
					traceback.print_exc()
					ud.debug(ud.LDAP, ud.ERROR, "calculate_supplementalCredentials: Continuing anyway, Primary:Kerberos-Newer-Keys (AES and DES keys) blob will be missing in supplementalCredentials ctr4.old_keys.")

	krb5_aes256 = ''
	krb5_aes128 = ''
	krb5_des_md5 = ''
	krb5_des_crc = ''
	krb_ctr3_salt = ''
	krb_ctr4_salt = ''
	for k in ucs_krb5key:
		(keyblock, salt, kvno) = heimdal.asn1_decode_key(k)
		key_data = keyblock.keyvalue()
		saltstring = salt.saltvalue()
		enctype = keyblock.keytype()
		enctype_id = enctype.toint()
		if enctype_id not in krb5_context.etype_ids:
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ignoring unsupported krb5_keytype: (%d)" % (enctype_id,))
			continue

		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: krb5_keytype: %s (%d)" % (enctype, enctype_id))
		if enctype_id == 18:
			krb5_aes256 = key_data
			if not krb_ctr4_salt:
				krb_ctr4_salt = saltstring
		elif enctype_id == 17:
			krb5_aes128 = key_data
			if not krb_ctr4_salt:
				krb_ctr4_salt = saltstring
		elif enctype_id == 3:
			krb5_des_md5 = key_data
			if not krb_ctr3_salt:
				krb_ctr3_salt = saltstring
		elif enctype_id == 1:
			krb5_des_crc = key_data
			if not krb_ctr3_salt:
				krb_ctr3_salt = saltstring

	# build new drsblobs.supplementalCredentialsBlob

	sc_blob = None
	cred_List = []
	package_names = []

	# Primary:Kerberos-Newer-Keys : AES keys
	if krb5_aes256 or krb5_aes128:
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: building Primary:Kerberos-Newer-Keys blob")
		kerberosKey4list = []

		if krb5_aes256:
			assert len(krb5_aes256) == 32
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 18
			next_key.value = krb5_aes256
			next_key.value_len = len(krb5_aes256)
			kerberosKey4list.append(next_key)
		if krb5_aes128:
			assert len(krb5_aes128) == 16
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 17
			next_key.value = krb5_aes128
			next_key.value_len = len(krb5_aes128)
			kerberosKey4list.append(next_key)
		if krb5_des_md5:
			assert len(krb5_des_md5) == 8
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 3
			next_key.value = krb5_des_md5
			next_key.value_len = len(krb5_des_md5)
			kerberosKey4list.append(next_key)
		if krb5_des_crc:
			assert len(krb5_des_crc) == 8
			next_key = drsblobs.package_PrimaryKerberosKey4()
			next_key.keytype = 1
			next_key.value = krb5_des_crc
			next_key.value_len = len(krb5_des_crc)
			kerberosKey4list.append(next_key)

		salt4 = drsblobs.package_PrimaryKerberosString()
		salt4.string = krb_ctr4_salt

		ctr4 = drsblobs.package_PrimaryKerberosCtr4()
		ctr4.salt = salt4
		ctr4.num_keys = len(kerberosKey4list)
		ctr4.keys = kerberosKey4list

		if old_krb.get('ctr4'):
			# Backup old_keys to s4_old_keys
			s4_num_old_keys = old_krb['ctr4'].num_old_keys
			s4_old_keys = []
			for key in old_krb['ctr4'].old_keys:
				s4_old_keys.append(key)

			# keys -> old_keys
			if len(old_krb['ctr4'].keys) != ctr4.num_keys:
				cleaned_old_keys = []
				for key in old_krb['ctr4'].keys:
					if key.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys filtering keytype %s from old_keys" % key.keytype)
						continue
					else:  # TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_old_keys.append(key)

				ctr4.old_keys = cleaned_old_keys
				ctr4.num_old_keys = len(cleaned_old_keys)
			else:
				ctr4.old_keys = old_krb['ctr4'].keys
				ctr4.num_old_keys = old_krb['ctr4'].num_keys

			# s4_old_keys -> older_keys
			if ctr4.num_old_keys != ctr4.num_older_keys:
				cleaned_older_keys = []
				for key in s4_old_keys:
					if key.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys filtering keytype %s from older_keys" % key.keytype)
						continue
					else:  # TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_older_keys.append(key)

				ctr4.older_keys = cleaned_older_keys
				ctr4.num_older_keys = len(cleaned_older_keys)
			else:
				ctr4.older_keys = s4_old_keys
				ctr4.num_older_keys = s4_num_old_keys

		if ctr4.num_old_keys != 0 and ctr4.num_old_keys != ctr4.num_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_keys = %s" % ctr4.num_keys)
			for k in ctr4.keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_old_keys = %s" % ctr4.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.old_key.keytype: %s" % k.keytype)

		if ctr4.num_older_keys != 0 and ctr4.num_older_keys != ctr4.num_old_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_old_keys = %s" % ctr4.num_old_keys)
			for k in ctr4.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.old_key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos-Newer-Keys num_older_keys = %s" % ctr4.num_older_keys)
			for k in ctr4.older_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr4.older_key.keytype: %s" % k.keytype)

		krb_Primary_Kerberos_Newer = drsblobs.package_PrimaryKerberosBlob()
		krb_Primary_Kerberos_Newer.version = 4
		krb_Primary_Kerberos_Newer.ctr = ctr4

		krb_blob_Primary_Kerberos_Newer = ndr_pack(krb_Primary_Kerberos_Newer)
		creddata_Primary_Kerberos_Newer = binascii.hexlify(krb_blob_Primary_Kerberos_Newer)
		credname_Primary_Kerberos_Newer = "Primary:Kerberos-Newer-Keys"

		cred_Primary_Kerberos_Newer = drsblobs.supplementalCredentialsPackage()
		cred_Primary_Kerberos_Newer.name = credname_Primary_Kerberos_Newer
		cred_Primary_Kerberos_Newer.name_len = len(credname_Primary_Kerberos_Newer)
		cred_Primary_Kerberos_Newer.data = creddata_Primary_Kerberos_Newer
		cred_Primary_Kerberos_Newer.data_len = len(creddata_Primary_Kerberos_Newer)
		cred_Primary_Kerberos_Newer.reserved = 1
		cred_List.append(cred_Primary_Kerberos_Newer)
		package_names.append('Kerberos-Newer-Keys')

	# Primary:Kerberos : MD5 and CRC keys
	if krb5_des_md5 or krb5_des_crc:
		ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: building Primary:Kerberos blob")
		kerberosKey3list = []

		if krb5_des_md5:
			next_key = drsblobs.package_PrimaryKerberosKey3()
			next_key.keytype = 3
			next_key.value = krb5_des_md5
			next_key.value_len = len(krb5_des_md5)
			kerberosKey3list.append(next_key)
		if krb5_des_crc:
			next_key = drsblobs.package_PrimaryKerberosKey3()
			next_key.keytype = 1
			next_key.value = krb5_des_crc
			next_key.value_len = len(krb5_des_crc)
			kerberosKey3list.append(next_key)

		salt = drsblobs.package_PrimaryKerberosString()
		salt.string = krb_ctr3_salt

		ctr3 = drsblobs.package_PrimaryKerberosCtr3()
		ctr3.salt = salt
		ctr3.num_keys = len(kerberosKey3list)
		ctr3.keys = kerberosKey3list

		if old_krb.get('ctr3'):
			# keys -> old_keys
			if len(old_krb['ctr3'].keys) != ctr3.num_keys:
				cleaned_ctr3_old_keys = []
				for key in old_krb['ctr3'].keys:
					if key.keytype == 4294967156:  # in all known cases W2k8 AD uses keytype 4294967156 (=-140L) to include the arc4 hash
						ud.debug(ud.LDAP, ud.INFO, "calculate_supplementalCredentials: Primary:Kerberos filtering keytype %s from old_keys" % key.keytype)
						continue
					else:  # TODO: can we do something better at this point to make old_keys == num_keys ?
						cleaned_ctr3_old_keys.append(key)

				ctr3.old_keys = cleaned_ctr3_old_keys
				ctr3.num_old_keys = len(cleaned_ctr3_old_keys)
			else:
				ctr3.old_keys = old_krb['ctr3'].keys
				ctr3.num_old_keys = old_krb['ctr3'].num_keys

		if ctr3.num_old_keys != 0 and ctr3.num_old_keys != ctr3.num_keys:
			# TODO: Recommended policy is to fill up old_keys to match num_keys, this will result in a traceback, can we do something better?
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos num_keys = %s" % ctr3.num_keys)
			for k in ctr3.keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr3.key.keytype: %s" % k.keytype)
			ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: Primary:Kerberos num_old_keys = %s" % ctr3.num_old_keys)
			for k in ctr3.old_keys:
				ud.debug(ud.LDAP, ud.WARN, "calculate_supplementalCredentials: ctr3.old_key.keytype: %s" % k.keytype)

		krb = drsblobs.package_PrimaryKerberosBlob()
		krb.version = 3
		krb.ctr = ctr3
		krb3_blob = ndr_pack(krb)

		creddata_Primary_Kerberos = binascii.hexlify(krb3_blob)
		credname_Primary_Kerberos = "Primary:Kerberos"

		cred_Primary_Kerberos = drsblobs.supplementalCredentialsPackage()
		cred_Primary_Kerberos.name = credname_Primary_Kerberos
		cred_Primary_Kerberos.name_len = len(credname_Primary_Kerberos)
		cred_Primary_Kerberos.data = creddata_Primary_Kerberos
		cred_Primary_Kerberos.data_len = len(creddata_Primary_Kerberos)
		cred_Primary_Kerberos.reserved = 1
		cred_List.append(cred_Primary_Kerberos)
		package_names.append('Kerberos')

	if package_names:
		krb_blob_Packages = '\0'.join(package_names).encode('utf-16le')
		cred_PackagesBlob_data = binascii.hexlify(krb_blob_Packages).upper()
		cred_PackagesBlob_name = "Packages"
		cred_PackagesBlob = drsblobs.supplementalCredentialsPackage()
		cred_PackagesBlob.name = cred_PackagesBlob_name
		cred_PackagesBlob.name_len = len(cred_PackagesBlob_name)
		cred_PackagesBlob.data = cred_PackagesBlob_data
		cred_PackagesBlob.data_len = len(cred_PackagesBlob_data)
		cred_PackagesBlob.reserved = 2
		cred_List.insert(-1, cred_PackagesBlob)

		sub = drsblobs.supplementalCredentialsSubBlob()
		sub.num_packages = len(cred_List)
		sub.packages = cred_List
		sub.signature = drsblobs.SUPPLEMENTAL_CREDENTIALS_SIGNATURE
		sub.prefix = drsblobs.SUPPLEMENTAL_CREDENTIALS_PREFIX

		sc = drsblobs.supplementalCredentialsBlob()
		sc.sub = sub
		sc_blob = ndr_pack(sc)
		ud.debug(ud.LDAP, ud.ALL, "calculate_supplementalCredentials: sc:\n%s" % ndr_print(sc))

	return sc_blob
Пример #38
0
def calculate_krb5key(unicodePwd, supplementalCredentials, kvno=0):
	up_blob = unicodePwd
	sc_blob = supplementalCredentials

	keys = []
	keytypes = []
	context = heimdal.context()

	if up_blob:
		#ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: up_blob: %s" % binascii.b2a_base64(up_blob))
		assert len(up_blob) == 16
		key = heimdal.keyblock_raw(context, 23, up_blob)
		keys.append(heimdal.asn1_encode_key(key, None, kvno))

	if sc_blob:
		#ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: sc_blob: %s" % binascii.b2a_base64(sc_blob))
		try:
			sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, sc_blob)
			for p in sc.sub.packages:
				krb = None
				ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: parsing %s blob" % p.name)
				if p.name == "Primary:Kerberos":
					krb_blob = binascii.unhexlify(p.data)
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 3

					for k in krb.ctr.keys:
						if k.keytype not in keytypes:
							ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ctr3.key.keytype: %s" % k.keytype)
							try:
								key = heimdal.keyblock_raw(context, k.keytype, k.value)
								krb5SaltObject = heimdal.salt_raw(context, krb.ctr.salt.string)
								keys.append(heimdal.asn1_encode_key(key, krb5SaltObject, kvno))
								keytypes.append(k.keytype)
							except:
								if k.keytype == 4294967156:	## in all known cases W2k8 AD uses keytype 4294967156 (=-140L) for this
									if k.value == up_blob:	## the known case
										ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ignoring arc4 NThash with special keytype %s in %s" % (k.keytype, p.name))
									else:					## unknown special case
										ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ignoring unknown key with special keytype %s in %s" % (k.keytype, p.name))
								else:
									traceback.print_exc()
									ud.debug(ud.LDAP, ud.ERROR, "calculate_krb5key: krb5Key with keytype %s could not be parsed in %s. Ignoring this keytype." % (k.keytype, p.name))

				elif p.name == "Primary:Kerberos-Newer-Keys":
					krb_blob = binascii.unhexlify(p.data)
					krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob)
					assert krb.version == 4

					for k in krb.ctr.keys:
						if k.keytype not in keytypes:
							ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ctr4.key.keytype: %s" % k.keytype)
							try:
								key = heimdal.keyblock_raw(context, k.keytype, k.value)
								krb5SaltObject = heimdal.salt_raw(context, krb.ctr.salt.string)
								keys.append(heimdal.asn1_encode_key(key, krb5SaltObject, kvno))
								keytypes.append(k.keytype)
							except:
								if k.keytype == 4294967156:	## in all known cases W2k8 AD uses keytype 4294967156 (=-140L) for this
									if k.value == up_blob:	## the known case
										ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ignoring arc4 NThash with special keytype %s in %s" % (k.keytype, p.name))
									else:					## unknown special case
										ud.debug(ud.LDAP, ud.INFO, "calculate_krb5key: ignoring unknown key with special keytype %s in %s" % (k.keytype, p.name))
								else:
									traceback.print_exc()
									ud.debug(ud.LDAP, ud.ERROR, "calculate_krb5key: krb5Key with keytype %s could not be parsed in %s. Ignoring this keytype." % (k.keytype, p.name))

		except Exception:
			import sys
			exc = sys.exc_info()[1]
			if type(exc.args) == type(()) and len(exc.args) == 2 and exc.args[1] == 'Buffer Size Error':
				ud.debug(ud.LDAP, ud.WARN, "calculate_krb5key: '%s' while unpacking supplementalCredentials:: %s" % ( exc, binascii.b2a_base64(sc_blob) ) )
				ud.debug(ud.LDAP, ud.WARN, "calculate_krb5key: the krb5Keys from the PrimaryKerberosBlob could not be parsed. Continuing anyway.")
			else:
				traceback.print_exc()
				ud.debug(ud.LDAP, ud.ERROR, "calculate_krb5key: the krb5Keys from the PrimaryKerberosBlob could not be parsed. Continuing anyway.")

	return keys
Пример #39
0
def __get_zone_name(object):
	zoneName=object['attributes'].get('zoneName')
	if not zoneName:
		ud.debug(ud.LDAP, ud.WARN, 'Failed to get zone name for object %s' % (object['dn']))
		raise 
	return zoneName
Пример #40
0
def ntsd_to_ucs(s4connector, key, s4_object):
	ud.debug(ud.LDAP, ud.INFO, "ntsd_to_ucs S4 object: %s" % s4_object)
	ud.debug(ud.LDAP, ud.INFO, "ntsd_to_ucs S4 key: %s" % key)

	# modlist
	ml = []

	# search Samba DS expicitly for hidden attribute
	# object dn is already mapped to the UCS DN:
	s4_dn = s4_object.get('dn')
	if not s4_dn:
		return  # ignore

	try:
		s4_attributes = s4connector.lo_s4.get(s4_dn, attr=['nTSecurityDescriptor'], required=True)
	except ldap.NO_SUCH_OBJECT:
		ud.debug(ud.LDAP, ud.WARN, 'ntsd_to_ucs: S4 object (%s) not found' % s4_dn)
		return

	ntsd_ndr = s4_attributes.get('nTSecurityDescriptor')
	if not ntsd_ndr:
		ud.debug(ud.LDAP, ud.INFO, 'ntsd_to_ucs: nTSecurityDescriptor not found in attributes!')
		return

	# search in UCS/OpenLDAP DS to determine modify/add
	ucs_dn = s4_dn
	try:
		ucs_attributes = s4connector.lo.get(ucs_dn, attr=['msNTSecurityDescriptor'])
	except ldap.NO_SUCH_OBJECT:
		ud.debug(ud.LDAP, ud.WARN, 'sid_to_ucs: UCS object (%s) not found' % ucs_dn)
		return

	domain_sid = security.dom_sid(s4connector.s4_sid)
	s4_ntsd_sddl = decode_sd_in_ndr_to_sddl(domain_sid, ntsd_ndr[0])
	ucs_ntsd_sddl = ucs_attributes.get('msNTSecurityDescriptor', [None])[0]
	if not ucs_ntsd_sddl or ucs_ntsd_sddl != s4_ntsd_sddl:
		ml.append(('msNTSecurityDescriptor', ucs_ntsd_sddl, s4_ntsd_sddl))
	if ml:
		ud.debug(ud.LDAP, ud.INFO, 'ntsd_to_ucs: modlist = %s' % ml)
		serverctrls = [PostReadControl(True, ['entryUUID', 'entryCSN'])]
		response = {}
		s4connector.lo.lo.modify(ucs_dn, ml, serverctrls=serverctrls, response=response)
		for c in response.get('ctrls', []):   # If the modify actually did something
			if c.controlType == PostReadControl.controlType:
				entryUUID = c.entry['entryUUID'][0]
				entryCSN = c.entry['entryCSN'][0]
				s4connector._remember_entryCSN_commited_by_connector(entryUUID, entryCSN)
Пример #41
0
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'),
                         ('domainPwdProperties', 'pwdProperties')]
        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 'msGPO' not in attr.get('objectClass', []):
                ml.append(('objectClass', '', 'msGPO'))

            ml.append(('msGPOLink', ucs_val, s4_val))

        if ml:
            s4connector.lo.modify(dn, ml)

    return True
Пример #42
0
Файл: dc.py Проект: B-Rich/smart
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
Пример #43
0
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.

import univention.debug2 as ud

ud.init( '/tmp/univention.debug2.log', 1, 1)
ud.set_level( ud.PROCESS, ud.ERROR )
ud.set_level( ud.LISTENER, ud.WARN )
ud.set_level( ud.NETWORK, ud.PROCESS )
ud.set_level( ud.LDAP, ud.INFO )
ud.set_level( ud.ADMIN, ud.ALL )

for lvl in [ ud.ERROR, ud.WARN, ud.PROCESS, ud.INFO, ud.ALL ]:
	for mod in [ ud.ADMIN, ud.PROCESS, ud.LISTENER, ud.NETWORK, ud.LDAP ]:
		ud.debug( mod, lvl, '==> send msg to %s with level %s' % (mod, lvl) )


ud.set_level( ud.ADMIN, ud.ERROR )
ud.debug( ud.ADMIN, ud.ERROR, '==> admin error' )
ud.debug( ud.ADMIN, ud.WARN, '==> admin warn' )
ud.debug( ud.ADMIN, ud.PROCESS, '==> admin process' )
ud.debug( ud.ADMIN, ud.INFO, '==> admin info' )
ud.debug( ud.ADMIN, ud.ALL, '==> admin all' )

ud.set_level( ud.LDAP, ud.INFO )
ud.debug( ud.LDAP, ud.ERROR, '==> ldap error' )
ud.debug( ud.LDAP, ud.WARN, '==> ldap warn' )
ud.debug( ud.LDAP, ud.PROCESS, '==> ldap process' )
ud.debug( ud.LDAP, ud.INFO, '==> ldap info' )
ud.debug( ud.LDAP, ud.ALL, '==> ldap all' )