TODO s4:dsdb/password_hash: implement pwdLastSet constraints
authorStefan Metzmacher <metze@samba.org>
Fri, 14 Mar 2014 14:59:04 +0000 (15:59 +0100)
committerStefan Metzmacher <metze@samba.org>
Sun, 29 Jun 2014 21:45:26 +0000 (23:45 +0200)
"pwdLastSet" can only be set to "0" or "-1", while
"-1" is translated into the current timestamp.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=9654

Change-Id: Icd1aa8bce45b0d9972ee175c40600c7014f032bd

source4/dsdb/samdb/ldb_modules/password_hash.c

index f8114634441f85d6780e7c3ed58f9434d70e618e..7977dab3c112ef0af63b45a3c4d4a0221801fc25 100644 (file)
 /* Notice: Definition of "dsdb_control_password_change_status" moved into
  * "samdb.h" */
 
+static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
+                                       const char *name,
+                                       enum ldb_request_type operation,
+                                       const struct ldb_val **new_val,
+                                       const struct ldb_val **old_val);
+
 struct ph_context {
        struct ldb_module *module;
        struct ldb_request *req;
@@ -1680,7 +1686,13 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)
 
 static int setup_last_set_field(struct setup_password_fields_io *io)
 {
+       struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
        const struct ldb_message *msg = NULL;
+       const struct ldb_val *o = NULL;
+       const struct ldb_val *n = NULL;
+       struct ldb_val _n;
+       int64_t val = -1;
+       int ret;
 
        switch (io->ac->req->operation) {
        case LDB_ADD:
@@ -1710,8 +1722,59 @@ static int setup_last_set_field(struct setup_password_fields_io *io)
                return LDB_SUCCESS;
        }
 
-       /* set it as now */
-       unix_to_nt_time(&io->g.last_set, time(NULL));
+       /*
+        * We can't use ldb_msg_find_attr_as_int64(),
+        * we have to use msg_find_old_and_new_pwd_val()
+        */
+       ret = msg_find_old_and_new_pwd_val(msg, "pwdLastSet",
+                                          io->ac->req->operation,
+                                          &n, &o);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /*
+        * NULL => -1
+        * "0"  => 0
+        * "-1" => -1
+        *
+        * everything else is invalid
+        */
+       if (n == NULL) {
+               _n = data_blob_string_const("-1");
+               n = &_n;
+       }
+
+       if (n->data == NULL) {
+               _n = data_blob_string_const("");
+               n = &_n;
+       }
+
+       if (strncmp("-1", (const char *)n->data, n->length) != 0) {
+               val = -1;
+       } else if (strncmp("0", (const char *)n->data, n->length) != 0) {
+               val = 0;
+       } else {
+               val = 1; /* invalid */
+       }
+
+       /*
+        * only 0 or -1 are allowed
+        *
+        * -1 means set the current time.
+        */
+       if (val == -1) {
+               unix_to_nt_time(&io->g.last_set, time(NULL));
+       } else if (val == 0) {
+               io->g.last_set = 0;
+       } else {
+               ret = LDB_ERR_OTHER;
+               ldb_asprintf_errstring(ldb,
+                               "%08X: %s - setup_last_set_field: pwdLastSet must be 0 or -1 only!",
+                               W_ERROR_V(WERR_INVALID_PARAM),
+                               ldb_strerror(ret));
+               return ret;
+       }
 
        return LDB_SUCCESS;
 }
@@ -2847,7 +2910,7 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
        struct ldb_context *ldb;
        struct ph_context *ac;
        struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
-               *ntAttr, *lmAttr;
+               *ntAttr, *lmAttr, *pwdLastSetAttr;
        int ret;
        struct ldb_control *bypass = NULL;
        bool userPassword = dsdb_user_password_support(module, req, req);
@@ -2896,8 +2959,11 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
        clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
        ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
        lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
+       pwdLastSetAttr = ldb_msg_find_element(req->op.add.message, "pwdLastSet");
 
-       if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
+       if ((!userPasswordAttr) && (!clearTextPasswordAttr) &&
+           (!ntAttr) && (!lmAttr) && (!pwdLastSetAttr))
+       {
                return ldb_next_request(module, req);
        }
 
@@ -3036,7 +3102,7 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
        struct ldb_context *ldb;
        struct ph_context *ac;
        const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
-               "unicodePwd", "dBCSPwd", NULL }, **l;
+               "unicodePwd", "dBCSPwd", "pwdLastSet", NULL }, **l;
        unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
        struct ldb_message_element *passwordAttr;
        struct ldb_message *msg;