s4:dsdb:ridalloc: add ridalloc_ridset_values infrastructure
[metze/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / ridalloc.c
index 07b3739f8ed453ee1ccb794bb4cc5c086aa599fc..2ba3edb9cbba6af1eb19e46e909a55c68786cf12 100644 (file)
  */
 
 
+/*
+  make a IRPC call to the drepl task to ask it to get the RID
+  Manager to give us another RID pool.
+
+  This function just sends the message to the drepl task then
+  returns immediately. It should be called well before we
+  completely run out of RIDs
+ */
+static void ridalloc_poke_rid_manager(struct ldb_module *module)
+{
+       struct messaging_context *msg;
+       struct server_id *server;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct loadparm_context *lp_ctx =
+               (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
+       TALLOC_CTX *tmp_ctx = talloc_new(module);
+
+       msg = messaging_client_init(tmp_ctx, lp_messaging_path(tmp_ctx, lp_ctx),
+                                   ldb_get_event_context(ldb));
+       if (!msg) {
+               DEBUG(3,(__location__ ": Failed to create messaging context\n"));
+               talloc_free(tmp_ctx);
+               return;
+       }
+
+       server = irpc_servers_byname(msg, msg, "dreplsrv");
+       if (!server) {
+               /* this means the drepl service is not running */
+               talloc_free(tmp_ctx);
+               return;
+       }
+
+       messaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL);
+
+       /* we don't care if the message got through */
+       talloc_free(tmp_ctx);
+}
+
+
+static const char * const ridalloc_ridset_attrs[] = {
+       "rIDAllocationPool",
+       "rIDPreviousAllocationPool",
+       "rIDNextRID",
+       "rIDUsedPool",
+       NULL
+};
+
+struct ridalloc_ridset_values {
+       uint64_t alloc_pool;
+       uint64_t prev_pool;
+       uint32_t next_rid;
+       uint32_t used_pool;
+};
+
+static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
+{
+       v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
+       v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
+       v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
+       v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
+}
+
+static int ridalloc_set_ridset_values(struct ldb_module *module,
+                                     struct ldb_message *msg,
+                                     const struct ridalloc_ridset_values *o,
+                                     const struct ridalloc_ridset_values *n)
+{
+       const uint32_t *o32, *n32;
+       const uint64_t *o64, *n64;
+       int ret;
+
+#define SETUP_PTRS(field, optr, nptr, max) do { \
+       optr = &o->field; \
+       nptr = &n->field; \
+       if (o->field == max) { \
+               optr = NULL; \
+       } \
+       if (n->field == max) { \
+               nptr = NULL; \
+       } \
+       if (o->field == n->field) { \
+               optr = NULL; \
+               nptr = NULL; \
+       } \
+} while(0)
+
+       SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
+       ret = dsdb_msg_constrainted_update_uint64(module, msg,
+                                                 "rIDAllocationPool",
+                                                 o64, n64);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
+       ret = dsdb_msg_constrainted_update_uint64(module, msg,
+                                                 "rIDPreviousAllocationPool",
+                                                 o64, n64);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
+       ret = dsdb_msg_constrainted_update_uint32(module, msg,
+                                                 "rIDNextRID",
+                                                 o32, n32);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
+       ret = dsdb_msg_constrainted_update_uint32(module, msg,
+                                                 "rIDUsedPool",
+                                                 o32, n32);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+#undef SETUP_PTRS
+
+       return LDB_SUCCESS;
+}
+
 /*
   allocate a new range of RIDs in the RID Manager object
  */
@@ -69,7 +191,8 @@ static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_d
        struct ldb_context *ldb = ldb_module_get_ctx(module);
        const unsigned alloc_size = 500;
 
-       ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn, attrs, 0);
+       ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
+                                   attrs, DSDB_FLAG_NEXT_MODULE);
        if (ret != LDB_SUCCESS) {
                ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
                                       ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
@@ -99,8 +222,8 @@ static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_d
        /* 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);
+       ret = dsdb_module_constrainted_update_uint64(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));
@@ -140,9 +263,8 @@ static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *m
 
        server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
        if (!server_dn) {
-               ldb_module_oom(module);
                talloc_free(tmp_ctx);
-               return LDB_ERR_OPERATIONS_ERROR;
+               return ldb_module_oom(module);
        }
 
        ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
@@ -155,13 +277,13 @@ static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *m
 
        rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
        if (rid_set_dn == NULL) {
-               ldb_module_oom(module);
-               return LDB_ERR_OPERATIONS_ERROR;
+               talloc_free(tmp_ctx);
+               return ldb_module_oom(module);
        }
 
        if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
-               ldb_module_oom(module);
-               return LDB_ERR_OPERATIONS_ERROR;
+               talloc_free(tmp_ctx);
+               return ldb_module_oom(module);
        }
 
        /* grab a pool from the RID Manager object */
@@ -226,7 +348,7 @@ static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *m
        }
        msg->elements[0].flags = LDB_FLAG_MOD_ADD;
 
