mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
r25723: Add a check to prevent deletion of entries with children. Sadly MMC
doesn't trigger it's recursive delete correctly, but the error return
is correct (but perhaps needs a different LDAP wire format).
Andrew Bartlett
(This used to be commit 10ba3ae699
)
This commit is contained in:
parent
b28810ab94
commit
1f680ef45d
@ -42,6 +42,8 @@ struct subtree_rename_context {
|
||||
struct ldb_request **down_req;
|
||||
int num_requests;
|
||||
int finished_requests;
|
||||
|
||||
int num_children;
|
||||
};
|
||||
|
||||
static struct subtree_rename_context *subtree_rename_init_handle(struct ldb_request *req,
|
||||
@ -95,7 +97,7 @@ static int subtree_rename_search_callback(struct ldb_context *ldb, void *context
|
||||
|
||||
/* Only entries are interesting, and we handle the case of the parent seperatly */
|
||||
if (ares->type == LDB_REPLY_ENTRY
|
||||
&& ldb_dn_compare(ares->message->dn, ac->orig_req->op.rename.olddn) != 0) {
|
||||
&& ldb_dn_compare(ares->message->dn, ac->orig_req->op.rename.olddn) == 0) {
|
||||
/* And it is an actual entry: now create a rename from it */
|
||||
int ret;
|
||||
|
||||
@ -203,6 +205,114 @@ static int subtree_rename(struct ldb_module *module, struct ldb_request *req)
|
||||
return ldb_next_request(module, new_req);
|
||||
}
|
||||
|
||||
|
||||
static int subtree_delete_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
|
||||
{
|
||||
struct ldb_request *req;
|
||||
struct subtree_rename_context *ac = talloc_get_type(context, struct subtree_rename_context);
|
||||
TALLOC_CTX *mem_ctx = talloc_new(ac);
|
||||
|
||||
if (!mem_ctx) {
|
||||
ldb_oom(ac->module->ldb);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
/* OK, we have one of *many* search results here:
|
||||
|
||||
We should also get the entry we tried to rename. This
|
||||
callback handles this and everything below it.
|
||||
*/
|
||||
|
||||
/* Only entries are interesting, and we handle the case of the parent seperatly */
|
||||
if (ares->type == LDB_REPLY_ENTRY
|
||||
&& ldb_dn_compare(ares->message->dn, ac->orig_req->op.del.dn) != 0) {
|
||||
/* And it is an actual entry: now object bitterly that we are not a leaf node */
|
||||
ac->num_children++;
|
||||
talloc_free(ares);
|
||||
return LDB_SUCCESS;
|
||||
} else if (ares->type == LDB_REPLY_DONE) {
|
||||
talloc_free(ares);
|
||||
if (ac->num_children > 0) {
|
||||
ldb_asprintf_errstring(ac->module->ldb, "Cannot delete %s, not a leaf node (has %d children)\n",
|
||||
ldb_dn_get_linearized(ac->orig_req->op.del.dn), ac->num_children);
|
||||
return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
|
||||
} else {
|
||||
req = talloc(mem_ctx, struct ldb_request);
|
||||
if (!req) {
|
||||
ldb_oom(ac->module->ldb);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
*req = *ac->orig_req;
|
||||
|
||||
ac->down_req = talloc_realloc(ac, ac->down_req,
|
||||
struct ldb_request *, ac->num_requests + 1);
|
||||
if (!ac->down_req) {
|
||||
ldb_oom(ac->module->ldb);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
ac->down_req[ac->num_requests] = req;
|
||||
ac->num_requests++;
|
||||
|
||||
return ldb_next_request(ac->module, req);
|
||||
}
|
||||
} else {
|
||||
talloc_free(ares);
|
||||
return LDB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* rename */
|
||||
static int subtree_delete(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
const char *attrs[] = { NULL };
|
||||
struct ldb_request *new_req;
|
||||
struct subtree_rename_context *ac;
|
||||
int ret;
|
||||
if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* This gets complex: We need to:
|
||||
- Do a search for all entires under this entry
|
||||
- Wait for these results to appear
|
||||
- In the callback for each result, issue a modify request
|
||||
- That will include this rename, we hope
|
||||
- Wait for each modify result
|
||||
- Regain our sainity
|
||||
*/
|
||||
|
||||
ac = subtree_rename_init_handle(req, module);
|
||||
if (!ac) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
ret = ldb_build_search_req(&new_req, module->ldb, req,
|
||||
req->op.del.dn,
|
||||
LDB_SCOPE_SUBTREE,
|
||||
"(objectClass=*)",
|
||||
attrs,
|
||||
req->controls,
|
||||
ac,
|
||||
subtree_delete_search_callback);
|
||||
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ac->down_req = talloc_realloc(ac, ac->down_req,
|
||||
struct ldb_request *, ac->num_requests + 1);
|
||||
if (!ac->down_req) {
|
||||
ldb_oom(ac->module->ldb);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
ac->down_req[ac->num_requests] = new_req;
|
||||
if (req == NULL) {
|
||||
ldb_oom(ac->module->ldb);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
ac->num_requests++;
|
||||
return ldb_next_request(module, new_req);
|
||||
}
|
||||
|
||||
static int subtree_rename_wait_none(struct ldb_handle *handle) {
|
||||
struct subtree_rename_context *ac;
|
||||
int i, ret = LDB_ERR_OPERATIONS_ERROR;
|
||||
@ -268,6 +378,7 @@ static int subtree_rename_wait(struct ldb_handle *handle, enum ldb_wait_type typ
|
||||
static const struct ldb_module_ops subtree_rename_ops = {
|
||||
.name = "subtree_rename",
|
||||
.rename = subtree_rename,
|
||||
.del = subtree_delete,
|
||||
.wait = subtree_rename_wait,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user