s4:dsdb: autogenerate a random utf16 buffer for krbtgt password resets.
authorStefan Metzmacher <metze@samba.org>
Mon, 13 Feb 2017 18:01:21 +0000 (19:01 +0100)
committerRalph Boehme <slow@samba.org>
Tue, 21 Feb 2017 15:09:22 +0000 (16:09 +0100)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12262

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source4/dsdb/samdb/ldb_modules/password_hash.c
source4/dsdb/samdb/ldb_modules/samldb.c

index 9b772a8befed5ce2aa0da222ca86b07c464808ac..bd29377b1b684c418442ed150954710764f3eddd 100644 (file)
@@ -35,6 +35,7 @@
 #include "includes.h"
 #include "ldb_module.h"
 #include "libcli/auth/libcli_auth.h"
+#include "libcli/security/dom_sid.h"
 #include "system/kerberos.h"
 #include "auth/kerberos/kerberos.h"
 #include "dsdb/samdb/samdb.h"
@@ -125,6 +126,7 @@ struct setup_password_fields_io {
                const char *sAMAccountName;
                const char *user_principal_name;
                bool is_computer;
+               bool is_krbtgt;
                uint32_t restrictions;
        } u;
 
@@ -2793,6 +2795,8 @@ static int setup_io(struct ph_context *ac,
                ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
        int ret;
        const struct ldb_message *info_msg = NULL;
+       struct dom_sid *account_sid = NULL;
+       int rodc_krbtgt = 0;
 
        ZERO_STRUCTP(io);
 
@@ -2837,6 +2841,26 @@ static int setup_io(struct ph_context *ac,
                                                                      "userPrincipalName", NULL);
        io->u.is_computer               = ldb_msg_check_string_attribute(info_msg, "objectClass", "computer");
 
+       /* Ensure it has an objectSID too */
+       account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid");
+       if (account_sid != NULL) {
+               NTSTATUS status;
+               uint32_t rid = 0;
+
+               status = dom_sid_split_rid(account_sid, account_sid, NULL, &rid);
+               if (NT_STATUS_IS_OK(status)) {
+                       if (rid == DOMAIN_RID_KRBTGT) {
+                               io->u.is_krbtgt = true;
+                       }
+               }
+       }
+
+       rodc_krbtgt = ldb_msg_find_attr_as_int(info_msg,
+                       "msDS-SecondaryKrbTgtNumber", 0);
+       if (rodc_krbtgt != 0) {
+               io->u.is_krbtgt = true;
+       }
+
        if (io->u.sAMAccountName == NULL) {
                ldb_asprintf_errstring(ldb,
                                       "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
@@ -2867,6 +2891,12 @@ static int setup_io(struct ph_context *ac,
                & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
                        | UF_SERVER_TRUST_ACCOUNT));
 
+       if (io->u.is_krbtgt) {
+               io->u.restrictions = 0;
+               io->ac->status->domain_data.pwdHistoryLength =
+                       MAX(io->ac->status->domain_data.pwdHistoryLength, 3);
+       }
+
        if (ac->userPassword) {
                ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
                                                   ac->req->operation,
@@ -3172,6 +3202,59 @@ static int setup_io(struct ph_context *ac,
                return ldb_operr(ldb);
        }
 
+       if (io->u.is_krbtgt) {
+               size_t min = 196;
+               size_t max = 255;
+               size_t diff = max - min;
+               size_t len = max;
+               struct ldb_val *krbtgt_utf16 = NULL;
+
+               if (!ac->pwd_reset) {
+                       return dsdb_module_werror(ac->module,
+                                       LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
+                                       WERR_DS_ATT_ALREADY_EXISTS,
+                                       "Password change on krbtgt not permitted!");
+               }
+
+               if (io->n.cleartext_utf16 == NULL) {
+                       return dsdb_module_werror(ac->module,
+                                       LDB_ERR_UNWILLING_TO_PERFORM,
+                                       WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
+                                       "Password reset on krbtgt requires UTF16!");
+               }
+
+               /*
+                * Instead of taking the callers value,
+                * we just generate a new random value here.
+                *
+                * Include null termination in the array.
+                */
+               if (diff > 0) {
+                       size_t tmp;
+
+                       generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
+
+                       tmp %= diff;
+
+                       len = min + tmp;
+               }
+
+               krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
+               if (krbtgt_utf16 == NULL) {
+                       return ldb_oom(ldb);
+               }
+
+               *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
+                                                     (len+1)*2);
+               if (krbtgt_utf16->data == NULL) {
+                       return ldb_oom(ldb);
+               }
+               krbtgt_utf16->length = len * 2;
+               generate_secret_buffer(krbtgt_utf16->data,
+                                      krbtgt_utf16->length);
+               io->n.cleartext_utf16 = krbtgt_utf16;
+       }
+
        if (existing_msg != NULL) {
                NTSTATUS status;
 
@@ -4055,6 +4138,7 @@ static int password_hash_mod_search_self(struct ph_context *ac)
                                              "badPasswordTime",
                                              "badPwdCount",
                                              "lockoutTime",
+                                             "msDS-SecondaryKrbTgtNumber",
                                              NULL };
        struct ldb_request *search_req;
        int ret;
index ea43ccc78f67fc9f4885cdac90e3e0af6e0627db..2c47ff17f1ba7aa78cdd4e6afae721781fa8a198 100644 (file)
@@ -664,7 +664,6 @@ static int samldb_rodc_add(struct samldb_ctx *ac)
        struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
        uint32_t krbtgt_number, i_start, i;
        int ret;
-       char *newpass;
        struct ldb_val newpass_utf16;
 
        /* find a unused msDC-SecondaryKrbTgtNumber */
@@ -710,21 +709,17 @@ found:
                return ldb_operr(ldb);
        }
 
-       newpass = generate_random_password(ac->msg, 128, 255);
-       if (newpass == NULL) {
-               return ldb_operr(ldb);
-       }
-
-       if (!convert_string_talloc(ac,
-                                  CH_UNIX, CH_UTF16,
-                                  newpass, strlen(newpass),
-                                  (void *)&newpass_utf16.data,
-                                  &newpass_utf16.length)) {
-               ldb_asprintf_errstring(ldb,
-                                      "samldb_rodc_add: "
-                                      "failed to generate UTF16 password from random password");
-               return LDB_ERR_OPERATIONS_ERROR;
+       newpass_utf16 = data_blob_talloc_zero(ac->module, 256);
+       if (newpass_utf16.data == NULL) {
+               return ldb_oom(ldb);
        }
+       /*
+        * Note that the password_hash module will ignore
+        * this value and use it's own generate_secret_buffer()
+        * that's why we can just use generate_random_buffer()
+        * here.
+        */
+       generate_random_buffer(newpass_utf16.data, newpass_utf16.length);
        ret = ldb_msg_add_steal_value(ac->msg, "clearTextPassword", &newpass_utf16);
        if (ret != LDB_SUCCESS) {
                return ldb_operr(ldb);