s3:registry: do not use regdb functions during db upgrade
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / ridalloc.c
blob2cef1c445f6224e6e8895a53886aaca1611971ad
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);
392 /* work out who is the RID Manager */
393 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
394 if (ret != LDB_SUCCESS) {
395 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
396 ldb_errstring(ldb));
397 talloc_free(tmp_ctx);
398 return ret;
401 /* find the DN of the RID Manager */
402 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
403 if (ret != LDB_SUCCESS) {
404 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
405 ldb_errstring(ldb));
406 talloc_free(tmp_ctx);
407 return ret;
410 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
411 ridalloc_poke_rid_manager(module);
412 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
413 talloc_free(tmp_ctx);
414 return LDB_ERR_UNWILLING_TO_PERFORM;
417 ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
418 talloc_free(tmp_ctx);
419 return ret;
423 get a new RID pool for ourselves
424 also returns the first rid for the new pool
426 static int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
428 TALLOC_CTX *tmp_ctx = talloc_new(module);
429 struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
430 int ret;
431 struct ldb_context *ldb = ldb_module_get_ctx(module);
433 /* work out who is the RID Manager */
434 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
435 if (ret != LDB_SUCCESS) {
436 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
437 ldb_errstring(ldb));
438 talloc_free(tmp_ctx);
439 return ret;
442 /* find the DN of the RID Manager */
443 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
444 if (ret != LDB_SUCCESS) {
445 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
446 ldb_errstring(ldb));
447 talloc_free(tmp_ctx);
448 return ret;
451 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
452 ridalloc_poke_rid_manager(module);
453 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
454 talloc_free(tmp_ctx);
455 return LDB_ERR_UNWILLING_TO_PERFORM;
458 /* grab a pool from the RID Manager object */
459 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
460 if (ret != LDB_SUCCESS) {
461 talloc_free(tmp_ctx);
462 return ret;
465 talloc_free(tmp_ctx);
466 return ret;
470 /* allocate a RID using our RID Set
471 If we run out of RIDs then allocate a new pool
472 either locally or by contacting the RID Manager
474 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
476 struct ldb_context *ldb;
477 int ret;
478 struct ldb_dn *rid_set_dn;
479 struct ldb_result *res;
480 struct ldb_message *msg;
481 struct ridalloc_ridset_values oridset;
482 struct ridalloc_ridset_values nridset;
483 uint32_t prev_pool_lo, prev_pool_hi;
484 TALLOC_CTX *tmp_ctx = talloc_new(module);
486 (*rid) = 0;
487 ldb = ldb_module_get_ctx(module);
489 ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
490 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
491 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
493 if (ret != LDB_SUCCESS) {
494 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
495 ldb_errstring(ldb));
496 talloc_free(tmp_ctx);
497 return ret;
500 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
501 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
502 if (ret != LDB_SUCCESS) {
503 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
504 ldb_dn_get_linearized(rid_set_dn));
505 talloc_free(tmp_ctx);
506 return ret;
509 ridalloc_get_ridset_values(res->msgs[0], &oridset);
510 if (oridset.alloc_pool == UINT64_MAX) {
511 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
512 ldb_dn_get_linearized(rid_set_dn));
513 talloc_free(tmp_ctx);
514 return LDB_ERR_OPERATIONS_ERROR;
517 nridset = oridset;
520 * If we never used a pool, setup out first pool
522 if (nridset.prev_pool == UINT64_MAX ||
523 nridset.next_rid == UINT32_MAX) {
524 nridset.prev_pool = nridset.alloc_pool;
525 nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
529 * Now check if our current pool is still usable
531 nridset.next_rid += 1;
532 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
533 prev_pool_hi = nridset.prev_pool >> 32;
534 if (nridset.next_rid > prev_pool_hi) {
536 * We need a new pool, check if we already have a new one
537 * Otherwise we need to get a new pool.
539 if (nridset.alloc_pool == nridset.prev_pool) {
541 * if we are the RID Manager,
542 * we can get a new pool localy.
543 * Otherwise we fail the operation and
544 * ask async for a new pool.
546 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
547 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
548 ridalloc_poke_rid_manager(module);
549 talloc_free(tmp_ctx);
550 return ret;
552 if (ret != LDB_SUCCESS) {
553 talloc_free(tmp_ctx);
554 return ret;
559 * increment the rIDUsedPool attribute
561 * Note: w2k8r2 doesn't update this attribute,
562 * at least if it's itself the rid master.
564 nridset.used_pool += 1;
566 /* now use the new pool */
567 nridset.prev_pool = nridset.alloc_pool;
568 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
569 prev_pool_hi = nridset.prev_pool >> 32;
570 nridset.next_rid = prev_pool_lo;
573 if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
574 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
575 (unsigned)nridset.next_rid,
576 (unsigned)prev_pool_lo,
577 (unsigned)prev_pool_hi);
578 talloc_free(tmp_ctx);
579 return LDB_ERR_OPERATIONS_ERROR;
583 * if we are half-exhausted then try to get a new pool.
585 if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2) {
587 * if we are the RID Manager,
588 * we can get a new pool localy.
589 * Otherwise we fail the operation and
590 * ask async for a new pool.
592 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
593 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
594 ridalloc_poke_rid_manager(module);
595 ret = LDB_SUCCESS;
597 if (ret != LDB_SUCCESS) {
598 talloc_free(tmp_ctx);
599 return ret;
604 * update the values
606 msg = ldb_msg_new(tmp_ctx);
607 if (msg == NULL) {
608 return ldb_module_oom(module);
610 msg->dn = rid_set_dn;
612 ret = ridalloc_set_ridset_values(module, msg,
613 &oridset, &nridset);
614 if (ret != LDB_SUCCESS) {
615 talloc_free(tmp_ctx);
616 return ret;
619 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
620 if (ret != LDB_SUCCESS) {
621 talloc_free(tmp_ctx);
622 return ret;
625 talloc_free(tmp_ctx);
626 *rid = nridset.next_rid;
627 return LDB_SUCCESS;
632 called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
634 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
635 struct ldb_request *parent)
637 struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
638 struct ldb_dn *rid_manager_dn;
639 TALLOC_CTX *tmp_ctx = talloc_new(module);
640 int ret;
641 struct ldb_context *ldb = ldb_module_get_ctx(module);
642 struct ldb_result *res;
643 struct ldb_message *msg;
644 struct ridalloc_ridset_values oridset, nridset;
646 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
647 if (ret != LDB_SUCCESS) {
648 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
649 GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
650 talloc_free(tmp_ctx);
651 return ret;
654 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
655 if (!server_dn) {
656 talloc_free(tmp_ctx);
657 return ldb_module_oom(module);
660 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
661 if (ret != LDB_SUCCESS) {
662 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
663 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
664 talloc_free(tmp_ctx);
665 return ret;
668 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
669 if (ret != LDB_SUCCESS) {
670 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
671 ldb_errstring(ldb));
672 talloc_free(tmp_ctx);
673 return ret;
676 ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
677 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
678 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
679 talloc_free(tmp_ctx);
680 return ret;
683 if (ret != LDB_SUCCESS) {
684 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
685 ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
686 talloc_free(tmp_ctx);
687 return ret;
690 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
691 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
692 if (ret != LDB_SUCCESS) {
693 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
694 ldb_dn_get_linearized(rid_set_dn));
695 talloc_free(tmp_ctx);
696 return ret;
699 ridalloc_get_ridset_values(res->msgs[0], &oridset);
700 if (oridset.alloc_pool == UINT64_MAX) {
701 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
702 ldb_dn_get_linearized(rid_set_dn));
703 talloc_free(tmp_ctx);
704 return LDB_ERR_OPERATIONS_ERROR;
707 nridset = oridset;
709 if (exop->fsmo_info != 0) {
711 if (nridset.alloc_pool != exop->fsmo_info) {
712 /* it has already been updated */
713 DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
714 (unsigned long long)exop->fsmo_info,
715 (unsigned long long)nridset.alloc_pool));
716 talloc_free(tmp_ctx);
717 return LDB_SUCCESS;
721 /* grab a pool from the RID Manager object */
722 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
723 if (ret != LDB_SUCCESS) {
724 talloc_free(tmp_ctx);
725 return ret;
729 * update the values
731 msg = ldb_msg_new(tmp_ctx);
732 if (msg == NULL) {
733 return ldb_module_oom(module);
735 msg->dn = rid_set_dn;
737 ret = ridalloc_set_ridset_values(module, msg,
738 &oridset, &nridset);
739 if (ret != LDB_SUCCESS) {
740 talloc_free(tmp_ctx);
741 return ret;
744 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
745 if (ret != LDB_SUCCESS) {
746 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
747 ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
748 talloc_free(tmp_ctx);
749 return ret;
752 talloc_free(tmp_ctx);
753 return LDB_SUCCESS;