bool change_status;
bool hash_values;
bool userPassword;
+ bool pwd_last_set_bypass;
};
data_blob_free(&subblob);
}
+ if (scpp == NULL) {
+ return ldb_error(ldb,
+ LDB_ERR_CONSTRAINT_VIOLATION,
+ "Primary:Packages missing");
+ }
+
+ if (scpk == NULL) {
+ /*
+ * If Primary:Kerberos is missing w2k8r2 reboots
+ * when a password is changed.
+ */
+ return ldb_error(ldb,
+ LDB_ERR_CONSTRAINT_VIOLATION,
+ "Primary:Kerberos missing");
+ }
+
if (scpp) {
struct package_PackagesBlob *p;
uint32_t n;
return LDB_ERR_OPERATIONS_ERROR;
}
io->g.aes_256 = data_blob_talloc(io->ac,
- key.keyvalue.data,
- key.keyvalue.length);
+ KRB5_KEY_DATA(&key),
+ KRB5_KEY_LENGTH(&key));
krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
if (!io->g.aes_256.data) {
return ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
io->g.aes_128 = data_blob_talloc(io->ac,
- key.keyvalue.data,
- key.keyvalue.length);
+ KRB5_KEY_DATA(&key),
+ KRB5_KEY_LENGTH(&key));
krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
if (!io->g.aes_128.data) {
return ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
io->g.des_md5 = data_blob_talloc(io->ac,
- key.keyvalue.data,
- key.keyvalue.length);
+ KRB5_KEY_DATA(&key),
+ KRB5_KEY_LENGTH(&key));
krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
if (!io->g.des_md5.data) {
return ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
io->g.des_crc = data_blob_talloc(io->ac,
- key.keyvalue.data,
- key.keyvalue.length);
+ KRB5_KEY_DATA(&key),
+ KRB5_KEY_LENGTH(&key));
krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
if (!io->g.des_crc.data) {
return ldb_oom(ldb);
}
for (i=0; i < ARRAY_SIZE(wdigest); i++) {
- MD5_CTX md5;
+ struct MD5Context md5;
MD5Init(&md5);
if (wdigest[i].nt4dom) {
MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
static int setup_last_set_field(struct setup_password_fields_io *io)
{
+ const struct ldb_message *msg = NULL;
+
+ switch (io->ac->req->operation) {
+ case LDB_ADD:
+ msg = io->ac->req->op.add.message;
+ break;
+ case LDB_MODIFY:
+ msg = io->ac->req->op.mod.message;
+ break;
+ default:
+ return LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+
+ if (io->ac->pwd_last_set_bypass) {
+ struct ldb_message_element *el;
+
+ if (msg == NULL) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ el = ldb_msg_find_element(msg, "pwdLastSet");
+ if (el == NULL) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
+ return LDB_SUCCESS;
+ }
+
/* set it as now */
unix_to_nt_time(&io->g.last_set, time(NULL));
g->cleartext_utf8->data,
g->cleartext_utf8->length,
(void *)&cleartext_utf16_blob->data,
- &cleartext_utf16_blob->length,
- false)) {
+ &cleartext_utf16_blob->length)) {
if (g->cleartext_utf8->length != 0) {
talloc_free(cleartext_utf16_blob);
ldb_asprintf_errstring(ldb,
g->cleartext_utf16->data,
g->cleartext_utf16->length,
(void *)&cleartext_utf8_blob->data,
- &cleartext_utf8_blob->length,
- false)) {
+ &cleartext_utf8_blob->length)) {
if (g->cleartext_utf16->length != 0) {
/* We must bail out here, the input wasn't even
* a multiple of 2 bytes */
{
struct ldb_context *ldb;
int ret;
- enum samr_ValidationStatus stat;
ldb = ldb_module_get_ctx(io->ac->module);
return LDB_SUCCESS;
}
+ /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
+ if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
+ !io->ac->pwd_reset)
+ {
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ ldb_asprintf_errstring(ldb,
+ "%08X: %s - check_password_restrictions: "
+ "password is too young to change!",
+ W_ERROR_V(WERR_PASSWORD_RESTRICTION),
+ ldb_strerror(ret));
+ return ret;
+ }
+
/*
* Fundamental password checks done by the call
* "samdb_check_password".
* It is also in use by "dcesrv_samr_ValidatePassword".
*/
if (io->n.cleartext_utf8 != NULL) {
- stat = samdb_check_password(io->n.cleartext_utf8,
- io->ac->status->domain_data.pwdProperties,
- io->ac->status->domain_data.minPwdLength);
- switch (stat) {
+ enum samr_ValidationStatus vstat;
+ vstat = samdb_check_password(io->n.cleartext_utf8,
+ io->ac->status->domain_data.pwdProperties,
+ io->ac->status->domain_data.minPwdLength);
+ switch (vstat) {
case SAMR_VALIDATION_STATUS_SUCCESS:
/* perfect -> proceed! */
break;
return ret;
}
- /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
- if (io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) {
- ret = LDB_ERR_CONSTRAINT_VIOLATION;
- ldb_asprintf_errstring(ldb,
- "%08X: %s - check_password_restrictions: "
- "password is too young to change!",
- W_ERROR_V(WERR_PASSWORD_RESTRICTION),
- ldb_strerror(ret));
- return ret;
- }
-
return LDB_SUCCESS;
}
& (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
| UF_SERVER_TRUST_ACCOUNT));
- if ((io->u.userAccountControl & UF_PASSWD_NOTREQD) != 0) {
- /* see [MS-ADTS] 2.2.15 */
- io->u.restrictions = 0;
- }
-
if (ac->userPassword) {
ret = msg_find_old_and_new_pwd_val(orig_msg, "userPassword",
ac->req->operation,
}
}
+ if (io->n.cleartext_utf8 != NULL) {
+ struct ldb_val *cleartext_utf8_blob;
+ char *p;
+
+ cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
+ if (!cleartext_utf8_blob) {
+ return ldb_oom(ldb);
+ }
+
+ *cleartext_utf8_blob = *io->n.cleartext_utf8;
+
+ /* make sure we have a null terminated string */
+ p = talloc_strndup(cleartext_utf8_blob,
+ (const char *)io->n.cleartext_utf8->data,
+ io->n.cleartext_utf8->length);
+ if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
+ return ldb_oom(ldb);
+ }
+ cleartext_utf8_blob->data = (uint8_t *)p;
+
+ io->n.cleartext_utf8 = cleartext_utf8_blob;
+ }
+
ret = msg_find_old_and_new_pwd_val(orig_msg, "clearTextPassword",
ac->req->operation,
&io->n.cleartext_utf16,
}
/* Checks and converts the actual "unicodePwd" attribute */
- if (quoted_utf16 &&
+ if (!ac->hash_values &&
+ quoted_utf16 &&
quoted_utf16->length >= 4 &&
quoted_utf16->data[0] == '"' &&
quoted_utf16->data[1] == 0 &&
}
/* Checks and converts the previous "unicodePwd" attribute */
- if (old_quoted_utf16 &&
+ if (!ac->hash_values &&
+ old_quoted_utf16 &&
old_quoted_utf16->length >= 4 &&
old_quoted_utf16->data[0] == '"' &&
old_quoted_utf16->data[1] == 0 &&
/* Mark the "change" control as uncritical (done) */
ctrl->critical = false;
}
+
+ ac->pwd_last_set_bypass = false;
+ ctrl = ldb_request_get_control(ac->req,
+ DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
+ if (ctrl != NULL) {
+ ac->pwd_last_set_bypass = true;
+
+ /* Mark the "bypass pwdLastSet" control as uncritical (done) */
+ ctrl->critical = false;
+ }
}
static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
return ldb_next_request(module, req);
}
- /* If the caller is manipulating the local passwords directly, let them pass */
- if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
- req->op.add.message->dn) == 0) {
- return ldb_next_request(module, req);
- }
-
bypass = ldb_request_get_control(req,
DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
if (bypass != NULL) {
return ldb_next_request(module, req);
}
- /* If the caller is manipulating the local passwords directly, let them pass */
- if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
- req->op.mod.message->dn) == 0) {
- return ldb_next_request(module, req);
- }
-
bypass = ldb_request_get_control(req,
DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
if (bypass != NULL) {