s4:dsdb:ridalloc: use ridalloc_ridset_values infrastructure in ridalloc_allocate_rid()
[Samba/ita.git] / source4 / dsdb / samdb / ldb_modules / ridalloc.c
blob2dd4c563c8e2fbdcb5c2baa094186aa90c537d15
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"
39 Note: the RID allocation attributes in AD are very badly named. Here
40 is what we think they really do:
42 in RID Set object:
43 - rIDPreviousAllocationPool: the pool which a DC is currently
44 pulling RIDs from. Managed by client DC
46 - rIDAllocationPool: the pool that the DC will switch to next,
47 when rIDPreviousAllocationPool is exhausted. Managed by RID Manager.
49 - rIDNextRID: the last RID allocated by this DC. Managed by client DC
51 in RID Manager object:
52 - rIDAvailablePool: the pool where the RID Manager gets new rID
53 pools from when it gets a EXOP_RID_ALLOC getncchanges call (or
54 locally when the DC is the RID Manager)
59 make a IRPC call to the drepl task to ask it to get the RID
60 Manager to give us another RID pool.
62 This function just sends the message to the drepl task then
63 returns immediately. It should be called well before we
64 completely run out of RIDs
66 static void ridalloc_poke_rid_manager(struct ldb_module *module)
68 struct messaging_context *msg;
69 struct server_id *server;
70 struct ldb_context *ldb = ldb_module_get_ctx(module);
71 struct loadparm_context *lp_ctx =
72 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
73 TALLOC_CTX *tmp_ctx = talloc_new(module);
75 msg = messaging_client_init(tmp_ctx, lp_messaging_path(tmp_ctx, lp_ctx),
76 ldb_get_event_context(ldb));
77 if (!msg) {
78 DEBUG(3,(__location__ ": Failed to create messaging context\n"));
79 talloc_free(tmp_ctx);
80 return;
83 server = irpc_servers_byname(msg, msg, "dreplsrv");
84 if (!server) {
85 /* this means the drepl service is not running */
86 talloc_free(tmp_ctx);
87 return;
90 messaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL);
92 /* we don't care if the message got through */
93 talloc_free(tmp_ctx);
97 static const char * const ridalloc_ridset_attrs[] = {
98 "rIDAllocationPool",
99 "rIDPreviousAllocationPool",
100 "rIDNextRID",
101 "rIDUsedPool",
102 NULL
105 struct ridalloc_ridset_values {
106 uint64_t alloc_pool;
107 uint64_t prev_pool;
108 uint32_t next_rid;
109 uint32_t used_pool;
112 static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
114 v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
115 v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
116 v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
117 v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
120 static int ridalloc_set_ridset_values(struct ldb_module *module,
121 struct ldb_message *msg,
122 const struct ridalloc_ridset_values *o,
123 const struct ridalloc_ridset_values *n)
125 const uint32_t *o32, *n32;
126 const uint64_t *o64, *n64;
127 int ret;
129 #define SETUP_PTRS(field, optr, nptr, max) do { \
130 optr = &o->field; \
131 nptr = &n->field; \
132 if (o->field == max) { \
133 optr = NULL; \
135 if (n->field == max) { \
136 nptr = NULL; \
138 if (o->field == n->field) { \
139 optr = NULL; \
140 nptr = NULL; \
142 } while(0)
144 SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
145 ret = dsdb_msg_constrainted_update_uint64(module, msg,
146 "rIDAllocationPool",
147 o64, n64);
148 if (ret != LDB_SUCCESS) {
149 return ret;
152 SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
153 ret = dsdb_msg_constrainted_update_uint64(module, msg,
154 "rIDPreviousAllocationPool",
155 o64, n64);
156 if (ret != LDB_SUCCESS) {
157 return ret;
160 SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
161 ret = dsdb_msg_constrainted_update_uint32(module, msg,
162 "rIDNextRID",
163 o32, n32);
164 if (ret != LDB_SUCCESS) {
165 return ret;
168 SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
169 ret = dsdb_msg_constrainted_update_uint32(module, msg,
170 "rIDUsedPool",
171 o32, n32);
172 if (ret != LDB_SUCCESS) {
173 return ret;
175 #undef SETUP_PTRS
177 return LDB_SUCCESS;
181 allocate a new range of RIDs in the RID Manager object
183 static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool)
185 int ret;
186 TALLOC_CTX *tmp_ctx = talloc_new(module);
187 const char *attrs[] = { "rIDAvailablePool", NULL };
188 uint64_t rid_pool, new_rid_pool, dc_pool;
189 uint32_t rid_pool_lo, rid_pool_hi;
190 struct ldb_result *res;
191 struct ldb_context *ldb = ldb_module_get_ctx(module);
192 const unsigned alloc_size = 500;
194 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
195 attrs, DSDB_FLAG_NEXT_MODULE);
196 if (ret != LDB_SUCCESS) {
197 ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
198 ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
199 talloc_free(tmp_ctx);
200 return ret;
203 rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
204 rid_pool_lo = rid_pool & 0xFFFFFFFF;
205 rid_pool_hi = rid_pool >> 32;
206 if (rid_pool_lo >= rid_pool_hi) {
207 ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
208 rid_pool_lo, rid_pool_hi);
209 talloc_free(tmp_ctx);
210 return ret;
213 /* lower part of new pool is the low part of the rIDAvailablePool */
214 dc_pool = rid_pool_lo;
216 /* allocate 500 RIDs to this DC */
217 rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
219 /* work out upper part of new pool */
220 dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
222 /* and new rIDAvailablePool value */
223 new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
225 ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
226 &rid_pool, &new_rid_pool);
227 if (ret != LDB_SUCCESS) {
228 ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
229 ldb_errstring(ldb));
230 talloc_free(tmp_ctx);
231 return ret;
234 (*new_pool) = dc_pool;
235 talloc_free(tmp_ctx);
236 return LDB_SUCCESS;
240 create a RID Set object for the specified DC
242 static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
243 struct ldb_dn *rid_manager_dn,
244 struct ldb_dn *ntds_dn, struct ldb_dn **dn)
246 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
247 struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
248 int ret;
249 struct ldb_message *msg;
250 struct ldb_context *ldb = ldb_module_get_ctx(module);
251 static const struct ridalloc_ridset_values o = {
252 .alloc_pool = UINT64_MAX,
253 .prev_pool = UINT64_MAX,
254 .next_rid = UINT32_MAX,
255 .used_pool = UINT32_MAX,
257 struct ridalloc_ridset_values n = {
258 .alloc_pool = 0,
259 .prev_pool = 0,
260 .next_rid = 0,
261 .used_pool = 0,
265 steps:
267 find the machine object for the DC
268 construct the RID Set DN
269 load rIDAvailablePool to find next available set
270 modify RID Manager object to update rIDAvailablePool
271 add the RID Set object
272 link to the RID Set object in machine object
275 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
276 if (!server_dn) {
277 talloc_free(tmp_ctx);
278 return ldb_module_oom(module);
281 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
282 if (ret != LDB_SUCCESS) {
283 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
284 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
285 talloc_free(tmp_ctx);
286 return ret;
289 rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
290 if (rid_set_dn == NULL) {
291 talloc_free(tmp_ctx);
292 return ldb_module_oom(module);
295 if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
296 talloc_free(tmp_ctx);
297 return ldb_module_oom(module);
300 /* grab a pool from the RID Manager object */
301 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool);
302 if (ret != LDB_SUCCESS) {
303 talloc_free(tmp_ctx);
304 return ret;
307 /* create the RID Set object */
308 msg = ldb_msg_new(tmp_ctx);
309 msg->dn = rid_set_dn;
311 ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
312 if (ret != LDB_SUCCESS) {
313 talloc_free(tmp_ctx);
314 return ret;
317 ret = ridalloc_set_ridset_values(module, msg, &o, &n);
318 if (ret != LDB_SUCCESS) {
319 talloc_free(tmp_ctx);
320 return ret;
323 /* we need this to go all the way to the top of the module
324 * stack, as we need all the extra attributes added (including
325 * complex ones like ntsecuritydescriptor) */
326 ret = dsdb_module_add(module, msg, DSDB_FLAG_TOP_MODULE | DSDB_MODIFY_RELAX);
327 if (ret != LDB_SUCCESS) {
328 ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
329 ldb_dn_get_linearized(msg->dn),
330 ldb_errstring(ldb));
331 talloc_free(tmp_ctx);
332 return ret;
335 /* add the rIDSetReferences link */
336 msg = ldb_msg_new(tmp_ctx);
337 msg->dn = machine_dn;
339 ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_linearized(rid_set_dn));
340 if (ret != LDB_SUCCESS) {
341 talloc_free(tmp_ctx);
342 return ret;
344 msg->elements[0].flags = LDB_FLAG_MOD_ADD;
346 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
347 if (ret != LDB_SUCCESS) {
348 ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
349 ldb_dn_get_linearized(msg->dn),
350 ldb_errstring(ldb));
351 talloc_free(tmp_ctx);
352 return ret;
355 (*dn) = talloc_steal(mem_ctx, rid_set_dn);
357 talloc_free(tmp_ctx);
358 return LDB_SUCCESS;
363 create a RID Set object for this DC
365 static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
366 struct ldb_dn **dn)
368 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
369 struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
370 int ret;
371 struct ldb_context *ldb = ldb_module_get_ctx(module);
373 /* work out who is the RID Manager */
374 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
375 if (ret != LDB_SUCCESS) {
376 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
377 ldb_errstring(ldb));
378 talloc_free(tmp_ctx);
379 return ret;
382 /* find the DN of the RID Manager */
383 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
384 if (ret != LDB_SUCCESS) {
385 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
386 ldb_errstring(ldb));
387 talloc_free(tmp_ctx);
388 return ret;
391 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
392 ridalloc_poke_rid_manager(module);
393 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
394 talloc_free(tmp_ctx);
395 return LDB_ERR_UNWILLING_TO_PERFORM;
398 ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn);
399 talloc_free(tmp_ctx);
400 return ret;
404 refresh a RID Set object for the specified DC
405 also returns the first RID for the new pool
407 static int ridalloc_refresh_rid_set_ntds(struct ldb_module *module,
408 struct ldb_dn *rid_manager_dn,
409 struct ldb_dn *ntds_dn, uint64_t *new_pool)
411 TALLOC_CTX *tmp_ctx = talloc_new(module);
412 struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
413 struct ldb_context *ldb = ldb_module_get_ctx(module);
414 int ret;
416 /* grab a pool from the RID Manager object */
417 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool);
418 if (ret != LDB_SUCCESS) {
419 talloc_free(tmp_ctx);
420 return ret;
423 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
424 if (!server_dn) {
425 talloc_free(tmp_ctx);
426 return ldb_module_oom(module);
429 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
430 if (ret != LDB_SUCCESS) {
431 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
432 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
433 talloc_free(tmp_ctx);
434 return ret;
437 ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn);
438 if (ret != LDB_SUCCESS) {
439 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
440 ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
441 talloc_free(tmp_ctx);
442 return ret;
445 ret = dsdb_module_set_integer(module, rid_set_dn, "rIDAllocationPool", *new_pool);
446 if (ret != LDB_SUCCESS) {
447 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
448 ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
449 talloc_free(tmp_ctx);
450 return ret;
453 talloc_free(tmp_ctx);
454 return LDB_SUCCESS;
459 get a new RID pool for ourselves
460 also returns the first rid for the new pool
462 static int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool)
464 TALLOC_CTX *tmp_ctx = talloc_new(module);
465 struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
466 int ret;
467 struct ldb_context *ldb = ldb_module_get_ctx(module);
469 /* work out who is the RID Manager */
470 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
471 if (ret != LDB_SUCCESS) {
472 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
473 ldb_errstring(ldb));
474 talloc_free(tmp_ctx);
475 return ret;
478 /* find the DN of the RID Manager */
479 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
480 if (ret != LDB_SUCCESS) {
481 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
482 ldb_errstring(ldb));
483 talloc_free(tmp_ctx);
484 return ret;
487 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
488 ridalloc_poke_rid_manager(module);
489 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
490 talloc_free(tmp_ctx);
491 return LDB_ERR_UNWILLING_TO_PERFORM;
494 /* grab a pool from the RID Manager object */
495 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool);
496 if (ret != LDB_SUCCESS) {
497 talloc_free(tmp_ctx);
498 return ret;
501 talloc_free(tmp_ctx);
502 return ret;
506 /* allocate a RID using our RID Set
507 If we run out of RIDs then allocate a new pool
508 either locally or by contacting the RID Manager
510 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
512 struct ldb_context *ldb;
513 int ret;
514 struct ldb_dn *rid_set_dn;
515 struct ldb_result *res;
516 struct ldb_message *msg;
517 struct ridalloc_ridset_values oridset;
518 struct ridalloc_ridset_values nridset;
519 uint32_t prev_pool_lo, prev_pool_hi;
520 TALLOC_CTX *tmp_ctx = talloc_new(module);
522 (*rid) = 0;
523 ldb = ldb_module_get_ctx(module);
525 ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
526 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
527 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn);
529 if (ret != LDB_SUCCESS) {
530 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
531 ldb_errstring(ldb));
532 talloc_free(tmp_ctx);
533 return ret;
536 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
537 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE);
538 if (ret != LDB_SUCCESS) {
539 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
540 ldb_dn_get_linearized(rid_set_dn));
541 talloc_free(tmp_ctx);
542 return ret;
545 ridalloc_get_ridset_values(res->msgs[0], &oridset);
546 if (oridset.alloc_pool == UINT64_MAX) {
547 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
548 ldb_dn_get_linearized(rid_set_dn));
549 talloc_free(tmp_ctx);
550 return LDB_ERR_OPERATIONS_ERROR;
553 nridset = oridset;
556 * If we never used a pool, setup out first pool
558 if (nridset.prev_pool == UINT64_MAX ||
559 nridset.next_rid == UINT32_MAX) {
560 nridset.prev_pool = nridset.alloc_pool;
561 nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
565 * Now check if our current pool is still usable
567 nridset.next_rid += 1;
568 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
569 prev_pool_hi = nridset.prev_pool >> 32;
570 if (nridset.next_rid > prev_pool_hi) {
572 * We need a new pool, check if we already have a new one
573 * Otherwise we need to get a new pool.
575 if (nridset.alloc_pool == nridset.prev_pool) {
577 * if we are the RID Manager,
578 * we can get a new pool localy.
579 * Otherwise we fail the operation and
580 * ask async for a new pool.
582 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool);
583 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
584 ridalloc_poke_rid_manager(module);
585 talloc_free(tmp_ctx);
586 return ret;
588 if (ret != LDB_SUCCESS) {
589 talloc_free(tmp_ctx);
590 return ret;
595 * increment the rIDUsedPool attribute
597 * Note: w2k8r2 doesn't update this attribute,
598 * at least if it's itself the rid master.
600 nridset.used_pool += 1;
602 /* now use the new pool */
603 nridset.prev_pool = nridset.alloc_pool;
604 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
605 prev_pool_hi = nridset.prev_pool >> 32;
606 nridset.next_rid = prev_pool_lo;
609 if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
610 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
611 (unsigned)nridset.next_rid,
612 (unsigned)prev_pool_lo,
613 (unsigned)prev_pool_hi);
614 talloc_free(tmp_ctx);
615 return LDB_ERR_OPERATIONS_ERROR;
619 * if we are half-exhausted then try to get a new pool.
621 if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2) {
623 * if we are the RID Manager,
624 * we can get a new pool localy.
625 * Otherwise we fail the operation and
626 * ask async for a new pool.
628 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool);
629 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
630 ridalloc_poke_rid_manager(module);
631 ret = LDB_SUCCESS;
633 if (ret != LDB_SUCCESS) {
634 talloc_free(tmp_ctx);
635 return ret;
640 * update the values
642 msg = ldb_msg_new(tmp_ctx);
643 if (msg == NULL) {
644 return ldb_module_oom(module);
646 msg->dn = rid_set_dn;
648 ret = ridalloc_set_ridset_values(module, msg,
649 &oridset, &nridset);
650 if (ret != LDB_SUCCESS) {
651 talloc_free(tmp_ctx);
652 return ret;
655 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
656 if (ret != LDB_SUCCESS) {
657 talloc_free(tmp_ctx);
658 return ret;
661 talloc_free(tmp_ctx);
662 *rid = nridset.next_rid;
663 return LDB_SUCCESS;
668 called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
670 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop)
672 struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
673 struct ldb_dn *rid_manager_dn;
674 TALLOC_CTX *tmp_ctx = talloc_new(module);
675 int ret;
676 struct ldb_context *ldb = ldb_module_get_ctx(module);
677 uint64_t new_pool;
679 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn);
680 if (ret != LDB_SUCCESS) {
681 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
682 GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
683 talloc_free(tmp_ctx);
684 return ret;
687 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
688 if (!server_dn) {
689 talloc_free(tmp_ctx);
690 return ldb_module_oom(module);
693 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
694 if (ret != LDB_SUCCESS) {
695 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
696 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
697 talloc_free(tmp_ctx);
698 return ret;
702 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
703 if (ret != LDB_SUCCESS) {
704 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
705 ldb_errstring(ldb));
706 talloc_free(tmp_ctx);
707 return ret;
710 ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn);
711 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
712 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn);
713 talloc_free(tmp_ctx);
714 return ret;
717 if (ret != LDB_SUCCESS) {
718 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
719 ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
720 talloc_free(tmp_ctx);
721 return ret;
724 if (exop->fsmo_info != 0) {
725 const char *attrs[] = { "rIDAllocationPool", NULL };
726 struct ldb_result *res;
727 uint64_t alloc_pool;
729 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
730 attrs, DSDB_FLAG_NEXT_MODULE);
731 if (ret != LDB_SUCCESS) {
732 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
733 ldb_dn_get_linearized(rid_set_dn));
734 talloc_free(tmp_ctx);
735 return ret;
738 alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
739 if (alloc_pool != exop->fsmo_info) {
740 /* it has already been updated */
741 DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
742 (unsigned long long)exop->fsmo_info,
743 (unsigned long long)alloc_pool));
744 talloc_free(tmp_ctx);
745 return LDB_SUCCESS;
749 ret = ridalloc_refresh_rid_set_ntds(module, rid_manager_dn, ntds_dn, &new_pool);
750 talloc_free(tmp_ctx);
751 return ret;