mirror of
https://github.com/samba-team/samba.git
synced 2025-01-26 10:04:02 +03:00
dsdb: refactor part of garbage_collect_tombstones into new function
Pair-programmed-with: Garming Sam <garming@catalyst.net.nz> Signed-off-by: Bob Campbell <bobcampbell@catalyst.net.nz> Signed-off-by: Garming Sam <garming@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
e0ef054fa9
commit
2dfedffb74
@ -33,6 +33,209 @@
|
||||
#include "lib/ldb-samba/ldb_matching_rules.h"
|
||||
#include "lib/util/time.h"
|
||||
|
||||
static NTSTATUS garbage_collect_tombstones_part(TALLOC_CTX *mem_ctx,
|
||||
struct ldb_context *samdb,
|
||||
struct dsdb_ldb_dn_list_node *part,
|
||||
char *filter,
|
||||
unsigned int *num_links_removed,
|
||||
unsigned int *num_objects_removed,
|
||||
struct dsdb_schema *schema,
|
||||
const char **attrs,
|
||||
char **error_string,
|
||||
NTTIME expunge_time_nttime)
|
||||
{
|
||||
int ret;
|
||||
struct ldb_dn *do_dn;
|
||||
struct ldb_result *res;
|
||||
unsigned int i, j, k;
|
||||
uint32_t flags;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
|
||||
if (!tmp_ctx) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ret = dsdb_get_deleted_objects_dn(samdb, tmp_ctx, part->dn, &do_dn);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
/* some partitions have no Deleted Objects
|
||||
container */
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
DEBUG(1, ("Doing a full scan on %s and looking for deleted objects\n",
|
||||
ldb_dn_get_linearized(part->dn)));
|
||||
|
||||
flags = DSDB_SEARCH_SHOW_RECYCLED |
|
||||
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
|
||||
DSDB_SEARCH_REVEAL_INTERNALS;
|
||||
ret = dsdb_search(samdb, tmp_ctx, &res, part->dn, LDB_SCOPE_SUBTREE,
|
||||
attrs, flags, "%s", filter);
|
||||
|
||||
if (ret != LDB_SUCCESS) {
|
||||
*error_string = talloc_asprintf(mem_ctx,
|
||||
"Failed to search for deleted "
|
||||
"objects in %s: %s",
|
||||
ldb_dn_get_linearized(do_dn),
|
||||
ldb_errstring(samdb));
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
for (i=0; i<res->count; i++) {
|
||||
struct ldb_message *cleanup_msg = NULL;
|
||||
unsigned int num_modified = 0;
|
||||
|
||||
bool isDeleted = ldb_msg_find_attr_as_bool(res->msgs[i],
|
||||
"isDeleted", false);
|
||||
if (isDeleted) {
|
||||
if (ldb_dn_compare(do_dn, res->msgs[i]->dn) == 0) {
|
||||
/* Skip the Deleted Object Container */
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = dsdb_delete(samdb, res->msgs[i]->dn,
|
||||
DSDB_SEARCH_SHOW_RECYCLED
|
||||
|DSDB_MODIFY_RELAX);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(1,(__location__ ": Failed to remove "
|
||||
"deleted object %s\n",
|
||||
ldb_dn_get_linearized(res->
|
||||
msgs[i]->dn)));
|
||||
} else {
|
||||
DEBUG(4,("Removed deleted object %s\n",
|
||||
ldb_dn_get_linearized(res->
|
||||
msgs[i]->dn)));
|
||||
(*num_objects_removed)++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This must have a linked attribute */
|
||||
|
||||
/*
|
||||
* From MS-ADTS 3.1.1.1.9 DCs, usn Counters, and
|
||||
* the Originating Update Stamp
|
||||
*
|
||||
* "A link value r is deleted, but exists as a
|
||||
* tombstone, if r.stamp.timeDeleted ≠ 0. When
|
||||
* the current time minus r.stamp.timeDeleted
|
||||
* exceeds the tombstone lifetime, the link
|
||||
* value r is garbage-collected; that is,
|
||||
* removed from its containing forward link
|
||||
* attribute. "
|
||||
*/
|
||||
|
||||
for (j=0; j < res->msgs[i]->num_elements; j++) {
|
||||
struct ldb_message_element *element = NULL;
|
||||
/* TODO this is O(log n) per attribute with deleted values */
|
||||
const struct dsdb_attribute *attrib = NULL;
|
||||
|
||||
element = &res->msgs[i]->elements[j];
|
||||
attrib = dsdb_attribute_by_lDAPDisplayName(schema,
|
||||
element->name);
|
||||
|
||||
/* This avoids parsing isDeleted as a link */
|
||||
if (attrib->linkID == 0 || ((attrib->linkID & 1) == 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k = 0; k < element->num_values; k++) {
|
||||
struct ldb_val *value = &element->values[k];
|
||||
uint64_t whenChanged = 0;
|
||||
NTSTATUS status;
|
||||
struct dsdb_dn *dn;
|
||||
struct ldb_message_element *cleanup_elem = NULL;
|
||||
char *guid_search_str = NULL;
|
||||
char *guid_buf_str = NULL;
|
||||
struct ldb_val cleanup_val;
|
||||
struct GUID_txt_buf buf_guid;
|
||||
struct GUID guid;
|
||||
const struct ldb_val *guid_blob;
|
||||
|
||||
if (dsdb_dn_is_deleted_val(value) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dn = dsdb_dn_parse(tmp_ctx, samdb,
|
||||
&element->values[k],
|
||||
attrib->syntax->ldap_oid);
|
||||
if (dn == NULL) {
|
||||
DEBUG(1, ("Failed to parse linked attribute blob of "
|
||||
"%s on %s while expunging expired links\n",
|
||||
element->name,
|
||||
ldb_dn_get_linearized(res->msgs[i]->dn)));
|
||||
continue;
|
||||
}
|
||||
|
||||
status = dsdb_get_extended_dn_uint64(dn->dn,
|
||||
&whenChanged,
|
||||
"RMD_CHANGETIME");
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Error: RMD_CHANGETIME is missing on a forward link.\n"));
|
||||
talloc_free(dn);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (whenChanged >= expunge_time_nttime) {
|
||||
talloc_free(dn);
|
||||
continue;
|
||||
}
|
||||
|
||||
guid_blob = ldb_dn_get_extended_component(dn->dn, "GUID");
|
||||
status = GUID_from_ndr_blob(guid_blob, &guid);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Error: Invalid GUID on link target.\n"));
|
||||
talloc_free(dn);
|
||||
continue;
|
||||
}
|
||||
|
||||
guid_buf_str = GUID_buf_string(&guid, &buf_guid);
|
||||
guid_search_str = talloc_asprintf(mem_ctx,
|
||||
"<GUID=%s>",
|
||||
guid_buf_str);
|
||||
cleanup_val = data_blob_string_const(guid_search_str);
|
||||
|
||||
talloc_free(dn);
|
||||
|
||||
if (cleanup_msg == NULL) {
|
||||
cleanup_msg = ldb_msg_new(mem_ctx);
|
||||
if (cleanup_msg == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
cleanup_msg->dn = res->msgs[i]->dn;
|
||||
}
|
||||
|
||||
ret = ldb_msg_add_value(cleanup_msg,
|
||||
element->name,
|
||||
&cleanup_val,
|
||||
&cleanup_elem);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
cleanup_elem->flags = LDB_FLAG_MOD_DELETE;
|
||||
num_modified++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_modified > 0) {
|
||||
ret = dsdb_modify(samdb, cleanup_msg,
|
||||
DSDB_REPLMD_VANISH_LINKS);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(1,(__location__ ": Failed to remove deleted object %s\n",
|
||||
ldb_dn_get_linearized(res->msgs[i]->dn)));
|
||||
} else {
|
||||
DEBUG(4,("Removed deleted object %s\n",
|
||||
ldb_dn_get_linearized(res->msgs[i]->dn)));
|
||||
*num_links_removed = *num_links_removed + num_modified;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Per MS-ADTS 3.1.1.5.5 Delete Operation
|
||||
*
|
||||
@ -58,11 +261,9 @@ NTSTATUS dsdb_garbage_collect_tombstones(TALLOC_CTX *mem_ctx,
|
||||
unsigned int *num_links_removed,
|
||||
char **error_string)
|
||||
{
|
||||
int ret;
|
||||
|
||||
const char **attrs = NULL;
|
||||
char *filter = NULL;
|
||||
|
||||
NTSTATUS status;
|
||||
unsigned int i;
|
||||
struct dsdb_attribute *next_attr;
|
||||
unsigned int num_link_attrs;
|
||||
@ -117,178 +318,24 @@ NTSTATUS dsdb_garbage_collect_tombstones(TALLOC_CTX *mem_ctx,
|
||||
attrs[i] = "isDeleted";
|
||||
attrs[i+1] = NULL;
|
||||
|
||||
filter = talloc_asprintf_append(filter, "(&(isDeleted=TRUE)(whenChanged<=%s)))", expunge_time_string);
|
||||
filter = talloc_asprintf_append(filter,
|
||||
"(&(isDeleted=TRUE)(whenChanged<=%s)))",
|
||||
expunge_time_string);
|
||||
if (filter == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
schema = dsdb_get_schema(samdb, mem_ctx);
|
||||
|
||||
for (; part != NULL; part = part->next) {
|
||||
struct ldb_dn *do_dn;
|
||||
struct ldb_result *res;
|
||||
unsigned int j, k;
|
||||
uint32_t flags;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
|
||||
if (!tmp_ctx) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
status = garbage_collect_tombstones_part(mem_ctx, samdb, part,
|
||||
filter,
|
||||
num_links_removed,
|
||||
num_objects_removed,
|
||||
schema, attrs,
|
||||
error_string,
|
||||
expunge_time_nttime);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
ret = dsdb_get_deleted_objects_dn(samdb, tmp_ctx, part->dn, &do_dn);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
/* some partitions have no Deleted Objects
|
||||
container */
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG(1, ("Doing a full scan on %s and looking for deleted objects\n",
|
||||
ldb_dn_get_linearized(part->dn)));
|
||||
|
||||
flags = DSDB_SEARCH_SHOW_RECYCLED |
|
||||
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
|
||||
DSDB_SEARCH_REVEAL_INTERNALS;
|
||||
ret = dsdb_search(samdb, tmp_ctx, &res, part->dn, LDB_SCOPE_SUBTREE,
|
||||
attrs, flags, "%s", filter);
|
||||
|
||||
if (ret != LDB_SUCCESS) {
|
||||
*error_string = talloc_asprintf(mem_ctx, "Failed to search for deleted objects in %s: %s",
|
||||
ldb_dn_get_linearized(do_dn),
|
||||
ldb_errstring(samdb));
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
for (i=0; i<res->count; i++) {
|
||||
struct ldb_message *cleanup_msg = NULL;
|
||||
unsigned int num_modified = 0;
|
||||
|
||||
bool isDeleted = ldb_msg_find_attr_as_bool(res->msgs[i], "isDeleted", false);
|
||||
if (isDeleted) {
|
||||
if (ldb_dn_compare(do_dn, res->msgs[i]->dn) == 0) {
|
||||
/* Skip the Deleted Object Container */
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = dsdb_delete(samdb, res->msgs[i]->dn, DSDB_SEARCH_SHOW_RECYCLED|DSDB_MODIFY_RELAX);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(1,(__location__ ": Failed to remove deleted object %s\n",
|
||||
ldb_dn_get_linearized(res->msgs[i]->dn)));
|
||||
} else {
|
||||
DEBUG(4,("Removed deleted object %s\n",
|
||||
ldb_dn_get_linearized(res->msgs[i]->dn)));
|
||||
(*num_objects_removed)++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This must have a linked attribute */
|
||||
|
||||
/*
|
||||
* From MS-ADTS 3.1.1.1.9 DCs, usn Counters, and the Originating Update Stamp
|
||||
*
|
||||
* "A link value r is deleted, but exists as a
|
||||
* tombstone, if r.stamp.timeDeleted ≠ 0. When
|
||||
* the current time minus r.stamp.timeDeleted
|
||||
* exceeds the tombstone lifetime, the link
|
||||
* value r is garbage-collected; that is,
|
||||
* removed from its containing forward link
|
||||
* attribute. "
|
||||
*/
|
||||
|
||||
for (j=0; j < res->msgs[i]->num_elements; j++) {
|
||||
struct ldb_message_element *element = &res->msgs[i]->elements[j];
|
||||
/* TODO this is O(log n) per attribute with deleted values */
|
||||
const struct dsdb_attribute *attrib
|
||||
= dsdb_attribute_by_lDAPDisplayName(schema, element->name);
|
||||
|
||||
/* This avoids parsing isDeleted as a link */
|
||||
if (attrib->linkID == 0 || ((attrib->linkID & 1) == 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k = 0; k < element->num_values; k++) {
|
||||
struct ldb_val *value = &element->values[k];
|
||||
uint64_t whenChanged = 0;
|
||||
NTSTATUS status;
|
||||
struct dsdb_dn *dn;
|
||||
struct ldb_message_element *cleanup_elem = NULL;
|
||||
char *guid_search_str = NULL, *guid_buf_str = NULL;
|
||||
struct ldb_val cleanup_val;
|
||||
struct GUID_txt_buf buf_guid;
|
||||
struct GUID guid;
|
||||
const struct ldb_val *guid_blob;
|
||||
|
||||
if (dsdb_dn_is_deleted_val(value) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dn = dsdb_dn_parse(tmp_ctx, samdb, &element->values[k],
|
||||
attrib->syntax->ldap_oid);
|
||||
if (dn == NULL) {
|
||||
DEBUG(1, ("Failed to parse linked attribute blob of %s on %s while expunging expired links\n", element->name,
|
||||
ldb_dn_get_linearized(res->msgs[i]->dn)));
|
||||
continue;
|
||||
}
|
||||
|
||||
status = dsdb_get_extended_dn_uint64(dn->dn, &whenChanged, "RMD_CHANGETIME");
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Error: RMD_CHANGETIME is missing on a forward link.\n"));
|
||||
talloc_free(dn);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (whenChanged >= expunge_time_nttime) {
|
||||
talloc_free(dn);
|
||||
continue;
|
||||
}
|
||||
|
||||
guid_blob = ldb_dn_get_extended_component(dn->dn, "GUID");
|
||||
status = GUID_from_ndr_blob(guid_blob, &guid);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("Error: Invalid GUID on link target.\n"));
|
||||
talloc_free(dn);
|
||||
continue;
|
||||
}
|
||||
|
||||
guid_buf_str = GUID_buf_string(&guid, &buf_guid);
|
||||
guid_search_str = talloc_asprintf(mem_ctx, "<GUID=%s>", guid_buf_str);
|
||||
cleanup_val = data_blob_string_const(guid_search_str);
|
||||
|
||||
talloc_free(dn);
|
||||
|
||||
if (cleanup_msg == NULL) {
|
||||
cleanup_msg = ldb_msg_new(mem_ctx);
|
||||
if (cleanup_msg == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
cleanup_msg->dn = res->msgs[i]->dn;
|
||||
}
|
||||
|
||||
ret = ldb_msg_add_value(cleanup_msg, element->name, &cleanup_val, &cleanup_elem);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
cleanup_elem->flags = LDB_FLAG_MOD_DELETE;
|
||||
num_modified++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_modified > 0) {
|
||||
ret = dsdb_modify(samdb, cleanup_msg, DSDB_REPLMD_VANISH_LINKS);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(1,(__location__ ": Failed to remove deleted object %s\n",
|
||||
ldb_dn_get_linearized(res->msgs[i]->dn)));
|
||||
} else {
|
||||
DEBUG(4,("Removed deleted object %s\n",
|
||||
ldb_dn_get_linearized(res->msgs[i]->dn)));
|
||||
*num_links_removed = *num_links_removed + num_modified;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
|
Loading…
x
Reference in New Issue
Block a user