summaryrefslogtreecommitdiff
path: root/source4/dsdb/samdb/ldb_modules/ridalloc.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2010-01-06 09:24:29 +1100
committerAndrew Tridgell <tridge@samba.org>2010-01-08 13:02:59 +1100
commit1053ce529d2ed833edd9343c36f28b4ba788db96 (patch)
treededdaf0cbd215b60ad99cef8e92855ed181c1757 /source4/dsdb/samdb/ldb_modules/ridalloc.c
parent439ee5aaaeb9036d2db69d512bcbc7e88f4a601e (diff)
downloadsamba-1053ce529d2ed833edd9343c36f28b4ba788db96.tar.gz
samba-1053ce529d2ed833edd9343c36f28b4ba788db96.tar.bz2
samba-1053ce529d2ed833edd9343c36f28b4ba788db96.zip
s4-dsdb: implement creation of the RID Set object
when we are the RID Manager we can create our own RID Set object when the first user is created
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules/ridalloc.c')
-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;
+}