s4:dsdb:ridalloc: use ridalloc_ridset_values infrastructure in ridalloc_create_rid_se...
[Samba.git] / source4 / dsdb / samdb / ldb_modules / ridalloc.c
blob6b5f2f9f1da18b56960a1002a49cc9aef099c71f
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_refresh_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 ret = ridalloc_refresh_rid_set_ntds(module, rid_manager_dn, fsmo_role_dn, new_pool);
495 talloc_free(tmp_ctx);
496 return ret;
500 /* allocate a RID using our RID Set
501 If we run out of RIDs then allocate a new pool
502 either locally or by contacting the RID Manager
504 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
506 struct ldb_context *ldb;
507 static const char * const attrs[] = { "rIDAllocationPool", "rIDPreviousAllocationPool",
508 "rIDNextRID" , "rIDUsedPool", NULL };
509 int ret;
510 struct ldb_dn *rid_set_dn;
511 struct ldb_result *res;
512 uint64_t alloc_pool, prev_alloc_pool;
513 uint32_t prev_alloc_pool_lo, prev_alloc_pool_hi;
514 uint32_t rid_used_pool;
515 int prev_rid;
516 TALLOC_CTX *tmp_ctx = talloc_new(module);
518 (*rid) = 0;
519 ldb = ldb_module_get_ctx(module);
521 ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
522 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
523 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn);
525 if (ret != LDB_SUCCESS) {
526 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
527 ldb_errstring(ldb));
528 talloc_free(tmp_ctx);
529 return ret;
532 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
533 attrs, DSDB_FLAG_NEXT_MODULE);
534 if (ret != LDB_SUCCESS) {
535 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
536 ldb_dn_get_linearized(rid_set_dn));
537 talloc_free(tmp_ctx);
538 return ret;
541 prev_alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDPreviousAllocationPool", 0);
542 alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
543 prev_rid = ldb_msg_find_attr_as_int(res->msgs[0], "rIDNextRID", 0);
544 rid_used_pool = ldb_msg_find_attr_as_int(res->msgs[0], "rIDUsedPool", 0);
545 if (alloc_pool == 0) {
546 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
547 ldb_dn_get_linearized(rid_set_dn));
548 talloc_free(tmp_ctx);
549 return LDB_ERR_OPERATIONS_ERROR;
552 prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
553 prev_alloc_pool_hi = prev_alloc_pool >> 32;
554 if (prev_rid >= prev_alloc_pool_hi) {
555 if (prev_alloc_pool == 0) {
556 ret = dsdb_module_set_integer(module, rid_set_dn, "rIDPreviousAllocationPool", alloc_pool);
557 } else {
558 ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool",
559 prev_alloc_pool, alloc_pool);
561 if (ret != LDB_SUCCESS) {
562 ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s",
563 ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
564 talloc_free(tmp_ctx);
565 return ret;
567 prev_alloc_pool = alloc_pool;
568 prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
569 prev_alloc_pool_hi = prev_alloc_pool >> 32;
572 * update the rIDUsedPool attribute
574 * Note: w2k8r2 doesn't update this attribute,
575 * at least if it's itself the rid master.
577 ret = dsdb_module_set_integer(module, rid_set_dn, "rIDUsedPool", rid_used_pool+1);
578 if (ret != LDB_SUCCESS) {
579 ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDUsedPool on %s - %s",
580 ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
581 talloc_free(tmp_ctx);
582 return ret;
585 (*rid) = prev_alloc_pool_lo;
588 /* see if we are still out of RIDs, and if so then ask
589 the RID Manager to give us more */
590 if (prev_rid >= prev_alloc_pool_hi) {
591 uint64_t new_pool;
592 ret = ridalloc_refresh_own_pool(module, &new_pool);
593 if (ret != LDB_SUCCESS) {
594 talloc_free(tmp_ctx);
595 return ret;
597 ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool",
598 prev_alloc_pool, new_pool);
599 if (ret != LDB_SUCCESS) {
600 ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s",
601 ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
602 talloc_free(tmp_ctx);
603 return ret;
605 prev_alloc_pool = new_pool;
606 prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
607 prev_alloc_pool_hi = prev_alloc_pool >> 32;
608 (*rid) = prev_alloc_pool_lo;
609 } else {
610 /* despite the name, rIDNextRID is the value of the last user
611 * added by this DC, not the next available RID */
612 if (*rid == 0) {
613 (*rid) = prev_rid + 1;
617 if (*rid < prev_alloc_pool_lo || *rid > prev_alloc_pool_hi) {
618 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
619 (unsigned)*rid, (unsigned)prev_alloc_pool_lo,
620 (unsigned)prev_alloc_pool_hi);
621 talloc_free(tmp_ctx);
622 return LDB_ERR_OPERATIONS_ERROR;
625 /* now modify the RID Set to use up this RID using a
626 * constrained delete/add if possible */
627 if (prev_rid == 0) {
628 ret = dsdb_module_set_integer(module, rid_set_dn, "rIDNextRID", *rid);
629 } else {
630 ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDNextRID", prev_rid, *rid);
633 /* if we are half-exhausted then ask the repl task to start
634 * getting another one */
635 if (*rid > (prev_alloc_pool_hi + prev_alloc_pool_lo)/2) {
636 ridalloc_poke_rid_manager(module);
639 talloc_free(tmp_ctx);
641 return ret;
646 called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
648 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop)
650 struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
651 struct ldb_dn *rid_manager_dn;
652 TALLOC_CTX *tmp_ctx = talloc_new(module);
653 int ret;
654 struct ldb_context *ldb = ldb_module_get_ctx(module);
655 uint64_t new_pool;
657 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn);
658 if (ret != LDB_SUCCESS) {
659 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
660 GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
661 talloc_free(tmp_ctx);
662 return ret;
665 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
666 if (!server_dn) {
667 talloc_free(tmp_ctx);
668 return ldb_module_oom(module);
671 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
672 if (ret != LDB_SUCCESS) {
673 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
674 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
675 talloc_free(tmp_ctx);
676 return ret;
680 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
681 if (ret != LDB_SUCCESS) {
682 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
683 ldb_errstring(ldb));
684 talloc_free(tmp_ctx);
685 return ret;
688 ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn);
689 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
690 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn);
691 talloc_free(tmp_ctx);
692 return ret;
695 if (ret != LDB_SUCCESS) {
696 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
697 ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
698 talloc_free(tmp_ctx);
699 return ret;
702 if (exop->fsmo_info != 0) {
703 const char *attrs[] = { "rIDAllocationPool", NULL };
704 struct ldb_result *res;
705 uint64_t alloc_pool;
707 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
708 attrs, DSDB_FLAG_NEXT_MODULE);
709 if (ret != LDB_SUCCESS) {
710 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
711 ldb_dn_get_linearized(rid_set_dn));
712 talloc_free(tmp_ctx);
713 return ret;
716 alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
717 if (alloc_pool != exop->fsmo_info) {
718 /* it has already been updated */
719 DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
720 (unsigned long long)exop->fsmo_info,
721 (unsigned long long)alloc_pool));
722 talloc_free(tmp_ctx);
723 return LDB_SUCCESS;
727 ret = ridalloc_refresh_rid_set_ntds(module, rid_manager_dn, ntds_dn, &new_pool);
728 talloc_free(tmp_ctx);
729 return ret;