s4:samldb LDB module - MS-SAMR 3.1.1.8.10 "userAccountControl"
[obnox/samba/samba-obnox.git] / source4 / dsdb / samdb / ldb_modules / samldb.c
index 5bb0b61d61a4eedba77f8c4f62a180c611a39928..603370fd6220952bdef1877890bfdb9654dc6f3e 100644 (file)
@@ -1049,6 +1049,18 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac)
                                uac_generated = true;
                        }
 
+                       /*
+                        * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
+                        */
+                       if ((user_account_control & UF_LOCKOUT) != 0) {
+                               user_account_control &= ~UF_LOCKOUT;
+                               uac_generated = true;
+                       }
+                       if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
+                               user_account_control &= ~UF_PASSWORD_EXPIRED;
+                               uac_generated = true;
+                       }
+
                        /* Temporary duplicate accounts aren't allowed */
                        if ((user_account_control & UF_TEMP_DUPLICATE_ACCOUNT) != 0) {
                                return LDB_ERR_OTHER;
@@ -1442,9 +1454,10 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
        struct ldb_message *tmp_msg;
        int ret;
        struct ldb_result *res;
-       const char * const attrs[] = { "userAccountControl", "objectClass", NULL };
+       const char * const attrs[] = { "userAccountControl", "objectClass",
+                                      "lockoutTime", NULL };
        unsigned int i;
-       bool is_computer = false;
+       bool is_computer = false, uac_generated = false;
 
        el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
                                         ac->req->operation);
@@ -1517,8 +1530,6 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
 
        account_type = ds_uf2atype(user_account_control);
        if (account_type == 0) {
-               char *tempstr;
-
                /*
                 * When there is no account type embedded in "userAccountControl"
                 * fall back to default "UF_NORMAL_ACCOUNT".
@@ -1530,18 +1541,7 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
                }
 
                user_account_control |= UF_NORMAL_ACCOUNT;
-
-               tempstr = talloc_asprintf(ac->msg, "%d", user_account_control);
-               if (tempstr == NULL) {
-                       return ldb_module_oom(ac->module);
-               }
-
-               /* Overwrite "userAccountControl" with "UF_NORMAL_ACCOUNT" added */
-               el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
-                                                ac->req->operation);
-               el->values[0].data = (uint8_t *) tempstr;
-               el->values[0].length = strlen(tempstr);
-
+               uac_generated = true;
                account_type = ATYPE_NORMAL_ACCOUNT;
        }
        ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
@@ -1552,6 +1552,41 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
        el = ldb_msg_find_element(ac->msg, "sAMAccountType");
        el->flags = LDB_FLAG_MOD_REPLACE;
 
+       /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
+       if ((user_account_control & UF_LOCKOUT) != 0) {
+               /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
+               uint64_t lockout_time = ldb_msg_find_attr_as_uint64(res->msgs[0],
+                                                                   "lockoutTime",
+                                                                   0);
+               if (lockout_time != 0) {
+                       ldb_msg_remove_attr(ac->msg, "lockoutTime");
+                       ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg,
+                                                  "lockoutTime", (NTTIME)0);
+                       if (ret != LDB_SUCCESS) {
+                               return ret;
+                       }
+                       el = ldb_msg_find_element(ac->msg, "lockoutTime");
+                       el->flags = LDB_FLAG_MOD_REPLACE;
+               }
+
+               user_account_control &= ~UF_LOCKOUT;
+               uac_generated = true;
+       }
+       if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
+               /* "pwdLastSet" reset as password expiration has been forced  */
+               ldb_msg_remove_attr(ac->msg, "pwdLastSet");
+               ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "pwdLastSet",
+                                          (NTTIME)0);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+               el = ldb_msg_find_element(ac->msg, "pwdLastSet");
+               el->flags = LDB_FLAG_MOD_REPLACE;
+
+               user_account_control &= ~UF_PASSWORD_EXPIRED;
+               uac_generated = true;
+       }
+
        /* "isCriticalSystemObject" might be set/changed */
        if (user_account_control
            & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
@@ -1595,6 +1630,21 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
                el->flags = LDB_FLAG_MOD_REPLACE;
        }
 
+       /* Propagate eventual "userAccountControl" attribute changes */
+       if (uac_generated) {
+               char *tempstr = talloc_asprintf(ac->msg, "%d",
+                                               user_account_control);
+               if (tempstr == NULL) {
+                       return ldb_module_oom(ac->module);
+               }
+
+               /* Overwrite "userAccountControl" correctly */
+               el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
+                                                ac->req->operation);
+               el->values[0].data = (uint8_t *) tempstr;
+               el->values[0].length = strlen(tempstr);
+       }
+
        return LDB_SUCCESS;
 }