struct entryUUID_private {
struct ldb_result *objectclass_res;
+ struct ldb_dn **base_dns;
};
static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
return val_copy(module, ctx, val);
}
+static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
+{
+ struct ldb_val out;
+ unsigned long long usn = strtoull(val->data, NULL, 10);
+ time_t t = (usn >> 24);
+ out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
+ return out;
+}
+
+static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val)
+{
+ char *entryCSN = talloc_strdup(ctx, val->data);
+ char *mod_per_sec;
+ time_t t;
+ unsigned long long usn;
+ char *p;
+ if (!entryCSN) {
+ return 0;
+ }
+ p = strchr(entryCSN, '#');
+ if (!p) {
+ return 0;
+ }
+ p[0] = '\0';
+ p++;
+ mod_per_sec = p;
+
+ p = strchr(p, '#');
+ if (!p) {
+ return 0;
+ }
+ p[0] = '\0';
+ p++;
+
+ usn = strtol(mod_per_sec, NULL, 16);
+
+ t = ldb_string_to_time(entryCSN);
+
+ usn = usn | ((unsigned long long)t <<24);
+ return usn;
+}
+
+static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
+{
+ struct ldb_val out;
+ unsigned long long usn = entryCSN_to_usn_int(ctx, val);
+ out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
+ return out;
+}
+
+static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
+{
+ struct ldb_val out;
+ unsigned long long usn = strtoull(val->data, NULL, 10);
+ time_t t = (usn >> 24);
+ out = data_blob_string_const(ldb_timestring(ctx, t));
+ return out;
+}
+
+static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
+{
+ struct ldb_val out;
+ time_t t;
+ unsigned long long usn;
+
+ t = ldb_string_to_time(val->data);
+
+ usn = ((unsigned long long)t <<24);
+
+ out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
+ return out;
+}
+
+
const struct ldb_map_attribute entryUUID_attributes[] =
{
/* objectGUID */
},
}
},
+ {
+ .local_name = "usnChanged",
+ .type = MAP_CONVERT,
+ .u = {
+ .convert = {
+ .remote_name = "entryCSN",
+ .convert_local = usn_to_entryCSN,
+ .convert_remote = entryCSN_to_usn
+ },
+ },
+ },
+ {
+ .local_name = "usnCreated",
+ .type = MAP_CONVERT,
+ .u = {
+ .convert = {
+ .remote_name = "createTimestamp",
+ .convert_local = usn_to_timestamp,
+ .convert_remote = timestamp_to_usn,
+ },
+ },
+ },
{
.local_name = "*",
.type = MAP_KEEP,
"objectGUID",
"whenCreated",
"whenChanged",
+ "usnCreated",
+ "usnChanged",
NULL
};
return ret;
}
+
+static int get_remote_rootdse(struct ldb_context *ldb, void *context,
+ struct ldb_reply *ares)
+{
+ struct entryUUID_private *entryUUID_private;
+ entryUUID_private = talloc_get_type(context,
+ struct entryUUID_private);
+ if (ares->type == LDB_REPLY_ENTRY) {
+ int i;
+ struct ldb_message_element *el = ldb_msg_find_element(ares->message, "namingContexts");
+ entryUUID_private->base_dns = talloc_realloc(entryUUID_private, entryUUID_private->base_dns, struct ldb_dn *,
+ el->num_values + 1);
+ for (i=0; i < el->num_values; i++) {
+ if (!entryUUID_private->base_dns) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ entryUUID_private->base_dns[i] = ldb_dn_explode(entryUUID_private->base_dns, (const char *)el->values[i].data);
+ if (!entryUUID_private->base_dns[i]) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ entryUUID_private->base_dns[i] = NULL;
+ }
+}
+
+static int find_base_dns(struct ldb_module *module,
+ struct entryUUID_private *entryUUID_private)
+{
+ int ret;
+ struct ldb_request *req;
+ const char *naming_context_attr[] = {
+ "namingContexts",
+ NULL
+ };
+ req = talloc(module, struct ldb_request);
+ if (req == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_SEARCH;
+ req->op.search.base = ldb_dn_new(req);
+ req->op.search.scope = LDB_SCOPE_BASE;
+
+ req->op.search.tree = ldb_parse_tree(req, "objectClass=*");
+ if (req->op.search.tree == NULL) {
+ ldb_set_errstring(module->ldb, "Unable to parse search expression");
+ talloc_free(req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->op.search.attrs = naming_context_attr;
+ req->controls = NULL;
+ req->context = entryUUID_private;
+ req->callback = get_remote_rootdse;
+ ldb_set_timeout(module->ldb, req, 0); /* use default timeout */
+
+ ret = ldb_next_request(module, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ talloc_free(req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+}
+
/* the context init function */
static int entryUUID_init(struct ldb_module *module)
{
ldb_asprintf_errstring(module->ldb, "Failed to fetch objectClass schema elements: %s\n", ldb_errstring(module->ldb));
return ret;
}
-
+
+ ret = find_base_dns(module, entryUUID_private);
+
return ldb_next_init(module);
}
+static int get_seq(struct ldb_context *ldb, void *context,
+ struct ldb_reply *ares)
+{
+ unsigned long long *max_seq = context;
+ unsigned long long seq;
+ if (ares->type == LDB_REPLY_ENTRY) {
+ struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
+ if (el) {
+ seq = entryCSN_to_usn_int(ares, &el->values[0]);
+ *max_seq = MAX(seq, *max_seq);
+ }
+ }
+}
+
+static int entryUUID_sequence_number(struct ldb_module *module, struct ldb_request *req)
+{
+ int i, ret;
+ struct map_private *map_private;
+ struct entryUUID_private *entryUUID_private;
+ unsigned long long max_seq = 0;
+ struct ldb_request *search_req;
+ map_private = talloc_get_type(module->private_data, struct map_private);
+
+ entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
+
+ /* Search the baseDNs for a sequence number */
+ for (i=0; entryUUID_private &&
+ entryUUID_private->base_dns &&
+ entryUUID_private->base_dns[i];
+ i++) {
+ static const char *contextCSN_attr[] = {
+ "contextCSN", NULL
+ };
+ search_req = talloc(req, struct ldb_request);
+ if (search_req == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ search_req->operation = LDB_SEARCH;
+ search_req->op.search.base = entryUUID_private->base_dns[i];
+ search_req->op.search.scope = LDB_SCOPE_BASE;
+
+ search_req->op.search.tree = ldb_parse_tree(search_req, "objectClass=*");
+ if (search_req->op.search.tree == NULL) {
+ ldb_set_errstring(module->ldb, "Unable to parse search expression");
+ talloc_free(search_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ search_req->op.search.attrs = contextCSN_attr;
+ search_req->controls = NULL;
+ search_req->context = &max_seq;
+ search_req->callback = get_seq;
+ ldb_set_timeout(module->ldb, search_req, 0); /* use default timeout */
+
+ ret = ldb_next_request(module, search_req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
+ }
+
+ talloc_free(search_req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ switch (req->op.seq_num.type) {
+ case LDB_SEQ_HIGHEST_SEQ:
+ req->op.seq_num.seq_num = max_seq;
+ break;
+ case LDB_SEQ_NEXT:
+ req->op.seq_num.seq_num = max_seq;
+ req->op.seq_num.seq_num++;
+ break;
+ case LDB_SEQ_HIGHEST_TIMESTAMP:
+ {
+ req->op.seq_num.seq_num = (max_seq >> 24);
+ break;
+ }
+ }
+ req->op.seq_num.flags = 0;
+ req->op.seq_num.flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
+ req->op.seq_num.flags |= LDB_SEQ_GLOBAL_SEQUENCE;
+ return LDB_SUCCESS;
+}
+
static struct ldb_module_ops entryUUID_ops = {
.name = "entryUUID",
.init_context = entryUUID_init,
+ .sequence_number = entryUUID_sequence_number
};
/* the init function */
entryUUID_ops.rename = ops.rename;
entryUUID_ops.search = ops.search;
entryUUID_ops.wait = ops.wait;
-
return ldb_register_module(&entryUUID_ops);
}
Copyright (C) Simo Sorce 2004-2006
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Andrew Tridgell 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
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", (unsigned long long)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;
+}
+
/* add_record: add objectGUID attribute */
static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_message *msg;
struct ldb_val v;
struct GUID guid;
+ uint64_t seq_num;
NTSTATUS nt_status;
int ret;
time_t t = time(NULL);
return LDB_ERR_OPERATIONS_ERROR;
}
+ /* Get a sequence number from the backend */
+ ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
+ if (ret == LDB_SUCCESS) {
+ if (add_uint64_element(msg, "uSNCreated", seq_num) != 0 ||
+ add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
+ talloc_free(down_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
/* go on with the call chain */
struct ldb_message *msg;
int ret;
time_t t = time(NULL);
+ uint64_t seq_num;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
return LDB_ERR_OPERATIONS_ERROR;
}
+ /* Get a sequence number from the backend */
+ ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
+ if (ret == LDB_SUCCESS) {
+ if (add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
+ talloc_free(down_req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
/* go on with the call chain */
{
int i, ret;
uint64_t seq_number = 0;
+ uint64_t timestamp_sequence = 0;
+ uint64_t timestamp = 0;
struct partition_private_data *data = talloc_get_type(module->private_data,
struct partition_private_data);
- ret = ldb_next_request(module, req);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- seq_number = seq_number + req->op.seq_num.seq_num;
- /* Look at base DN */
- /* Figure out which partition it is under */
- /* Skip the lot if 'data' isn't here yet (initialistion) */
- for (i=0; data && data->partitions && data->partitions[i]; i++) {
- struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
-
- ret = ldb_next_request(next, req);
- talloc_free(next);
+ switch (req->op.seq_num.type) {
+ case LDB_SEQ_NEXT:
+ case LDB_SEQ_HIGHEST_SEQ:
+ ret = ldb_next_request(module, req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (req->op.seq_num.flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
+ timestamp_sequence = req->op.seq_num.seq_num;
+ } else {
+ seq_number = seq_number + req->op.seq_num.seq_num;
+ }
+
+ /* Look at base DN */
+ /* Figure out which partition it is under */
+ /* Skip the lot if 'data' isn't here yet (initialistion) */
+ for (i=0; data && data->partitions && data->partitions[i]; i++) {
+ struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
+
+ ret = ldb_next_request(next, req);
+ talloc_free(next);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (req->op.seq_num.flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
+ timestamp_sequence = MAX(timestamp_sequence, req->op.seq_num.seq_num);
+ } else {
+ seq_number = seq_number + req->op.seq_num.seq_num;
+ }
+ }
+ /* fall though */
+ case LDB_SEQ_HIGHEST_TIMESTAMP:
+ {
+ struct ldb_request *date_req = talloc(req, struct ldb_request);
+ if (!date_req) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ *date_req = *req;
+ date_req->op.seq_num.flags = LDB_SEQ_HIGHEST_TIMESTAMP;
+
+ ret = ldb_next_request(module, date_req);
if (ret != LDB_SUCCESS) {
return ret;
}
- seq_number = seq_number + req->op.seq_num.seq_num;
+ timestamp = date_req->op.seq_num.seq_num;
+
+ /* Look at base DN */
+ /* Figure out which partition it is under */
+ /* Skip the lot if 'data' isn't here yet (initialistion) */
+ for (i=0; data && data->partitions && data->partitions[i]; i++) {
+ struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
+
+ ret = ldb_next_request(next, date_req);
+ talloc_free(next);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ timestamp = MAX(timestamp, date_req->op.seq_num.seq_num);
+ }
+ break;
+ }
+ }
+
+ switch (req->op.seq_num.flags) {
+ case LDB_SEQ_NEXT:
+ case LDB_SEQ_HIGHEST_SEQ:
+
+ req->op.seq_num.flags = 0;
+
+ /* Has someone above set a timebase sequence? */
+ if (timestamp_sequence) {
+ req->op.seq_num.seq_num = (((unsigned long long)timestamp << 24) | (seq_number & 0xFFFFFF));
+ } else {
+ req->op.seq_num.seq_num = seq_number;
+ }
+
+ if (timestamp_sequence > req->op.seq_num.seq_num) {
+ req->op.seq_num.seq_num = timestamp_sequence;
+ req->op.seq_num.flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
+ }
+
+ req->op.seq_num.flags |= LDB_SEQ_GLOBAL_SEQUENCE;
+ break;
+ case LDB_SEQ_HIGHEST_TIMESTAMP:
+ req->op.seq_num.seq_num = timestamp;
+ break;
+ }
+
+ switch (req->op.seq_num.flags) {
+ case LDB_SEQ_NEXT:
+ req->op.seq_num.seq_num++;
}
- req->op.seq_num.seq_num = seq_number;
return LDB_SUCCESS;
}
if (do_attribute(attrs, "highestCommittedUSN")) {
uint64_t seq_num;
- int ret = ldb_sequence_number(module->ldb, &seq_num);
+ int ret = ldb_sequence_number(module->ldb, LDB_SEQ_HIGHEST_SEQ, &seq_num);
if (ret == LDB_SUCCESS) {
if (ldb_msg_add_fmt(msg, "highestCommittedUSN",
"%llu", (unsigned long long)seq_num) != 0) {
/*
return the global sequence number
*/
-int ldb_sequence_number(struct ldb_context *ldb, uint64_t *seq_num)
+int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num)
{
struct ldb_request *req;
int ret;
req->callback = NULL;
ldb_set_timeout(ldb, req, 0); /* use default timeout */
+ req->op.seq_num.type = type;
/* do request and autostart a transaction */
ret = ldb_request(ldb, req);
};
struct ldb_sequence_number {
+ enum ldb_sequence_type {
+ LDB_SEQ_HIGHEST_SEQ,
+ LDB_SEQ_HIGHEST_TIMESTAMP,
+ LDB_SEQ_NEXT
+ } type;
uint64_t seq_num;
+ uint32_t flags;
};
typedef int (*ldb_request_callback_t)(struct ldb_context *, void *, struct ldb_reply *);
*/
int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn);
-/**
- Obtain current database sequence number
-*/
-int ldb_sequence_number(struct ldb_context *ldb, uint64_t *seq_num);
-
/**
start a transaction
*/
/* The following definitions come from lib/ldb/common/ldb_utf8.c */
char *ldb_casefold_default(void *context, void *mem_ctx, const char *s);
+
+/**
+ Obtain current/next database sequence number
+*/
+int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num);
+
+#define LDB_SEQ_GLOBAL_SEQUENCE 0x01
+#define LDB_SEQ_TIMESTAMP_SEQUENCE 0x02
+
+
#endif
{
struct ltdb_private *ltdb = module->private_data;
struct ldb_message *msg;
- struct ldb_message_element el;
+ struct ldb_message_element el[2];
struct ldb_val val;
+ struct ldb_val val_time;
+ time_t t = time(NULL);
char *s = NULL;
int ret;
return -1;
}
- s = talloc_asprintf(msg, "%.0f", ltdb->sequence_number+1);
+ s = talloc_asprintf(msg, "%llu", ltdb->sequence_number+1);
if (!s) {
errno = ENOMEM;
return -1;
}
- msg->num_elements = 1;
- msg->elements = ⪙
+ msg->num_elements = ARRAY_SIZE(el);
+ msg->elements = el;
msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO);
if (msg->dn == NULL) {
talloc_free(msg);
errno = ENOMEM;
return -1;
}
- el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
- if (el.name == NULL) {
+ el[0].name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
+ if (el[0].name == NULL) {
talloc_free(msg);
errno = ENOMEM;
return -1;
}
- el.values = &val;
- el.num_values = 1;
- el.flags = LDB_FLAG_MOD_REPLACE;
+ el[0].values = &val;
+ el[0].num_values = 1;
+ el[0].flags = LDB_FLAG_MOD_REPLACE;
val.data = (uint8_t *)s;
val.length = strlen(s);
+ el[1].name = talloc_strdup(msg, LTDB_MOD_TIMESTAMP);
+ if (el[1].name == NULL) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return -1;
+ }
+ el[1].values = &val_time;
+ el[1].num_values = 1;
+ el[1].flags = LDB_FLAG_MOD_REPLACE;
+
+ s = ldb_timestring(msg, t);
+ if (s == NULL) {
+ return -1;
+ }
+
+ val_time.data = (uint8_t *)s;
+ val_time.length = strlen(s);
+
ret = ltdb_modify_internal(module, msg);
talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
+ req->op.seq_num.flags = 0;
+
tret = ltdb_search_dn1(module, dn, msg);
if (tret != 1) {
talloc_free(tmp_ctx);
return LDB_SUCCESS;
}
- req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0);
+ switch (req->op.seq_num.type) {
+ case LDB_SEQ_HIGHEST_SEQ:
+ req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0);
+ break;
+ case LDB_SEQ_NEXT:
+ req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0);
+ req->op.seq_num.seq_num++;
+ break;
+ case LDB_SEQ_HIGHEST_TIMESTAMP:
+ {
+ const char *date = ldb_msg_find_attr_as_string(msg, LTDB_MOD_TIMESTAMP, NULL);
+ if (date) {
+ req->op.seq_num.seq_num = ldb_string_to_time(date);
+ } else {
+ req->op.seq_num.seq_num = 0;
+ /* zero is as good as anything when we don't know */
+ }
+ break;
+ }
+ }
talloc_free(tmp_ctx);
return LDB_SUCCESS;
}
/* a double is used for portability and ease of string
handling. It has plenty of digits of precision */
- double sequence_number;
+ unsigned long long sequence_number;
struct ltdb_cache {
struct ldb_message *baseinfo;
/* special attribute types */
#define LTDB_SEQUENCE_NUMBER "sequenceNumber"
+#define LTDB_MOD_TIMESTAMP "whenChanged"
#define LTDB_OBJECTCLASS "objectClass"
/* The following definitions come from lib/ldb/ldb_tdb/ldb_cache.c */
return -1;
}
-/*
- 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", (unsigned long long)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 search operations
return ret;
}
-/*
- hook add record ops
-*/
-static int operational_add(struct ldb_module *module, struct ldb_request *req)
-{
- struct ldb_request *down_req;
- struct ldb_message *msg;
- uint64_t seq_num;
- int ret;
-
- if (ldb_dn_is_special(req->op.add.message->dn)) {
- return ldb_next_request(module, req);
- }
-
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *down_req = *req;
-
- /* we have to copy the message as the caller might have it as a const */
- down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
- if (msg == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* Get a sequence number from the backend */
- ret = ldb_sequence_number(module->ldb, &seq_num);
- if (ret == LDB_SUCCESS) {
- if (add_uint64_element(msg, "uSNCreated", seq_num) != 0 ||
- add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
- talloc_free(down_req);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- }
-
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
- }
-
- return ret;
-}
-
-/*
- hook modify record ops
-*/
-static int operational_modify(struct ldb_module *module, struct ldb_request *req)
-{
- struct ldb_request *down_req;
- struct ldb_message *msg;
- uint64_t seq_num;
- int ret;
-
- if (ldb_dn_is_special(req->op.mod.message->dn)) {
- return ldb_next_request(module, req);
- }
-
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *down_req = *req;
-
- /* we have to copy the message as the caller might have it as a const */
- down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
- if (msg == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- /* Get a sequence number from the backend */
- ret = ldb_sequence_number(module->ldb, &seq_num);
- if (ret == LDB_SUCCESS) {
- /* update the records USN if possible */
- if (add_uint64_element(msg, "uSNChanged",
- seq_num) != 0) {
- talloc_free(down_req);
- return -1;
- }
- }
-
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
- }
-
- return ret;
-}
-
static int operational_init(struct ldb_module *ctx)
{
/* setup some standard attribute handlers */
static const struct ldb_module_ops operational_ops = {
.name = "operational",
.search = operational_search,
- .add = operational_add,
- .modify = operational_modify,
.init_context = operational_init
};
index objectClass eq
index samAccountName eq
+overlay syncprov
+syncprov-checkpoint 100 10
+syncprov-sessionlog 100
+
EOF
PROVISION_OPTIONS="$CONFIGURATION --host-name=$NETBIOSNAME --host-ip=127.0.0.1"