"badPasswordTime",
"lmPwdHistory",
"ntPwdHistory",
+ "msDS-ResultantPSO",
NULL,
};
return NT_STATUS_OK;
}
+/*
+ * Returns the details for the Password Settings Object (PSO), if one applies
+ * the user.
+ */
+static int authsam_get_user_pso(struct ldb_context *sam_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message *user_msg,
+ struct ldb_message **pso_msg)
+{
+ const char *attrs[] = { "msDS-LockoutThreshold",
+ "msDS-LockoutObservationWindow",
+ NULL };
+ struct ldb_dn *pso_dn = NULL;
+ struct ldb_result *res = NULL;
+ int ret;
+
+ /* check if the user has a PSO that applies to it */
+ pso_dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, user_msg,
+ "msDS-ResultantPSO");
+
+ if (pso_dn != NULL) {
+ ret = dsdb_search_dn(sam_ctx, mem_ctx, &res, pso_dn, attrs, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ *pso_msg = res->msgs[0];
+ }
+
+ return LDB_SUCCESS;
+}
+
NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
struct ldb_message *msg,
struct ldb_dn *domain_dn)
NTSTATUS status;
struct ldb_result *domain_res;
struct ldb_message *msg_mod = NULL;
+ struct ldb_message *pso_msg = NULL;
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_new(msg);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
+ ret = authsam_get_user_pso(sam_ctx, mem_ctx, msg, &pso_msg);
+ if (ret != LDB_SUCCESS) {
+
+ /*
+ * fallback to using the domain defaults so that we still
+ * record the bad password attempt
+ */
+ DBG_ERR("Error (%d) checking PSO for %s",
+ ret, ldb_dn_get_linearized(msg->dn));
+ }
+
status = dsdb_update_bad_pwd_count(mem_ctx, sam_ctx,
- msg, domain_res->msgs[0], &msg_mod);
+ msg, domain_res->msgs[0], pso_msg,
+ &msg_mod);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(mem_ctx);
return status;
return dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
}
+/*
+ * Returns the lockoutThreshold that applies. If a PSO is specified, then that
+ * setting is used over the domain defaults
+ */
+static int64_t get_lockout_threshold(struct ldb_message *domain_msg,
+ struct ldb_message *pso_msg)
+{
+ if (pso_msg != NULL) {
+ return ldb_msg_find_attr_as_int(pso_msg,
+ "msDS-LockoutThreshold", 0);
+ } else {
+ return ldb_msg_find_attr_as_int(domain_msg,
+ "lockoutThreshold", 0);
+ }
+}
+
+/*
+ * Returns the lockOutObservationWindow that applies. If a PSO is specified,
+ * then that setting is used over the domain defaults
+ */
+static int64_t get_lockout_observation_window(struct ldb_message *domain_msg,
+ struct ldb_message *pso_msg)
+{
+ if (pso_msg != NULL) {
+ return ldb_msg_find_attr_as_int(pso_msg,
+ "msDS-LockoutObservationWindow",
+ 0);
+ } else {
+ return ldb_msg_find_attr_as_int(domain_msg,
+ "lockOutObservationWindow", 0);
+ }
+}
+
/*
* Prepare an update to the badPwdCount and associated attributes.
*
* - pwdProperties
* - lockoutThreshold
* - lockOutObservationWindow
+ *
+ * This also requires that the pso_msg have (if present):
+ * - msDS-LockoutThreshold
+ * - msDS-LockoutObservationWindow
*/
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 i, ret, badPwdCount;
* Also, the built in administrator account is exempt:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
*/
- lockoutThreshold = ldb_msg_find_attr_as_int(domain_msg,
- "lockoutThreshold", 0);
+ 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_NO_MEMORY;
}
- lockOutObservationWindow = ldb_msg_find_attr_as_int64(domain_msg,
- "lockOutObservationWindow", 0);
+ lockOutObservationWindow = get_lockout_observation_window(domain_msg,
+ pso_msg);
badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);