def ignore_filter_from_tmpl(template, ucr_key, default=''):
	"""
	Construct an `ignore_filter` from a `ucr_key`
	(`connector/s4/mapping/*/ignorelist`, a comma delimited list of values), as
	specified by `template` while correctly escaping the filter-expression.

	`template` must be formatted as required by `format_escaped`.

	>>> ignore_filter_from_tmpl('(cn={0!e})',
	... 'connector/s4/mapping/nonexistend/ignorelist',
	... 'one,two,three')
	'(|(cn=one)(cn=two)(cn=three))'
	"""
	variables = [v for v in configRegistry.get(ucr_key, default).split(',') if v]
	filter_parts = [format_escaped(template, v) for v in variables]
	if filter_parts:
		return '(|{})'.format(''.join(filter_parts))
	return ''
def password_sync_ucs_to_s4(s4connector, key, object):
	_d = ud.function('ldap.s4.password_sync_ucs_to_s4')
	ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4 called")

	modify = False
	old_ucs_object = object.get('old_ucs_object', {})
	new_ucs_object = object.get('new_ucs_object', {})
	if old_ucs_object or new_ucs_object:
		for attr in ['sambaLMPassword', 'sambaNTPassword', 'sambaPwdLastSet', 'sambaPwdMustChange', 'krb5PrincipalName', 'krb5Key', 'shadowLastChange', 'shadowMax', 'krb5PasswordEnd', 'univentionService']:
			old_values = set(old_ucs_object.get(attr, []))
			new_values = set(new_ucs_object.get(attr, []))
			if old_values != new_values:
				modify = True
				break
	else:
		# add mode
		modify = True

	if not modify:
		ud.debug(ud.LDAP, ud.INFO, 'password_sync_ucs_to_s4: the password for %s has not been changed. Skipping password sync.' % (object['dn']))
		return

	try:
		ud.debug(ud.LDAP, ud.INFO, "Object DN=%s" % object['dn'])
	except:  # FIXME: which exception is to be caught?
		ud.debug(ud.LDAP, ud.INFO, "Object DN not printable")

	ucs_object = s4connector._object_mapping(key, object, 'con')

	try:
		ud.debug(ud.LDAP, ud.INFO, "   UCS DN = %s" % ucs_object['dn'])
	except:  # FIXME: which exception is to be caught?
		ud.debug(ud.LDAP, ud.INFO, "   UCS DN not printable")

	try:
		ucs_object_attributes = s4connector.lo.get(ucs_object['dn'], ['sambaLMPassword', 'sambaNTPassword', 'sambaPwdLastSet', 'sambaPwdMustChange', 'krb5PrincipalName', 'krb5Key', 'shadowLastChange', 'shadowMax', 'krb5PasswordEnd', 'univentionService'], required=True)
	except ldap.NO_SUCH_OBJECT:
		ud.debug(ud.LDAP, ud.PROCESS, "password_sync_ucs_to_s4: The UCS object (%s) was not found. The object was removed." % ucs_object['dn'])
		return

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

	sambaPwdLastSet = None
	if 'sambaPwdLastSet' in ucs_object_attributes:
		sambaPwdLastSet = long(ucs_object_attributes['sambaPwdLastSet'][0])
	ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaPwdLastSet: %s" % sambaPwdLastSet)

	if 'sambaPwdMustChange' in ucs_object_attributes:
		sambaPwdMustChange = long(ucs_object_attributes['sambaPwdMustChange'][0])
		ud.debug(ud.LDAP, ud.WARN, "password_sync_ucs_to_s4: Ignoring sambaPwdMustChange: %s" % sambaPwdMustChange)

	ucsLMhash = ucs_object_attributes.get('sambaLMPassword', [None])[0]
	ucsNThash = ucs_object_attributes.get('sambaNTPassword', [None])[0]
	krb5Principal = ucs_object_attributes.get('krb5PrincipalName', [None])[0]
	krb5Key = ucs_object_attributes.get('krb5Key', [])

	if not ucsNThash:
		ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaNTPassword missing in UCS LDAP, trying krb5Key")
		ucsNThash = extract_NThash_from_krb5key(krb5Key)

	if not ucsNThash:
		ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get NT Password-Hash from UCS LDAP")

	# ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Password-Hash from UCS: %s" % ucsNThash)

	s4_object_attributes = s4connector.lo_s4.get(compatible_modstring(object['dn']), ['pwdLastSet', 'objectSid'])
	pwdLastSet = None
	if 'pwdLastSet' in s4_object_attributes:
		pwdLastSet = long(s4_object_attributes['pwdLastSet'][0])
	objectSid = univention.s4connector.s4.decode_sid(s4_object_attributes['objectSid'][0])
	ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdLastSet from S4 : %s" % pwdLastSet)
	# rid = None
	# if s4_object_attributes.has_key('objectSid'):
	# 	rid = str(univention.s4connector.s4.decode_sid(s4_object_attributes['objectSid'][0]).split('-')[-1])

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

	unicodePwd_attr = s4_search_attributes.get('unicodePwd', [None])[0]
	dBCSPwd_attr = s4_search_attributes.get('dBCSPwd', [None])[0]
	userPrincipalName_attr = s4_search_attributes.get('userPrincipalName', [None])[0]
	supplementalCredentials = s4_search_attributes.get('supplementalCredentials', [None])[0]
	msDS_KeyVersionNumber = s4_search_attributes.get('msDS-KeyVersionNumber', [0])[0]
	# ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Password-Hash from S4: %s" % unicodePwd_attr)

	s4NThash = None
	if unicodePwd_attr:
		s4NThash = binascii.b2a_hex(unicodePwd_attr).upper()
	else:
		ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get NT Password-Hash from S4")

	s4LMhash = None
	if dBCSPwd_attr:
		s4LMhash = binascii.b2a_hex(dBCSPwd_attr).upper()
	else:
		ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: Failed to get LM Password-Hash from S4")

	modlist = []
	if krb5Principal != userPrincipalName_attr:
		if krb5Principal:
			if not userPrincipalName_attr:  # new and not old
				modlist.append((ldap.MOD_ADD, 'userPrincipalName', krb5Principal))
			else:  # new and old differ
				if krb5Principal.lower() != userPrincipalName_attr.lower():
					ud.debug(ud.LDAP, ud.WARN, "password_sync_ucs_to_s4: userPrincipalName != krb5Principal: '%s' != '%s'" % (userPrincipalName_attr, krb5Principal))
				modlist.append((ldap.MOD_REPLACE, 'userPrincipalName', krb5Principal))
		else:
			if userPrincipalName_attr:  # old and not new
				modlist.append((ldap.MOD_DELETE, 'userPrincipalName', userPrincipalName_attr))

	if not ucsNThash == s4NThash:
		ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: NT Hash S4: %s NT Hash UCS: %s" % (s4NThash, ucsNThash))
		# Now if ucsNThash is empty there should at least some timestamp in UCS,
		# otherwise it's probably not a good idea to remove the unicodePwd.
		# Usecase: LDB module on ucs_3.0-0-ucsschool slaves creates XP computers/windows in UDM without password
		if ucsNThash or sambaPwdLastSet:
			pwd_set = True
			unicodePwd_new = None
			if ucsNThash:
				try:
					unicodePwd_new = binascii.a2b_hex(ucsNThash)
				except TypeError as exc:
					if ucsNThash.startswith("NO PASSWORD"):
						pwd_set = False
					else:
						raise
			if pwd_set:
				if unicodePwd_attr:
					modlist.append((ldap.MOD_DELETE, 'unicodePwd', unicodePwd_attr))
				if unicodePwd_new:
					modlist.append((ldap.MOD_ADD, 'unicodePwd', unicodePwd_new))

	if not ucsLMhash == s4LMhash:
		ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: LM Hash S4: %s LM Hash UCS: %s" % (s4LMhash, ucsLMhash))
		pwd_set = True
		if dBCSPwd_attr:
			modlist.append((ldap.MOD_DELETE, 'dBCSPwd', dBCSPwd_attr))
		if ucsLMhash:
			dBCSPwd_new = binascii.a2b_hex(ucsLMhash)
			modlist.append((ldap.MOD_ADD, 'dBCSPwd', dBCSPwd_new))

	if pwd_set or not supplementalCredentials:
		if krb5Principal:
			# encoding of Samba4 supplementalCredentials
			if supplementalCredentials:
				modlist.append((ldap.MOD_DELETE, 'supplementalCredentials', supplementalCredentials))
			if krb5Key:
				supplementalCredentials_new = calculate_supplementalCredentials(krb5Key, supplementalCredentials)
				if supplementalCredentials_new:
					modlist.append((ldap.MOD_ADD, 'supplementalCredentials', supplementalCredentials_new))
				else:
					ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: no supplementalCredentials_new")
				# if supplementalCredentials:
				#	modlist.append((ldap.MOD_REPLACE, 'msDS-KeyVersionNumber', krb5KeyVersionNumber))
				# else:
				#	modlist.append((ldap.MOD_ADD, 'msDS-KeyVersionNumber', krb5KeyVersionNumber))

		if sambaPwdLastSet is None:
			sambaPwdLastSet = int(time.time())
			newpwdlastset = str(univention.s4connector.s4.samba2s4_time(sambaPwdLastSet))
		elif sambaPwdLastSet in [0, 1]:
			ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: samba pwd expired, set newpwdLastSet to 0")
			newpwdlastset = 0
		else:
			newpwdlastset = univention.s4connector.s4.samba2s4_time(sambaPwdLastSet)
		ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdLastSet in modlist: %s" % newpwdlastset)
		modlist.append((ldap.MOD_REPLACE, 'pwdLastSet', str(newpwdlastset)))
		modlist.append((ldap.MOD_REPLACE, 'badPwdCount', '0'))
		modlist.append((ldap.MOD_REPLACE, 'badPasswordTime', '0'))
		modlist.append((ldap.MOD_REPLACE, 'lockoutTime', '0'))

	else:
		ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: No password change to sync to S4 ")

		# check pwdLastSet
		if sambaPwdLastSet is not None:
			if sambaPwdLastSet in [0, 1]:
				newpwdlastset = 0
			else:
				newpwdlastset = univention.s4connector.s4.samba2s4_time(sambaPwdLastSet)
			ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: sambaPwdLastSet: %d" % sambaPwdLastSet)
			ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: newpwdlastset  : %s" % newpwdlastset)
			ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: pwdLastSet (AD): %s" % pwdLastSet)
			if newpwdlastset != pwdLastSet and abs(newpwdlastset - pwdLastSet) >= 10000000:
				modlist.append((ldap.MOD_REPLACE, 'pwdLastSet', str(newpwdlastset)))

	# TODO: Password History
	ctrl_bypass_password_hash = LDAPControl('1.3.6.1.4.1.7165.4.3.12', criticality=0)
	ud.debug(ud.LDAP, ud.INFO, "password_sync_ucs_to_s4: modlist: %s" % modlist)
	if modlist:
		s4connector.lo_s4.lo.modify_ext_s(compatible_modstring(object['dn']), modlist, serverctrls=[ctrl_bypass_password_hash])
def 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 = long(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 = long(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('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

				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 con2ucs(s4connector, key, object):

    ud.debug(ud.LDAP, ud.INFO,
             'dc con2ucs: Object (%s): %s' % (object['dn'], object))

    # Search sambaDomainname object via sambaSID
    object_sid = decode_sid(object['attributes']['objectSid'][0])
    sambadomainnameObject = univention.admin.handlers.settings.sambadomain.lookup(
        None, s4connector.lo, format_escaped('sambaSID={0!e}', object_sid))

    if len(sambadomainnameObject) > 1:
        ud.debug(
            ud.LDAP, ud.WARN,
            'dc con2ucs: Found more than one sambaDomainname object with sambaSID %r'
            % (object_sid, ))
    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(
                int(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.decode('UTF-8')
                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 b'msGPO' not in attr.get('objectClass', []):
                ml.append(('objectClass', b'', b'msGPO'))

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

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

    return True