#include "librpc/ndr/libndr.h"
#include "librpc/gen_ndr/ndr_security.h"
#include "libcli/security/security.h"
-#include "dsdb/samdb/ldb_modules/schema.h"
#include "auth/auth.h"
#include "param/param.h"
#include "dsdb/samdb/ldb_modules/util.h"
DATA_BLOB *sd;
const struct dsdb_class *objectclass;
static const char * const parent_attrs[] = { "nTSecurityDescriptor", NULL };
+ uint32_t instanceType;
+ bool isNC = false;
ldb = ldb_module_get_ctx(module);
dn = req->op.add.message->dn;
return ldb_next_request(module, req);
}
- /* if the object has a parent, retrieve its SD to
- * use for calculation. Unfortunately we do not yet have
- * instanceType, so we use dsdb_find_nc_root. */
- parent_dn = ldb_dn_get_parent(req, dn);
- if (parent_dn == NULL) {
- return ldb_oom(ldb);
+ instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0);
+
+ if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
+ isNC = true;
}
- ret = dsdb_find_nc_root(ldb, req, dn, &nc_root);
- if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_TRACE,"descriptor_add: Could not find NC root for %s\n",
- ldb_dn_get_linearized(dn));
- return ret;
+ if (!isNC) {
+ ret = dsdb_find_nc_root(ldb, req, dn, &nc_root);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE,"descriptor_add: Could not find NC root for %s\n",
+ ldb_dn_get_linearized(dn));
+ return ret;
+ }
+
+ if (ldb_dn_compare(dn, nc_root) == 0) {
+ DEBUG(0, ("Found DN %s being a NC by the old method\n", ldb_dn_get_linearized(dn)));
+ isNC = true;
+ }
+ }
+
+ if (isNC) {
+ DEBUG(2, ("DN: %s is a NC\n", ldb_dn_get_linearized(dn)));
}
+ if (!isNC) {
+ /* if the object has a parent, retrieve its SD to
+ * use for calculation. Unfortunately we do not yet have
+ * instanceType, so we use dsdb_find_nc_root. */
+
+ parent_dn = ldb_dn_get_parent(req, dn);
+ if (parent_dn == NULL) {
+ return ldb_oom(ldb);
+ }
- if (ldb_dn_compare(dn, nc_root) != 0) {
/* we aren't any NC */
ret = dsdb_module_search_dn(module, req, &parent_res, parent_dn,
parent_attrs,
return ldb_operr(ldb);
}
- objectclass = get_last_structural_class(schema, objectclass_element, req);
+ objectclass = dsdb_get_last_structural_class(schema,
+ objectclass_element);
if (objectclass == NULL) {
return ldb_operr(ldb);
}
return ldb_next_request(module, add_req);
}
+struct descriptor_modify_state {
+ struct ldb_module *module;
+ struct ldb_request *req;
+};
+
+static int descriptor_modify_callback(struct ldb_request *mod_req,
+ struct ldb_reply *ares);
+
static int descriptor_modify(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_context *ldb;
- struct ldb_control *sd_recalculate_control, *sd_flags_control;
+ struct descriptor_modify_state *state = NULL;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_control *sd_recalculate_control, *sd_flags_control, *show_deleted_control;
struct ldb_request *mod_req;
struct ldb_message *msg;
struct ldb_result *current_res, *parent_res;
struct ldb_dn *parent_dn, *dn;
struct ldb_message_element *objectclass_element;
int ret;
- uint32_t instanceType, sd_flags = 0;
+ uint32_t instanceType, sd_flags = 0, flags;
const struct dsdb_schema *schema;
DATA_BLOB *sd;
const struct dsdb_class *objectclass;
static const char * const current_attrs[] = { "nTSecurityDescriptor",
"instanceType",
"objectClass", NULL };
- ldb = ldb_module_get_ctx(module);
+
+ state = talloc_zero(req, struct descriptor_modify_state);
+ if (state == NULL) {
+ return ldb_oom(ldb);
+ }
+ state->module = module;
+ state->req = req;
+
dn = req->op.mod.message->dn;
user_sd = ldb_msg_find_ldb_val(req->op.mod.message, "nTSecurityDescriptor");
/* This control forces the recalculation of the SD also when
* no modification is performed. */
+ show_deleted_control = ldb_request_get_control(req,
+ LDB_CONTROL_SHOW_DELETED_OID);
sd_recalculate_control = ldb_request_get_control(req,
LDB_CONTROL_RECALCULATE_SD_OID);
if (!user_sd && !sd_recalculate_control) {
if (ldb_dn_is_special(dn)) {
return ldb_next_request(module, req);
}
-
- ret = dsdb_module_search_dn(module, req, ¤t_res, dn,
+ flags = DSDB_FLAG_NEXT_MODULE;
+ if (show_deleted_control) {
+ flags |= DSDB_SEARCH_SHOW_DELETED;
+ }
+ ret = dsdb_module_search_dn(module, state, ¤t_res, dn,
current_attrs,
- DSDB_FLAG_NEXT_MODULE,
+ flags,
req);
if (ret != LDB_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_ERROR,"descriptor_modify: Could not find %s\n",
if (parent_dn == NULL) {
return ldb_oom(ldb);
}
- ret = dsdb_module_search_dn(module, req, &parent_res, parent_dn,
+ ret = dsdb_module_search_dn(module, state, &parent_res,
+ parent_dn,
parent_attrs,
DSDB_FLAG_NEXT_MODULE,
req);
return ldb_operr(ldb);
}
- objectclass = get_last_structural_class(schema, objectclass_element, req);
+ objectclass = dsdb_get_last_structural_class(schema,
+ objectclass_element);
if (objectclass == NULL) {
return ldb_operr(ldb);
}
old_sd = ldb_msg_find_ldb_val(current_res->msgs[0], "nTSecurityDescriptor");
}
- sd = get_new_descriptor(module, dn, req,
+ if ((sd_recalculate_control != NULL) &&
+ (sd_recalculate_control->data != NULL))
+ {
+ if (user_sd != NULL) {
+ return ldb_error(ldb, ret,
+ "descriptor_modify: RECALCULATE_SD with given value rejected");
+ }
+
+ sd_flags = 0x0000000F;
+ old_sd = NULL;
+ user_sd = ldb_msg_find_ldb_val(current_res->msgs[0], "nTSecurityDescriptor");
+ }
+
+ sd = get_new_descriptor(module, dn, state,
objectclass, parent_sd,
user_sd, old_sd, sd_flags);
- msg = ldb_msg_copy_shallow(req, req->op.mod.message);
+ msg = ldb_msg_copy_shallow(state, req->op.mod.message);
if (sd != NULL) {
struct ldb_message_element *sd_element;
- if (user_sd != NULL) {
- sd_element = ldb_msg_find_element(msg,
- "nTSecurityDescriptor");
- sd_element->values[0] = *sd;
- } else if (sd_recalculate_control != NULL) {
+
+ if (sd_recalculate_control != NULL) {
/* In this branch we really do force the recalculation
* of the SD */
ldb_msg_remove_attr(msg, "nTSecurityDescriptor");
sd_element = ldb_msg_find_element(msg,
"nTSecurityDescriptor");
sd_element->flags = LDB_FLAG_MOD_REPLACE;
+ } else if (user_sd != NULL) {
+ sd_element = ldb_msg_find_element(msg,
+ "nTSecurityDescriptor");
+ sd_element->values[0] = *sd;
}
}
sd_recalculate_control->critical = 0;
}
- ret = ldb_build_mod_req(&mod_req, ldb, req,
+ ret = ldb_build_mod_req(&mod_req, ldb, state,
msg,
req->controls,
- req,
- dsdb_next_callback,
+ state,
+ descriptor_modify_callback,
req);
LDB_REQ_SET_LOCATION(mod_req);
if (ret != LDB_SUCCESS) {
return ldb_next_request(module, mod_req);
}
+/*
+ used to chain to the callers callback
+ */
+static int descriptor_modify_callback(struct ldb_request *mod_req,
+ struct ldb_reply *ares)
+{
+ struct descriptor_modify_state *state =
+ talloc_get_type_abort(mod_req->context,
+ struct descriptor_modify_state);
+ struct ldb_module *module = state->module;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_request *req = state->req;
+ struct ldb_result *res = NULL;
+ const char * const no_attrs[] = { NULL };
+ unsigned int i;
+ int ret;
+
+ if (!ares) {
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ return ldb_module_send_referral(req, ares->referral);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = dsdb_module_search(module, ares, &res,
+ req->op.mod.message->dn,
+ LDB_SCOPE_ONELEVEL, no_attrs,
+ DSDB_FLAG_NEXT_MODULE |
+ DSDB_FLAG_AS_SYSTEM |
+ DSDB_SEARCH_SHOW_RECYCLED |
+ DSDB_SEARCH_SHOW_DELETED,
+ req, "(objectClass=*)");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL, ret);
+ }
+
+ for (i=0; i < res->count; i++) {
+ struct ldb_request *sub_req;
+ struct ldb_result *mod_res;
+
+ mod_res = talloc_zero(res, struct ldb_result);
+ if (!mod_res) {
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_build_mod_req(&sub_req, ldb, req,
+ res->msgs[i],
+ NULL,
+ mod_res,
+ ldb_modify_default_callback,
+ req);
+ LDB_REQ_SET_LOCATION(sub_req);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ldb_req_mark_trusted(sub_req);
+
+ ret = ldb_request_add_control(sub_req,
+ LDB_CONTROL_RECALCULATE_SD_OID,
+ true, req);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ ret = ldb_request_add_control(sub_req,
+ LDB_CONTROL_AS_SYSTEM_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_request_add_control(sub_req,
+ LDB_CONTROL_SHOW_DELETED_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ ret = ldb_request_add_control(sub_req,
+ LDB_CONTROL_SHOW_RECYCLED_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = descriptor_modify(module, sub_req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(sub_req->handle, LDB_WAIT_ALL);
+ }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ talloc_free(mod_res);
+ }
+
+ return ldb_module_done(req, ares->controls,
+ ares->response, ares->error);
+}
+
static int descriptor_search(struct ldb_module *module, struct ldb_request *req)
{
int ret;
return ldb_next_request(ac->module, down_req);
}
-/* TODO */
+
+struct descriptor_rename_state {
+ struct ldb_module *module;
+ struct ldb_request *req;
+};
+
+static int descriptor_rename_callback(struct ldb_request *req,
+ struct ldb_reply *reply);
+
static int descriptor_rename(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_context *ldb = ldb_module_get_ctx(module);
- ldb_debug(ldb, LDB_DEBUG_TRACE,"descriptor_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn));
+ struct descriptor_rename_state *state;
+ int ret;
+ struct ldb_request *rename_req = NULL;
+
+ ldb_debug(ldb, LDB_DEBUG_TRACE,"descriptor_rename: %s\n",
+ ldb_dn_get_linearized(req->op.rename.olddn));
/* do not manipulate our control entries */
if (ldb_dn_is_special(req->op.rename.olddn)) {
return ldb_next_request(module, req);
}
- return ldb_next_request(module, req);
+ state = talloc_zero(req, struct descriptor_rename_state);
+ if (state == NULL) {
+ return ldb_oom(ldb);
+ }
+ state->module = module;
+ state->req = req;
+
+ ret = ldb_build_rename_req(&rename_req, ldb, state,
+ req->op.rename.olddn,
+ req->op.rename.newdn,
+ req->controls,
+ state,
+ descriptor_rename_callback,
+ req);
+ LDB_REQ_SET_LOCATION(rename_req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return ldb_next_request(module, rename_req);
+}
+
+static int descriptor_rename_callback(struct ldb_request *rename_req,
+ struct ldb_reply *ares)
+{
+ struct descriptor_rename_state *state =
+ talloc_get_type_abort(rename_req->context,
+ struct descriptor_rename_state);
+ struct ldb_module *module = state->module;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_request *req = state->req;
+ struct ldb_message *msg;
+ struct ldb_request *mod_req;
+ int ret;
+ struct ldb_result *mod_res;
+
+ if (!ares) {
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ return ldb_module_send_referral(req, ares->referral);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(ares);
+ if (msg == NULL) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ msg->dn = req->op.rename.newdn;
+
+ mod_res = talloc_zero(msg, struct ldb_result);
+ if (mod_res == NULL) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_build_mod_req(&mod_req, ldb, msg,
+ msg,
+ NULL,
+ mod_res,
+ ldb_modify_default_callback,
+ req);
+ LDB_REQ_SET_LOCATION(mod_req);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ldb_req_mark_trusted(mod_req);
+
+ ret = ldb_request_add_control(mod_req,
+ LDB_CONTROL_RECALCULATE_SD_OID,
+ true, req);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ ret = ldb_request_add_control(mod_req,
+ LDB_CONTROL_AS_SYSTEM_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_request_add_control(mod_req,
+ LDB_CONTROL_SHOW_DELETED_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ ret = ldb_request_add_control(mod_req,
+ LDB_CONTROL_SHOW_RECYCLED_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = descriptor_modify(module, mod_req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
+ }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ talloc_free(msg);
+
+ return ldb_module_done(req, ares->controls,
+ ares->response, ares->error);
}
static int descriptor_init(struct ldb_module *module)