s4-dsdb: Use samdb_dn_is_our_ntdsa()
[Samba.git] / source4 / dsdb / samdb / ldb_modules / ridalloc.c
blobd0266eda8aa8845f8039e153963797ce48e67d6f
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, *our_ntds_guid;
392 NTSTATUS status;
394 /* work out who is the RID Manager */
395 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
396 if (ret != LDB_SUCCESS) {
397 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
398 ldb_errstring(ldb));
399 talloc_free(tmp_ctx);
400 return ret;
403 /* find the DN of the RID Manager */
404 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
405 if (ret != LDB_SUCCESS) {
406 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
407 ldb_errstring(ldb));
408 talloc_free(tmp_ctx);
409 return ret;
412 status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID");
413 if (!NT_STATUS_IS_OK(status)) {
414 talloc_free(tmp_ctx);
415 return ldb_operr(ldb_module_get_ctx(module));
418 our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module));
419 if (!our_ntds_guid) {
420 talloc_free(tmp_ctx);
421 return ldb_operr(ldb_module_get_ctx(module));
424 if (!GUID_equal(&fsmo_role_guid, our_ntds_guid)) {
425 ridalloc_poke_rid_manager(module);
426 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
427 talloc_free(tmp_ctx);
428 return LDB_ERR_UNWILLING_TO_PERFORM;
431 ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
432 talloc_free(tmp_ctx);
433 return ret;
437 get a new RID pool for ourselves
438 also returns the first rid for the new pool
440 static int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
442 TALLOC_CTX *tmp_ctx = talloc_new(module);
443 struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
444 int ret;
445 struct ldb_context *ldb = ldb_module_get_ctx(module);
446 bool is_us;
448 /* work out who is the RID Manager */
449 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
450 if (ret != LDB_SUCCESS) {
451 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
452 ldb_errstring(ldb));
453 talloc_free(tmp_ctx);
454 return ret;
457 /* find the DN of the RID Manager */
458 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
459 if (ret != LDB_SUCCESS) {
460 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
461 ldb_errstring(ldb));
462 talloc_free(tmp_ctx);
463 return ret;
466 ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us);
467 if (ret != LDB_SUCCESS) {
468 ldb_asprintf_errstring(ldb, "Failed to confirm if our ntdsDsa is %s: %s",
469 ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb));
470 talloc_free(tmp_ctx);
471 return ret;
474 if (!is_us) {
475 ridalloc_poke_rid_manager(module);
476 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
477 talloc_free(tmp_ctx);
478 return LDB_ERR_UNWILLING_TO_PERFORM;
481 /* grab a pool from the RID Manager object */
482 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
483 if (ret != LDB_SUCCESS) {
484 talloc_free(tmp_ctx);
485 return ret;
488 talloc_free(tmp_ctx);
489 return ret;
493 /* allocate a RID using our RID Set
494 If we run out of RIDs then allocate a new pool
495 either locally or by contacting the RID Manager
497 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
499 struct ldb_context *ldb;
500 int ret;
501 struct ldb_dn *rid_set_dn;
502 struct ldb_result *res;
503 struct ldb_message *msg;
504 struct ridalloc_ridset_values oridset;
505 struct ridalloc_ridset_values nridset;
506 uint32_t prev_pool_lo, prev_pool_hi;
507 TALLOC_CTX *tmp_ctx = talloc_new(module);
509 (*rid) = 0;
510 ldb = ldb_module_get_ctx(module);
512 ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
513 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
514 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
516 if (ret != LDB_SUCCESS) {
517 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
518 ldb_errstring(ldb));
519 talloc_free(tmp_ctx);
520 return ret;
523 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
524 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
525 if (ret != LDB_SUCCESS) {
526 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
527 ldb_dn_get_linearized(rid_set_dn));
528 talloc_free(tmp_ctx);
529 return ret;
532 ridalloc_get_ridset_values(res->msgs[0], &oridset);
533 if (oridset.alloc_pool == UINT64_MAX) {
534 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
535 ldb_dn_get_linearized(rid_set_dn));
536 talloc_free(tmp_ctx);
537 return LDB_ERR_OPERATIONS_ERROR;
540 nridset = oridset;
543 * If we never used a pool, setup out first pool
545 if (nridset.prev_pool == UINT64_MAX ||
546 nridset.next_rid == UINT32_MAX) {
547 nridset.prev_pool = nridset.alloc_pool;
548 nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
552 * Now check if our current pool is still usable
554 nridset.next_rid += 1;
555 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
556 prev_pool_hi = nridset.prev_pool >> 32;
557 if (nridset.next_rid > prev_pool_hi) {
559 * We need a new pool, check if we already have a new one
560 * Otherwise we need to get a new pool.
562 if (nridset.alloc_pool == nridset.prev_pool) {
564 * if we are the RID Manager,
565 * we can get a new pool localy.
566 * Otherwise we fail the operation and
567 * ask async for a new pool.
569 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
570 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
571 ridalloc_poke_rid_manager(module);
572 talloc_free(tmp_ctx);
573 return ret;
575 if (ret != LDB_SUCCESS) {
576 talloc_free(tmp_ctx);
577 return ret;
582 * increment the rIDUsedPool attribute
584 * Note: w2k8r2 doesn't update this attribute,
585 * at least if it's itself the rid master.
587 nridset.used_pool += 1;
589 /* now use the new pool */
590 nridset.prev_pool = nridset.alloc_pool;
591 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
592 prev_pool_hi = nridset.prev_pool >> 32;
593 nridset.next_rid = prev_pool_lo;
596 if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
597 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
598 (unsigned)nridset.next_rid,
599 (unsigned)prev_pool_lo,
600 (unsigned)prev_pool_hi);
601 talloc_free(tmp_ctx);
602 return LDB_ERR_OPERATIONS_ERROR;
606 * if we are half-exhausted then try to get a new pool.
608 if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2) {
610 * if we are the RID Manager,
611 * we can get a new pool localy.
612 * Otherwise we fail the operation and
613 * ask async for a new pool.
615 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
616 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
617 ridalloc_poke_rid_manager(module);
618 ret = LDB_SUCCESS;
620 if (ret != LDB_SUCCESS) {
621 talloc_free(tmp_ctx);
622 return ret;
627 * update the values
629 msg = ldb_msg_new(tmp_ctx);
630 if (msg == NULL) {
631 return ldb_module_oom(module);
633 msg->dn = rid_set_dn;
635 ret = ridalloc_set_ridset_values(module, msg,
636 &oridset, &nridset);
637 if (ret != LDB_SUCCESS) {
638 talloc_free(tmp_ctx);
639 return ret;
642 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
643 if (ret != LDB_SUCCESS) {
644 talloc_free(tmp_ctx);
645 return ret;
648 talloc_free(tmp_ctx);
649 *rid = nridset.next_rid;
650 return LDB_SUCCESS;
655 called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
657 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
658 struct ldb_request *parent)
660 struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
661 struct ldb_dn *rid_manager_dn;
662 TALLOC_CTX *tmp_ctx = talloc_new(module);
663 int ret;
664 struct ldb_context *ldb = ldb_module_get_ctx(module);
665 struct ldb_result *res;
666 struct ldb_message *msg;
667 struct ridalloc_ridset_values oridset, nridset;
669 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
670 if (ret != LDB_SUCCESS) {
671 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
672 GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
673 talloc_free(tmp_ctx);
674 return ret;
677 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
678 if (!server_dn) {
679 talloc_free(tmp_ctx);
680 return ldb_module_oom(module);
683 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
684 if (ret != LDB_SUCCESS) {
685 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
686 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
687 talloc_free(tmp_ctx);
688 return ret;
691 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
692 if (ret != LDB_SUCCESS) {
693 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
694 ldb_errstring(ldb));
695 talloc_free(tmp_ctx);
696 return ret;
699 ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
700 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
701 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
702 talloc_free(tmp_ctx);
703 return ret;
706 if (ret != LDB_SUCCESS) {
707 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
708 ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
709 talloc_free(tmp_ctx);
710 return ret;
713 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
714 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
715 if (ret != LDB_SUCCESS) {
716 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
717 ldb_dn_get_linearized(rid_set_dn));
718 talloc_free(tmp_ctx);
719 return ret;
722 ridalloc_get_ridset_values(res->msgs[0], &oridset);
723 if (oridset.alloc_pool == UINT64_MAX) {
724 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
725 ldb_dn_get_linearized(rid_set_dn));
726 talloc_free(tmp_ctx);
727 return LDB_ERR_OPERATIONS_ERROR;
730 nridset = oridset;
732 if (exop->fsmo_info != 0) {
734 if (nridset.alloc_pool != exop->fsmo_info) {
735 /* it has already been updated */
736 DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
737 (unsigned long long)exop->fsmo_info,
738 (unsigned long long)nridset.alloc_pool));
739 talloc_free(tmp_ctx);
740 return LDB_SUCCESS;
744 /* grab a pool from the RID Manager object */
745 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
746 if (ret != LDB_SUCCESS) {
747 talloc_free(tmp_ctx);
748 return ret;
752 * update the values
754 msg = ldb_msg_new(tmp_ctx);
755 if (msg == NULL) {
756 return ldb_module_oom(module);
758 msg->dn = rid_set_dn;
760 ret = ridalloc_set_ridset_values(module, msg,
761 &oridset, &nridset);
762 if (ret != LDB_SUCCESS) {
763 talloc_free(tmp_ctx);
764 return ret;
767 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
768 if (ret != LDB_SUCCESS) {
769 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
770 ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
771 talloc_free(tmp_ctx);
772 return ret;
775 talloc_free(tmp_ctx);
776 return LDB_SUCCESS;