summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/samdb/ldb_modules/rootdse.c9
-rw-r--r--source4/lib/ldb/include/ldb_private.h3
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.c26
-rw-r--r--source4/lib/ldb/modules/operational.c43
4 files changed, 81 insertions, 0 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c
index 07e34f1841..987fd7a7f1 100644
--- a/source4/dsdb/samdb/ldb_modules/rootdse.c
+++ b/source4/dsdb/samdb/ldb_modules/rootdse.c
@@ -43,6 +43,7 @@ static int do_attribute(const char * const *attrs, const char *name)
ldb_attr_in_list(attrs, "*");
}
+
/*
add dynamically generated attributes to rootDSE result
*/
@@ -106,6 +107,14 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_request *re
}
}
}
+
+ if (do_attribute(s->attrs, "highestCommittedUSN")) {
+ if (module->ldb->sequence_number != NULL &&
+ ldb_msg_add_fmt(msg, "highestCommittedUSN",
+ "%llu", module->ldb->sequence_number(module->ldb)) != 0) {
+ goto failed;
+ }
+ }
/* TODO: lots more dynamic attributes should be added here */
diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h
index 24967faeea..3f9be357a7 100644
--- a/source4/lib/ldb/include/ldb_private.h
+++ b/source4/lib/ldb/include/ldb_private.h
@@ -107,6 +107,9 @@ struct ldb_context {
int transaction_active;
int (*async_wait)(struct ldb_async_handle *, enum ldb_async_wait_type);
+
+ /* a backend supplied highestCommittedUSN function */
+ uint64_t (*sequence_number)(struct ldb_context *);
};
/* the modules init function */
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
index 8d8c01278d..b58b03f221 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -772,6 +772,31 @@ static int ltdb_request(struct ldb_module *module, struct ldb_request *req)
}
}
+/*
+ return sequenceNumber from @BASEINFO
+*/
+static uint64_t ltdb_sequence_number(struct ldb_context *ldb)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(ldb);
+ const char *attrs[] = { "sequenceNumber", NULL };
+ struct ldb_result *res = NULL;
+ struct ldb_dn *dn = ldb_dn_explode(tmp_ctx, "@BASEINFO");
+ int ret;
+ uint64_t seq_num;
+
+ ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, attrs, &res);
+ talloc_steal(tmp_ctx, res);
+ if (ret != LDB_SUCCESS || res->count != 1) {
+ talloc_free(tmp_ctx);
+ /* zero is as good as anything when we don't know */
+ return 0;
+ }
+
+ seq_num = ldb_msg_find_uint64(res->msgs[0], "sequenceNumber", 0);
+ talloc_free(tmp_ctx);
+ return seq_num;
+}
+
static int ltdb_init_2(struct ldb_module *module)
{
return LDB_SUCCESS;
@@ -847,6 +872,7 @@ int ltdb_connect(struct ldb_context *ldb, const char *url,
ldb->modules->prev = ldb->modules->next = NULL;
ldb->modules->private_data = ltdb;
ldb->modules->ops = &ltdb_ops;
+ ldb->sequence_number = ltdb_sequence_number;
return 0;
}
diff --git a/source4/lib/ldb/modules/operational.c b/source4/lib/ldb/modules/operational.c
index 8b7d6b3518..51f0ce25e4 100644
--- a/source4/lib/ldb/modules/operational.c
+++ b/source4/lib/ldb/modules/operational.c
@@ -267,6 +267,29 @@ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
return 0;
}
+/*
+ add a uint64_t element to a record
+*/
+static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
+{
+ struct ldb_message_element *el;
+
+ if (ldb_msg_find_element(msg, attr) != NULL) {
+ return 0;
+ }
+
+ if (ldb_msg_add_fmt(msg, attr, "%llu", v) != 0) {
+ return -1;
+ }
+
+ el = ldb_msg_find_element(msg, attr);
+ /* always set as replace. This works because on add ops, the flag
+ is ignored */
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ return 0;
+}
+
/*
hook add record ops
@@ -292,6 +315,17 @@ static int operational_add(struct ldb_module *module, struct ldb_request *req)
talloc_free(msg2);
return -1;
}
+
+ /* see if the backend can give us the USN */
+ if (module->ldb->sequence_number != NULL) {
+ uint64_t seq_num = module->ldb->sequence_number(module->ldb);
+ if (add_uint64_element(msg2, "uSNCreated", seq_num) != 0 ||
+ add_uint64_element(msg2, "uSNChanged", seq_num) != 0) {
+ talloc_free(msg2);
+ return -1;
+ }
+ }
+
/* use the new structure for the call chain below this point */
req->op.add.message = msg2;
/* go on with the call chain */
@@ -326,6 +360,15 @@ static int operational_modify(struct ldb_module *module, struct ldb_request *req
talloc_free(msg2);
return -1;
}
+
+ /* update the records USN if possible */
+ if (module->ldb->sequence_number != NULL &&
+ add_uint64_element(msg2, "uSNChanged",
+ module->ldb->sequence_number(module->ldb)) != 0) {
+ talloc_free(msg2);
+ return -1;
+ }
+
/* use the new structure for the call chain below this point */
req->op.mod.message = msg2;
/* go on with the call chain */