NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
				   struct ldb_context *sam_ctx,
				   struct ldb_message *user_msg,
				   struct ldb_message *domain_msg,
				   struct ldb_message *pso_msg,
				   struct ldb_message **_mod_msg)
{
	int ret, badPwdCount;
	unsigned int i;
	int64_t lockoutThreshold, lockOutObservationWindow;
	struct dom_sid *sid;
	struct timeval tv_now = timeval_current();
	NTTIME now = timeval_to_nttime(&tv_now);
	NTSTATUS status;
	uint32_t pwdProperties, rid = 0;
	struct ldb_message *mod_msg;

	sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");

	pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
						  "pwdProperties", -1);
	if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
		status = dom_sid_split_rid(NULL, sid, NULL, &rid);
		if (!NT_STATUS_IS_OK(status)) {
			/*
			 * This can't happen anyway, but always try
			 * and update the badPwdCount on failure
			 */
			rid = 0;
		}
	}
	TALLOC_FREE(sid);

	/*
	 * Work out if we are doing password lockout on the domain.
	 * Also, the built in administrator account is exempt:
	 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
	 */
	lockoutThreshold = get_lockout_threshold(domain_msg, pso_msg);
	if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
		DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
			  ldb_dn_get_linearized(user_msg->dn)));
		return NT_STATUS_OK;
	}

	mod_msg = ldb_msg_new(mem_ctx);
	if (mod_msg == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
	if (mod_msg->dn == NULL) {
		TALLOC_FREE(mod_msg);
		return NT_STATUS_NO_MEMORY;
	}

	lockOutObservationWindow = get_lockout_observation_window(domain_msg,
								  pso_msg);

	badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);

	badPwdCount++;

	ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
	if (ret != LDB_SUCCESS) {
		TALLOC_FREE(mod_msg);
		return NT_STATUS_NO_MEMORY;
	}
	ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
	if (ret != LDB_SUCCESS) {
		TALLOC_FREE(mod_msg);
		return NT_STATUS_NO_MEMORY;
	}

	if (badPwdCount >= lockoutThreshold) {
		ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
		if (ret != LDB_SUCCESS) {
			TALLOC_FREE(mod_msg);
			return NT_STATUS_NO_MEMORY;
		}
		DEBUGC( DBGC_AUTH, 1, ("Locked out user %s after %d wrong passwords\n",
			  ldb_dn_get_linearized(user_msg->dn), badPwdCount));
	} else {
		DEBUGC( DBGC_AUTH, 5, ("Updated badPwdCount on %s after %d wrong passwords\n",
			  ldb_dn_get_linearized(user_msg->dn), badPwdCount));
	}

	/* mark all the message elements as LDB_FLAG_MOD_REPLACE */
	for (i=0; i< mod_msg->num_elements; i++) {
		mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
	}

	*_mod_msg = mod_msg;
	return NT_STATUS_OK;
}
NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
				   struct ldb_context *sam_ctx,
				   struct ldb_message *user_msg,
				   struct ldb_message *domain_msg,
				   struct ldb_message *pso_msg,
				   struct ldb_message **_mod_msg)
{
	int ret, badPwdCount;
	unsigned int i;
	int64_t lockoutThreshold, lockOutObservationWindow;
	struct dom_sid *sid;
	struct timeval tv_now = timeval_current();
	NTTIME now = timeval_to_nttime(&tv_now);
	NTSTATUS status;
	uint32_t pwdProperties, rid = 0;
	struct ldb_message *mod_msg;

	sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");

	pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
						  "pwdProperties", -1);
	if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
		status = dom_sid_split_rid(NULL, sid, NULL, &rid);
		if (!NT_STATUS_IS_OK(status)) {
			 
			rid = 0;
		}
	}
	TALLOC_FREE(sid);

	 
	lockoutThreshold = get_lockout_threshold(domain_msg, pso_msg);
	if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
		DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
			  ldb_dn_get_linearized(user_msg->dn)));
		return NT_STATUS_OK;
	}

	mod_msg = ldb_msg_new(mem_ctx);
	if (mod_msg == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
	if (mod_msg->dn == NULL) {
		TALLOC_FREE(mod_msg);
		return NT_STATUS_NO_MEMORY;
	}

	lockOutObservationWindow = get_lockout_observation_window(domain_msg,
								  pso_msg);

	badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);

	badPwdCount++;

	ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
	if (ret != LDB_SUCCESS) {
		TALLOC_FREE(mod_msg);
		return NT_STATUS_NO_MEMORY;
	}
	ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
	if (ret != LDB_SUCCESS) {
		TALLOC_FREE(mod_msg);
		return NT_STATUS_NO_MEMORY;
	}

	if (badPwdCount >= lockoutThreshold) {
		ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
		if (ret != LDB_SUCCESS) {
			TALLOC_FREE(mod_msg);
			return NT_STATUS_NO_MEMORY;
		}
		DEBUGC( DBGC_AUTH, 1, ("Locked out user %s after %d wrong passwords\n",
			  ldb_dn_get_linearized(user_msg->dn), badPwdCount));
	} else {
		DEBUGC( DBGC_AUTH, 5, ("Updated badPwdCount on %s after %d wrong passwords\n",
			  ldb_dn_get_linearized(user_msg->dn), badPwdCount));
	}

	 
	for (i=0; i< mod_msg->num_elements; i++) {
		mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
	}

	*_mod_msg = mod_msg;
	return NT_STATUS_OK;
}