summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/dsdb/samdb/ldb_modules/acl.c187
1 files changed, 177 insertions, 10 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c
index 8b1dcbeed51..cd7144a138c 100644
--- a/source4/dsdb/samdb/ldb_modules/acl.c
+++ b/source4/dsdb/samdb/ldb_modules/acl.c
@@ -968,13 +968,15 @@ static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
return ret;
}
-static int acl_check_password_rights(TALLOC_CTX *mem_ctx,
- struct ldb_module *module,
- struct ldb_request *req,
- struct security_descriptor *sd,
- struct dom_sid *sid,
- const struct dsdb_class *objectclass,
- bool userPassword)
+static int acl_check_password_rights(
+ TALLOC_CTX *mem_ctx,
+ struct ldb_module *module,
+ struct ldb_request *req,
+ struct security_descriptor *sd,
+ struct dom_sid *sid,
+ const struct dsdb_class *objectclass,
+ bool userPassword,
+ struct dsdb_control_password_acl_validation **control_for_response)
{
int ret = LDB_SUCCESS;
unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
@@ -996,6 +998,12 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx,
talloc_free(tmp_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
+ /*
+ * Set control_for_response to pav so it can be added to the response
+ * and be passed up to the audit_log module which uses it to identify
+ * password reset attempts.
+ */
+ *control_for_response = pav;
c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OID);
if (c != NULL) {
@@ -1165,6 +1173,105 @@ checked:
return LDB_SUCCESS;
}
+/*
+ * Context needed by acl_callback
+ */
+struct acl_callback_context {
+ struct ldb_request *request;
+ struct ldb_module *module;
+};
+
+/*
+ * @brief Copy the password validation control to the reply.
+ *
+ * Copy the dsdb_control_password_acl_validation control from the request,
+ * to the reply. The control is used by the audit_log module to identify
+ * password rests.
+ *
+ * @param req the ldb request.
+ * @param ares the result, updated with the control.
+ */
+static void copy_password_acl_validation_control(
+ struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_control *pav_ctrl = NULL;
+ struct dsdb_control_password_acl_validation *pav = NULL;
+
+ pav_ctrl = ldb_request_get_control(
+ discard_const(req),
+ DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
+ if (pav_ctrl == NULL) {
+ return;
+ }
+
+ pav = talloc_get_type_abort(
+ pav_ctrl->data,
+ struct dsdb_control_password_acl_validation);
+ if (pav == NULL) {
+ return;
+ }
+ ldb_reply_add_control(
+ ares,
+ DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
+ false,
+ pav);
+}
+/*
+ * @brief call back function for acl_modify.
+ *
+ * Calls acl_copy to copy the dsdb_control_password_acl_validation from
+ * the request to the reply.
+ *
+ * @param req the ldb_request.
+ * @param ares the operation result.
+ *
+ * @return the LDB_STATUS
+ */
+static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct acl_callback_context *ac = NULL;
+
+ ac = talloc_get_type(req->context, struct acl_callback_context);
+
+ if (!ares) {
+ return ldb_module_done(
+ ac->request,
+ NULL,
+ NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* pass on to the callback */
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ return ldb_module_send_entry(
+ ac->request,
+ ares->message,
+ ares->controls);
+
+ case LDB_REPLY_REFERRAL:
+ return ldb_module_send_referral(
+ ac->request,
+ ares->referral);
+
+ case LDB_REPLY_DONE:
+ /*
+ * Copy the ACL control from the request to the response
+ */
+ copy_password_acl_validation_control(req, ares);
+ return ldb_module_done(
+ ac->request,
+ ares->controls,
+ ares->response,
+ ares->error);
+
+ default:
+ /* Can't happen */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+}
+
static int acl_modify(struct ldb_module *module, struct ldb_request *req)
{
int ret;
@@ -1187,6 +1294,10 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
"objectSid",
NULL
};
+ struct acl_callback_context *context = NULL;
+ struct ldb_request *new_req = NULL;
+ struct dsdb_control_password_acl_validation *pav = NULL;
+ struct ldb_control **controls = NULL;
if (ldb_dn_is_special(msg->dn)) {
return ldb_next_request(module, req);
@@ -1324,6 +1435,14 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
} else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
(userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
ldb_attr_cmp("clearTextPassword", el->name) == 0) {
+ /*
+ * Ideally we would do the acl_check_password_rights
+ * before we checked the other attributes, i.e. in a
+ * loop before the current one.
+ * Have not done this as yet in order to limit the size
+ * of the change. To limit the possibility of breaking
+ * the ACL logic.
+ */
if (password_rights_checked) {
continue;
}
@@ -1333,7 +1452,8 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
sd,
sid,
objectclass,
- userPassword);
+ userPassword,
+ &pav);
if (ret != LDB_SUCCESS) {
goto fail;
}
@@ -1382,10 +1502,57 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
success:
talloc_free(tmp_ctx);
- return ldb_next_request(module, req);
+ context = talloc_zero(req, struct acl_callback_context);
+
+ if (context == NULL) {
+ return ldb_oom(ldb);
+ }
+ context->request = req;
+ context->module = module;
+ ret = ldb_build_mod_req(
+ &new_req,
+ ldb,
+ req,
+ req->op.mod.message,
+ req->controls,
+ context,
+ acl_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ return ldb_next_request(module, new_req);
fail:
talloc_free(tmp_ctx);
- return ret;
+ /*
+ * We copy the pav into the result, so that the password reset
+ * logging code in audit_log can log failed password reset attempts.
+ */
+ if (pav) {
+ struct ldb_control *control = NULL;
+
+ controls = talloc_zero_array(req, struct ldb_control *, 2);
+ if (controls == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ control = talloc(controls, struct ldb_control);
+
+ if (control == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ control->oid= talloc_strdup(
+ control,
+ DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
+ if (control->oid == NULL) {
+ return ldb_oom(ldb);
+ }
+ control->critical = false;
+ control->data = pav;
+ *controls = control;
+ }
+ return ldb_module_done(req, controls, NULL, ret);
}
/* similar to the modify for the time being.