summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/samdb/ldb_modules/ridalloc.c348
1 files changed, 289 insertions, 59 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/ridalloc.c b/source4/dsdb/samdb/ldb_modules/ridalloc.c
index 12318314d8..8715828fd9 100644
--- a/source4/dsdb/samdb/ldb_modules/ridalloc.c
+++ b/source4/dsdb/samdb/ldb_modules/ridalloc.c
@@ -32,109 +32,339 @@
#include "dsdb/samdb/samdb.h"
#include "dsdb/samdb/ldb_modules/util.h"
-/* allocate a RID using our RID Set
- If we run out of RIDs then allocate a new pool
- either locally or by contacting the RID Manager
-*/
-int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
+
+/*
+ create a RID Set object for the specified DC
+ */
+static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+ struct ldb_dn *rid_manager_dn,
+ struct ldb_dn *ntds_dn, struct ldb_dn **dn)
{
- struct ldb_context *ldb;
- static const char * const attrs[] = { "rIDAllocationPool", "rIDNextRID" , NULL };
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
int ret;
- struct ldb_dn *rid_set_dn;
- struct ldb_result *res;
- uint64_t alloc_pool;
- uint32_t alloc_pool_lo, alloc_pool_hi;
- int next_rid;
+ const char *attrs[] = { "rIDAvailablePool", NULL };
+ uint64_t rid_pool, new_rid_pool, dc_pool;
+ uint32_t rid_pool_lo, rid_pool_hi;
struct ldb_message *msg;
- TALLOC_CTX *tmp_ctx = talloc_new(module);
- struct ldb_message_element *el;
- struct ldb_val v1, v2;
- char *ridstring;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ const unsigned int alloc_size = 500;
+ struct ldb_result *res;
- ldb = ldb_module_get_ctx(module);
+ /*
+ steps:
- ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
+ find the machine object for the DC
+ construct the RID Set DN
+ load rIDAvailablePool to find next available set
+ modify RID Manager object to update rIDAvailablePool
+ add the RID Set object
+ link to the RID Set object in machine object
+ */
+
+ server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
+ if (!server_dn) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN");
+ ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
+ ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
talloc_free(tmp_ctx);
return ret;
}
- ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, attrs, 0);
+ rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
+ if (rid_set_dn == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn, attrs, 0);
if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
- ldb_dn_get_linearized(rid_set_dn));
+ ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
+ ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
talloc_free(tmp_ctx);
return ret;
}
- alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
- next_rid = ldb_msg_find_attr_as_int(res->msgs[0], "rIDNextRID", -1);
- if (next_rid == -1 || alloc_pool == 0) {
- ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
- ldb_dn_get_linearized(rid_set_dn));
+ rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
+ rid_pool_lo = rid_pool & 0xFFFFFFFF;
+ rid_pool_hi = rid_pool >> 32;
+ if (rid_pool_lo >= rid_pool_hi) {
+ ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
+ rid_pool_lo, rid_pool_hi);
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ret;
}
- alloc_pool_lo = alloc_pool & 0xFFFFFFFF;
- alloc_pool_hi = alloc_pool >> 32;
- if (next_rid > alloc_pool_hi) {
- /* TODO: add call to RID Manager */
- ldb_asprintf_errstring(ldb, __location__ ": Out of RIDs in RID Set %s",
- ldb_dn_get_linearized(rid_set_dn));
- talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ /* lower part of new pool is the low part of the rIDAvailablePool */
+ dc_pool = rid_pool_lo;
- /* despite the name, rIDNextRID is the value of the last user
- * added by this DC, not the next available RID */
+ /* allocate 500 RIDs to this DC */
+ rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
- (*rid) = next_rid + 1;
+ /* work out upper part of new pool */
+ dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
- /* now modify the RID Set to use up this RID using a
- * constrained delete/add */
+ /* and new rIDAvailablePool value */
+ new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
+
+ ret = dsdb_module_constrainted_update_integer(module, rid_manager_dn, "rIDAvailablePool",
+ rid_pool, new_rid_pool);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* create the RID Set object */
msg = ldb_msg_new(tmp_ctx);
msg->dn = rid_set_dn;
- ret = ldb_msg_add_empty(msg, "rIDNextRID", LDB_FLAG_MOD_DELETE, &el);
+ ret = ldb_msg_add_string(msg, "objectClass", "top");
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
}
- el->num_values = 1;
- el->values = &v1;
- ridstring = talloc_asprintf(msg, "%u", (unsigned)next_rid);
- if (!ridstring) {
- ldb_module_oom(module);
+ ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
+ if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ret;
+ }
+ ret = ldb_msg_add_string(msg, "cn", "RID Set");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = ldb_msg_add_string(msg, "name", "RID Set");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = ldb_msg_add_fmt(msg, "rIDAllocationPool", "%llu", (unsigned long long)dc_pool);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = ldb_msg_add_fmt(msg, "rIDPreviousAllocationPool", "%llu", (unsigned long long)dc_pool);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = ldb_msg_add_fmt(msg, "rIDUsedPool", "0");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = ldb_msg_add_fmt(msg, "rIDNextRID", "%lu", (unsigned long)(dc_pool & 0xFFFFFFFF));
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
}
- v1 = data_blob_string_const(ridstring);
- ret = ldb_msg_add_empty(msg, "rIDNextRID", LDB_FLAG_MOD_ADD, &el);
+ ret = dsdb_module_add(module, msg, 0);
if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(ldb));
talloc_free(tmp_ctx);
return ret;
}
- el->num_values = 1;
- el->values = &v2;
- ridstring = talloc_asprintf(msg, "%u", (unsigned)next_rid+1);
- if (!ridstring) {
- ldb_module_oom(module);
+
+ /* add the rIDSetReferences link */
+ msg = ldb_msg_new(tmp_ctx);
+ msg->dn = machine_dn;
+
+ ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_linearized(rid_set_dn));
+ if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ret;
}
- v2 = data_blob_string_const(ridstring);
+ msg->elements[0].flags = LDB_FLAG_MOD_ADD;
ret = dsdb_module_modify(module, msg, 0);
if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(ldb));
talloc_free(tmp_ctx);
return ret;
}
- talloc_free(tmp_ctx);
+ (*dn) = talloc_steal(mem_ctx, rid_set_dn);
+ talloc_free(tmp_ctx);
return LDB_SUCCESS;
}
+
+
+/*
+ create a RID Set object for this DC
+ */
+static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+ struct ldb_dn **dn)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
+ int ret;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+ /* work out who is the RID Manager */
+ ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* find the DN of the RID Manager */
+ ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
+ ldb_asprintf_errstring(ldb, "Remote RID Set allocation not implemented");
+ talloc_free(tmp_ctx);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ refresh a RID Set object for the specified DC
+ also returns the first RID for the new pool
+ */
+static int ridalloc_refresh_rid_set_ntds(struct ldb_module *module,
+ struct ldb_dn *rid_manager_dn,
+ struct ldb_dn *ntds_dn, uint32_t *first_rid)
+{
+ ldb_asprintf_errstring(ldb, "Refresh of RID Set not implemented");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+}
+
+
+
+/*
+ get a new RID pool for ourselves
+ also returns the first rid for the new pool
+ */
+static int ridalloc_refresh_own_pool(struct ldb_module *module, uint32_t *first_rid)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(module);
+ struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
+ int ret;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+ /* work out who is the RID Manager */
+ ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* find the DN of the RID Manager */
+ ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
+ ldb_asprintf_errstring(ldb, "Remote RID Set allocation not implemented");
+ talloc_free(tmp_ctx);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ ret = ridalloc_refresh_rid_set_ntds(module, rid_manager_dn, fsmo_role_dn, first_rid);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
+/* allocate a RID using our RID Set
+ If we run out of RIDs then allocate a new pool
+ either locally or by contacting the RID Manager
+*/
+int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
+{
+ struct ldb_context *ldb;
+ static const char * const attrs[] = { "rIDAllocationPool", "rIDNextRID" , NULL };
+ int ret;
+ struct ldb_dn *rid_set_dn;
+ struct ldb_result *res;
+ uint64_t alloc_pool;
+ uint32_t alloc_pool_lo, alloc_pool_hi;
+ int prev_rid;
+ TALLOC_CTX *tmp_ctx = talloc_new(module);
+
+ ldb = ldb_module_get_ctx(module);
+
+ ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn);
+ }
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, attrs, 0);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
+ ldb_dn_get_linearized(rid_set_dn));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
+ prev_rid = ldb_msg_find_attr_as_int(res->msgs[0], "rIDNextRID", -1);
+ if (prev_rid == -1 || alloc_pool == 0) {
+ ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
+ ldb_dn_get_linearized(rid_set_dn));
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ alloc_pool_lo = alloc_pool & 0xFFFFFFFF;
+ alloc_pool_hi = alloc_pool >> 32;
+ if (prev_rid > alloc_pool_hi) {
+ ret = ridalloc_refresh_own_pool(module, rid);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ } else {
+ /* despite the name, rIDNextRID is the value of the last user
+ * added by this DC, not the next available RID */
+ (*rid) = prev_rid + 1;
+ }
+
+ /* now modify the RID Set to use up this RID using a
+ * constrained delete/add */
+ ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDNextRID", prev_rid, *rid);
+ talloc_free(tmp_ctx);
+
+ return ret;
+}