dsdb-ridalloc: Fix RID pools - RID numbers increase too quickly
[Samba.git] / source4 / dsdb / samdb / ldb_modules / ridalloc.c
blobc0859d3fbd07cbd6be919f550247d34528e8d923
1 /*
2 RID allocation helper functions
4 Copyright (C) Andrew Bartlett 2010
5 Copyright (C) Andrew Tridgell 2010
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * Name: ldb
24 * Component: RID allocation logic
26 * Description: manage RID Set and RID Manager objects
30 #include "includes.h"
31 #include "ldb_module.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "dsdb/samdb/ldb_modules/util.h"
34 #include "lib/messaging/irpc.h"
35 #include "param/param.h"
36 #include "librpc/gen_ndr/ndr_misc.h"
37 #include "dsdb/samdb/ldb_modules/ridalloc.h"
40 Note: the RID allocation attributes in AD are very badly named. Here
41 is what we think they really do:
43 in RID Set object:
44 - rIDPreviousAllocationPool: the pool which a DC is currently
45 pulling RIDs from. Managed by client DC
47 - rIDAllocationPool: the pool that the DC will switch to next,
48 when rIDPreviousAllocationPool is exhausted. Managed by RID Manager.
50 - rIDNextRID: the last RID allocated by this DC. Managed by client DC
52 in RID Manager object:
53 - rIDAvailablePool: the pool where the RID Manager gets new rID
54 pools from when it gets a EXOP_RID_ALLOC getncchanges call (or
55 locally when the DC is the RID Manager)
60 make a IRPC call to the drepl task to ask it to get the RID
61 Manager to give us another RID pool.
63 This function just sends the message to the drepl task then
64 returns immediately. It should be called well before we
65 completely run out of RIDs
67 static void ridalloc_poke_rid_manager(struct ldb_module *module)
69 struct imessaging_context *msg;
70 struct server_id *server;
71 struct ldb_context *ldb = ldb_module_get_ctx(module);
72 struct loadparm_context *lp_ctx =
73 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
74 TALLOC_CTX *tmp_ctx = talloc_new(module);
76 msg = imessaging_client_init(tmp_ctx, lp_ctx,
77 ldb_get_event_context(ldb));
78 if (!msg) {
79 DEBUG(3,(__location__ ": Failed to create messaging context\n"));
80 talloc_free(tmp_ctx);
81 return;
84 server = irpc_servers_byname(msg, msg, "dreplsrv");
85 if (!server) {
86 /* this means the drepl service is not running */
87 talloc_free(tmp_ctx);
88 return;
91 imessaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL);
93 /* we don't care if the message got through */
94 talloc_free(tmp_ctx);
98 static const char * const ridalloc_ridset_attrs[] = {
99 "rIDAllocationPool",
100 "rIDPreviousAllocationPool",
101 "rIDNextRID",
102 "rIDUsedPool",
103 NULL
106 struct ridalloc_ridset_values {
107 uint64_t alloc_pool;
108 uint64_t prev_pool;
109 uint32_t next_rid;
110 uint32_t used_pool;
113 static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
115 v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
116 v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
117 v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
118 v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
121 static int ridalloc_set_ridset_values(struct ldb_module *module,
122 struct ldb_message *msg,
123 const struct ridalloc_ridset_values *o,
124 const struct ridalloc_ridset_values *n)
126 const uint32_t *o32, *n32;
127 const uint64_t *o64, *n64;
128 int ret;
130 #define SETUP_PTRS(field, optr, nptr, max) do { \
131 optr = &o->field; \
132 nptr = &n->field; \
133 if (o->field == max) { \
134 optr = NULL; \
136 if (n->field == max) { \
137 nptr = NULL; \
139 if (o->field == n->field) { \
140 optr = NULL; \
141 nptr = NULL; \
143 } while(0)
145 SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
146 ret = dsdb_msg_constrainted_update_uint64(module, msg,
147 "rIDAllocationPool",
148 o64, n64);
149 if (ret != LDB_SUCCESS) {
150 return ret;
153 SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
154 ret = dsdb_msg_constrainted_update_uint64(module, msg,
155 "rIDPreviousAllocationPool",
156 o64, n64);
157 if (ret != LDB_SUCCESS) {
158 return ret;
161 SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
162 ret = dsdb_msg_constrainted_update_uint32(module, msg,
163 "rIDNextRID",
164 o32, n32);
165 if (ret != LDB_SUCCESS) {
166 return ret;
169 SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
170 ret = dsdb_msg_constrainted_update_uint32(module, msg,
171 "rIDUsedPool",
172 o32, n32);
173 if (ret != LDB_SUCCESS) {
174 return ret;
176 #undef SETUP_PTRS
178 return LDB_SUCCESS;
182 allocate a new range of RIDs in the RID Manager object
184 static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool,
185 struct ldb_request *parent)
187 int ret;
188 TALLOC_CTX *tmp_ctx = talloc_new(module);
189 const char *attrs[] = { "rIDAvailablePool", NULL };
190 uint64_t rid_pool, new_rid_pool, dc_pool;
191 uint32_t rid_pool_lo, rid_pool_hi;
192 struct ldb_result *res;
193 struct ldb_context *ldb = ldb_module_get_ctx(module);
194 const unsigned alloc_size = 500;
196 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
197 attrs, DSDB_FLAG_NEXT_MODULE, parent);
198 if (ret != LDB_SUCCESS) {
199 ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
200 ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
201 talloc_free(tmp_ctx);
202 return ret;
205 rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
206 rid_pool_lo = rid_pool & 0xFFFFFFFF;
207 rid_pool_hi = rid_pool >> 32;
208 if (rid_pool_lo >= rid_pool_hi) {
209 ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
210 rid_pool_lo, rid_pool_hi);
211 talloc_free(tmp_ctx);
212 return ret;
215 /* lower part of new pool is the low part of the rIDAvailablePool */
216 dc_pool = rid_pool_lo;
218 /* allocate 500 RIDs to this DC */
219 rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
221 /* work out upper part of new pool */
222 dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
224 /* and new rIDAvailablePool value */
225 new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
227 ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
228 &rid_pool, &new_rid_pool, parent);
229 if (ret != LDB_SUCCESS) {
230 ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
231 ldb_errstring(ldb));
232 talloc_free(tmp_ctx);
233 return ret;
236 (*new_pool) = dc_pool;
237 talloc_free(tmp_ctx);
238 return LDB_SUCCESS;
242 create a RID Set object for the specified DC
244 static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
245 struct ldb_dn *rid_manager_dn,
246 struct ldb_dn *ntds_dn, struct ldb_dn **dn,
247 struct ldb_request *parent)
249 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
250 struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
251 int ret;
252 struct ldb_message *msg;
253 struct ldb_context *ldb = ldb_module_get_ctx(module);
254 static const struct ridalloc_ridset_values o = {
255 .alloc_pool = UINT64_MAX,
256 .prev_pool = UINT64_MAX,
257 .next_rid = UINT32_MAX,
258 .used_pool = UINT32_MAX,
260 struct ridalloc_ridset_values n = {
261 .alloc_pool = 0,
262 .prev_pool = 0,
263 .next_rid = 0,
264 .used_pool = 0,
266 const char *no_attrs[] = { NULL };
267 struct ldb_result *res;
270 steps:
272 find the machine object for the DC
273 construct the RID Set DN
274 load rIDAvailablePool to find next available set
275 modify RID Manager object to update rIDAvailablePool
276 add the RID Set object
277 link to the RID Set object in machine object
280 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
281 if (!server_dn) {
282 talloc_free(tmp_ctx);
283 return ldb_module_oom(module);
286 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
287 if (ret != LDB_SUCCESS) {
288 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
289 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
290 talloc_free(tmp_ctx);
291 return ret;
294 rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
295 if (rid_set_dn == NULL) {
296 talloc_free(tmp_ctx);
297 return ldb_module_oom(module);
300 if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
301 talloc_free(tmp_ctx);
302 return ldb_module_oom(module);
305 /* grab a pool from the RID Manager object */
306 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent);
307 if (ret != LDB_SUCCESS) {
308 talloc_free(tmp_ctx);
309 return ret;
312 /* create the RID Set object */
313 msg = ldb_msg_new(tmp_ctx);
314 msg->dn = rid_set_dn;
316 ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
317 if (ret != LDB_SUCCESS) {
318 talloc_free(tmp_ctx);
319 return ret;
322 ret = ridalloc_set_ridset_values(module, msg, &o, &n);
323 if (ret != LDB_SUCCESS) {
324 talloc_free(tmp_ctx);
325 return ret;
328 /* we need this to go all the way to the top of the module
329 * stack, as we need all the extra attributes added (including
330 * complex ones like ntsecuritydescriptor) */
331 ret = dsdb_module_add(module, msg, DSDB_FLAG_TOP_MODULE | DSDB_MODIFY_RELAX, parent);
332 if (ret != LDB_SUCCESS) {
333 ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
334 ldb_dn_get_linearized(msg->dn),
335 ldb_errstring(ldb));
336 talloc_free(tmp_ctx);
337 return ret;
340 /* add the rIDSetReferences link */
341 msg = ldb_msg_new(tmp_ctx);
342 msg->dn = machine_dn;
344 /* we need the extended DN of the RID Set object for
345 * rIDSetReferences */
346 ret = dsdb_module_search_dn(module, msg, &res, rid_set_dn, no_attrs,
347 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, parent);
348 if (ret != LDB_SUCCESS) {
349 ldb_asprintf_errstring(ldb, "Failed to find extended DN of RID Set %s - %s",
350 ldb_dn_get_linearized(msg->dn),
351 ldb_errstring(ldb));
352 talloc_free(tmp_ctx);
353 return ret;
355 rid_set_dn = res->msgs[0]->dn;
358 ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_extended_linearized(msg, rid_set_dn, 1));
359 if (ret != LDB_SUCCESS) {
360 talloc_free(tmp_ctx);
361 return ret;
363 msg->elements[0].flags = LDB_FLAG_MOD_ADD;
365 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
366 if (ret != LDB_SUCCESS) {
367 ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
368 ldb_dn_get_linearized(msg->dn),
369 ldb_errstring(ldb));
370 talloc_free(tmp_ctx);
371 return ret;
374 (*dn) = talloc_steal(mem_ctx, rid_set_dn);
376 talloc_free(tmp_ctx);
377 return LDB_SUCCESS;
382 create a RID Set object for this DC
384 static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
385 struct ldb_dn **dn, struct ldb_request *parent)
387 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
388 struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
389 int ret;
390 struct ldb_context *ldb = ldb_module_get_ctx(module);
391 struct GUID fsmo_role_guid;
392 const struct GUID *our_ntds_guid;
393 NTSTATUS status;
395 /* work out who is the RID Manager */
396 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
397 if (ret != LDB_SUCCESS) {
398 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
399 ldb_errstring(ldb));
400 talloc_free(tmp_ctx);
401 return ret;
404 /* find the DN of the RID Manager */
405 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
406 if (ret != LDB_SUCCESS) {
407 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
408 ldb_errstring(ldb));
409 talloc_free(tmp_ctx);
410 return ret;
413 status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID");
414 if (!NT_STATUS_IS_OK(status)) {
415 talloc_free(tmp_ctx);
416 return ldb_operr(ldb_module_get_ctx(module));
419 our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module));
420 if (!our_ntds_guid) {
421 talloc_free(tmp_ctx);
422 return ldb_operr(ldb_module_get_ctx(module));
425 if (!GUID_equal(&fsmo_role_guid, our_ntds_guid)) {
426 ridalloc_poke_rid_manager(module);
427 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
428 talloc_free(tmp_ctx);
429 return LDB_ERR_UNWILLING_TO_PERFORM;
432 ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
433 talloc_free(tmp_ctx);
434 return ret;
438 get a new RID pool for ourselves
439 also returns the first rid for the new pool
441 static int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
443 TALLOC_CTX *tmp_ctx = talloc_new(module);
444 struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
445 int ret;
446 struct ldb_context *ldb = ldb_module_get_ctx(module);
447 bool is_us;
449 /* work out who is the RID Manager */
450 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
451 if (ret != LDB_SUCCESS) {
452 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
453 ldb_errstring(ldb));
454 talloc_free(tmp_ctx);
455 return ret;
458 /* find the DN of the RID Manager */
459 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
460 if (ret != LDB_SUCCESS) {
461 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
462 ldb_errstring(ldb));
463 talloc_free(tmp_ctx);
464 return ret;
467 ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us);
468 if (ret != LDB_SUCCESS) {
469 ldb_asprintf_errstring(ldb, "Failed to confirm if our ntdsDsa is %s: %s",
470 ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb));
471 talloc_free(tmp_ctx);
472 return ret;
475 if (!is_us) {
476 ridalloc_poke_rid_manager(module);
477 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
478 talloc_free(tmp_ctx);
479 return LDB_ERR_UNWILLING_TO_PERFORM;
482 /* grab a pool from the RID Manager object */
483 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
484 if (ret != LDB_SUCCESS) {
485 talloc_free(tmp_ctx);
486 return ret;
489 talloc_free(tmp_ctx);
490 return ret;
494 /* allocate a RID using our RID Set
495 If we run out of RIDs then allocate a new pool
496 either locally or by contacting the RID Manager
498 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
500 struct ldb_context *ldb;
501 int ret;
502 struct ldb_dn *rid_set_dn;
503 struct ldb_result *res;
504 struct ldb_message *msg;
505 struct ridalloc_ridset_values oridset;
506 struct ridalloc_ridset_values nridset;
507 uint32_t prev_pool_lo, prev_pool_hi;
508 TALLOC_CTX *tmp_ctx = talloc_new(module);
510 (*rid) = 0;
511 ldb = ldb_module_get_ctx(module);
513 ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
514 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
515 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
517 if (ret != LDB_SUCCESS) {
518 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
519 ldb_errstring(ldb));
520 talloc_free(tmp_ctx);
521 return ret;
524 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
525 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
526 if (ret != LDB_SUCCESS) {
527 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
528 ldb_dn_get_linearized(rid_set_dn));
529 talloc_free(tmp_ctx);
530 return ret;
533 ridalloc_get_ridset_values(res->msgs[0], &oridset);
534 if (oridset.alloc_pool == UINT64_MAX) {
535 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
536 ldb_dn_get_linearized(rid_set_dn));
537 talloc_free(tmp_ctx);
538 return LDB_ERR_OPERATIONS_ERROR;
541 nridset = oridset;
544 * If we never used a pool, setup out first pool
546 if (nridset.prev_pool == UINT64_MAX ||
547 nridset.next_rid == UINT32_MAX) {
548 nridset.prev_pool = nridset.alloc_pool;
549 nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
553 * Now check if our current pool is still usable
555 nridset.next_rid += 1;
556 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
557 prev_pool_hi = nridset.prev_pool >> 32;
558 if (nridset.next_rid > prev_pool_hi) {
560 * We need a new pool, check if we already have a new one
561 * Otherwise we need to get a new pool.
563 if (nridset.alloc_pool == nridset.prev_pool) {
565 * if we are the RID Manager,
566 * we can get a new pool localy.
567 * Otherwise we fail the operation and
568 * ask async for a new pool.
570 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
571 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
572 ridalloc_poke_rid_manager(module);
573 talloc_free(tmp_ctx);
574 return ret;
576 if (ret != LDB_SUCCESS) {
577 talloc_free(tmp_ctx);
578 return ret;
583 * increment the rIDUsedPool attribute
585 * Note: w2k8r2 doesn't update this attribute,
586 * at least if it's itself the rid master.
588 nridset.used_pool += 1;
590 /* now use the new pool */
591 nridset.prev_pool = nridset.alloc_pool;
592 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
593 prev_pool_hi = nridset.prev_pool >> 32;
594 nridset.next_rid = prev_pool_lo;
597 if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
598 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
599 (unsigned)nridset.next_rid,
600 (unsigned)prev_pool_lo,
601 (unsigned)prev_pool_hi);
602 talloc_free(tmp_ctx);
603 return LDB_ERR_OPERATIONS_ERROR;
607 * if we are half-exhausted then try to get a new pool.
609 if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2 &&
610 nridset.alloc_pool == nridset.prev_pool) {
612 * if we are the RID Manager,
613 * we can get a new pool localy.
614 * Otherwise we fail the operation and
615 * ask async for a new pool.
617 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
618 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
619 ridalloc_poke_rid_manager(module);
620 ret = LDB_SUCCESS;
622 if (ret != LDB_SUCCESS) {
623 talloc_free(tmp_ctx);
624 return ret;
629 * update the values
631 msg = ldb_msg_new(tmp_ctx);
632 if (msg == NULL) {
633 return ldb_module_oom(module);
635 msg->dn = rid_set_dn;
637 ret = ridalloc_set_ridset_values(module, msg,
638 &oridset, &nridset);
639 if (ret != LDB_SUCCESS) {
640 talloc_free(tmp_ctx);
641 return ret;
644 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
645 if (ret != LDB_SUCCESS) {
646 talloc_free(tmp_ctx);
647 return ret;
650 talloc_free(tmp_ctx);
651 *rid = nridset.next_rid;
652 return LDB_SUCCESS;
657 called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
659 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
660 struct ldb_request *parent)
662 struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
663 struct ldb_dn *rid_manager_dn;
664 TALLOC_CTX *tmp_ctx = talloc_new(module);
665 int ret;
666 struct ldb_context *ldb = ldb_module_get_ctx(module);
667 struct ldb_result *res;
668 struct ldb_message *msg;
669 struct ridalloc_ridset_values oridset, nridset;
671 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
672 if (ret != LDB_SUCCESS) {
673 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
674 GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
675 talloc_free(tmp_ctx);
676 return ret;
679 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
680 if (!server_dn) {
681 talloc_free(tmp_ctx);
682 return ldb_module_oom(module);
685 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
686 if (ret != LDB_SUCCESS) {
687 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
688 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
689 talloc_free(tmp_ctx);
690 return ret;
693 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
694 if (ret != LDB_SUCCESS) {
695 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
696 ldb_errstring(ldb));
697 talloc_free(tmp_ctx);
698 return ret;
701 ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
702 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
703 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
704 talloc_free(tmp_ctx);
705 return ret;
708 if (ret != LDB_SUCCESS) {
709 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
710 ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
711 talloc_free(tmp_ctx);
712 return ret;
715 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
716 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
717 if (ret != LDB_SUCCESS) {
718 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
719 ldb_dn_get_linearized(rid_set_dn));
720 talloc_free(tmp_ctx);
721 return ret;
724 ridalloc_get_ridset_values(res->msgs[0], &oridset);
725 if (oridset.alloc_pool == UINT64_MAX) {
726 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
727 ldb_dn_get_linearized(rid_set_dn));
728 talloc_free(tmp_ctx);
729 return LDB_ERR_OPERATIONS_ERROR;
732 nridset = oridset;
734 if (exop->fsmo_info != 0) {
736 if (nridset.alloc_pool != exop->fsmo_info) {
737 /* it has already been updated */
738 DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
739 (unsigned long long)exop->fsmo_info,
740 (unsigned long long)nridset.alloc_pool));
741 talloc_free(tmp_ctx);
742 return LDB_SUCCESS;
746 /* grab a pool from the RID Manager object */
747 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
748 if (ret != LDB_SUCCESS) {
749 talloc_free(tmp_ctx);
750 return ret;
754 * update the values
756 msg = ldb_msg_new(tmp_ctx);
757 if (msg == NULL) {
758 return ldb_module_oom(module);
760 msg->dn = rid_set_dn;
762 ret = ridalloc_set_ridset_values(module, msg,
763 &oridset, &nridset);
764 if (ret != LDB_SUCCESS) {
765 talloc_free(tmp_ctx);
766 return ret;
769 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
770 if (ret != LDB_SUCCESS) {
771 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
772 ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
773 talloc_free(tmp_ctx);
774 return ret;
777 talloc_free(tmp_ctx);
778 return LDB_SUCCESS;