-       ret = dsdb_module_modify(module, msg, 0);
+       ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
        if (ret != LDB_SUCCESS) {
                ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
                                       ldb_dn_get_linearized(msg->dn),
@@ -272,6 +394,7 @@ static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *me
        }
 
        if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
+               ridalloc_poke_rid_manager(module);
                ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
                talloc_free(tmp_ctx);
                return LDB_ERR_UNWILLING_TO_PERFORM;
@@ -304,9 +427,8 @@ static int ridalloc_refresh_rid_set_ntds(struct ldb_module *module,
 
        server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
        if (!server_dn) {
-               ldb_module_oom(module);
                talloc_free(tmp_ctx);
-               return LDB_ERR_OPERATIONS_ERROR;
+               return ldb_module_oom(module);
        }
 
        ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
@@ -338,44 +460,6 @@ static int ridalloc_refresh_rid_set_ntds(struct ldb_module *module,
 }
 
 
-/*
-  make a IRPC call to the drepl task to ask it to get the RID
-  Manager to give us another RID pool.
-
-  This function just sends the message to the drepl task then
-  returns immediately. It should be called well before we
-  completely run out of RIDs
- */
-static void ridalloc_poke_rid_manager(struct ldb_module *module)
-{
-       struct messaging_context *msg;
-       struct server_id *server;
-       struct ldb_context *ldb = ldb_module_get_ctx(module);
-       struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm");
-       TALLOC_CTX *tmp_ctx = talloc_new(module);
-
-       msg = messaging_client_init(tmp_ctx, lp_messaging_path(tmp_ctx, lp_ctx),
-                                   lp_iconv_convenience(lp_ctx),
-                                   ldb_get_event_context(ldb));
-       if (!msg) {
-               DEBUG(3,(__location__ ": Failed to create messaging context\n"));
-               talloc_free(tmp_ctx);
-               return;
-       }
-
-       server = irpc_servers_byname(msg, msg, "dreplsrv");
-       if (!server) {
-               /* this means the drepl service is not running */
-               talloc_free(tmp_ctx);
-               return;
-       }
-
-       messaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL);
-
-       /* we don't care if the message got through */
-       talloc_free(tmp_ctx);
-}
-
 /*
   get a new RID pool for ourselves
   also returns the first rid for the new pool
@@ -406,6 +490,7 @@ static int ridalloc_refresh_own_pool(struct ldb_module *module, uint64_t *new_po
        }
 
        if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
+               ridalloc_poke_rid_manager(module);
                ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
                talloc_free(tmp_ctx);
                return LDB_ERR_UNWILLING_TO_PERFORM;
@@ -449,7 +534,8 @@ int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
                return ret;
        }
 
-       ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, attrs, 0);
+       ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
+                                   attrs, DSDB_FLAG_NEXT_MODULE);
        if (ret != LDB_SUCCESS) {
                ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
                                       ldb_dn_get_linearized(rid_set_dn));
@@ -487,7 +573,12 @@ int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
                prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
                prev_alloc_pool_hi = prev_alloc_pool >> 32;
 
-               /* update the rIDUsedPool attribute */
+               /*
+                * update the rIDUsedPool attribute
+                *
+                * Note: w2k8r2 doesn't update this attribute,
+                *       at least if it's itself the rid master.
+                */
                ret = dsdb_module_set_integer(module, rid_set_dn, "rIDUsedPool", rid_used_pool+1);
                if (ret != LDB_SUCCESS) {
                        ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDUsedPool on %s - %s",
@@ -505,6 +596,7 @@ int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
                uint64_t new_pool;
                ret = ridalloc_refresh_own_pool(module, &new_pool);
                if (ret != LDB_SUCCESS) {
+                       talloc_free(tmp_ctx);
                        return ret;
                }
                ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool",
@@ -577,9 +669,8 @@ int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_
 
        server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
        if (!server_dn) {
-               ldb_module_oom(module);
                talloc_free(tmp_ctx);
-               return LDB_ERR_OPERATIONS_ERROR;
+               return ldb_module_oom(module);
        }
 
        ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
@@ -618,7 +709,8 @@ int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_
                struct ldb_result *res;
                uint64_t alloc_pool;
 
-               ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, attrs, 0);
+               ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
+                                           attrs, DSDB_FLAG_NEXT_MODULE);
                if (ret != LDB_SUCCESS) {
                        ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
                                               ldb_dn_get_linearized(rid_set_dn));