]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
dsdb/auth: Use PSO settings for lockOutThreshold/Duration
authorTim Beale <timbeale@catalyst.net.nz>
Fri, 6 Apr 2018 04:42:50 +0000 (16:42 +1200)
committerGarming Sam <garming@samba.org>
Wed, 23 May 2018 04:55:30 +0000 (06:55 +0200)
If a PSO applies to a user, use its lockOutThreshold/Duration settings
instead of the domain setting. When we lookup a user, we now include the
msDS-ResultantPSO attribute. If the attribute is present for a user,
then we lookup the corresponding PSO object to get the lockOutThreshold/
Duration settings.

Note: This is not quite enough to make the PSO lockout tests pass, as
msDS-User-Account-Control-Computed is still constructed based on the
domain lockoutDuration setting rather than the PSO.

Updating the password_hash.c code properly will be done in a subsequent
commit.

Signed-off-by: Tim Beale <timbeale@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
source4/auth/sam.c
source4/dsdb/common/util.c
source4/dsdb/samdb/ldb_modules/password_hash.c

index 9d1fc650142994be1fc96a42d25c39953bacb003..22ec8cef2a1f057d9d3023946121120a61a91917 100644 (file)
@@ -103,6 +103,7 @@ const char *user_attrs[] = {
        "badPasswordTime",
        "lmPwdHistory",
        "ntPwdHistory",
+       "msDS-ResultantPSO",
        NULL,
 };
 
@@ -777,6 +778,38 @@ NTSTATUS authsam_get_user_info_dc_principal(TALLOC_CTX *mem_ctx,
        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)
@@ -790,6 +823,7 @@ NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
        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);
@@ -803,8 +837,20 @@ NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
                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;
index ed91bc725dfb78f7400fdd07f6d01b68bbff26d9..cc5890952944a067bf917376529317a0c9f097a4 100644 (file)
@@ -5266,6 +5266,39 @@ int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
        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.
  *
@@ -5278,11 +5311,16 @@ int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
  *  - 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;
@@ -5315,8 +5353,7 @@ NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
         * 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)));
@@ -5333,8 +5370,8 @@ NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
                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);
 
index 2641cb9c064f9bb44ba50d04381a779c5c1cc5dd..80e634895d50fe62e48a8cc988bf6214caca6726 100644 (file)
@@ -2533,6 +2533,7 @@ static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io
        status = dsdb_update_bad_pwd_count(io->ac, ldb,
                                           io->ac->search_res->message,
                                           io->ac->dom_res->message,
+                                          NULL, /* TODO: support PSO */
                                           &mod_msg);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;