messaging4: Change irpc_servers_by_name to NTSTATUS
[Samba.git] / source4 / dsdb / samdb / ldb_modules / ridalloc.c
blob05764eeb4fe924ca75865f7d1bec3456e73290e2
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 int ridalloc_poke_rid_manager(struct ldb_module *module)
69 struct imessaging_context *msg;
70 unsigned num_servers;
71 struct server_id *servers;
72 struct ldb_context *ldb = ldb_module_get_ctx(module);
73 struct loadparm_context *lp_ctx =
74 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
75 TALLOC_CTX *tmp_ctx = talloc_new(module);
76 NTSTATUS status;
78 msg = imessaging_client_init(tmp_ctx, lp_ctx,
79 ldb_get_event_context(ldb));
80 if (!msg) {
81 ldb_asprintf_errstring(ldb_module_get_ctx(module),
82 "Failed to send MSG_DREPL_ALLOCATE_RID, "
83 "unable init client messaging context");
84 DEBUG(3,(__location__ ": Failed to create messaging context\n"));
85 talloc_free(tmp_ctx);
86 return LDB_ERR_UNWILLING_TO_PERFORM;
89 status = irpc_servers_byname(msg, msg, "dreplsrv",
90 &num_servers, &servers);
91 if (!NT_STATUS_IS_OK(status)) {
92 ldb_asprintf_errstring(ldb_module_get_ctx(module),
93 "Failed to send MSG_DREPL_ALLOCATE_RID, "
94 "unable to locate dreplsrv");
95 /* this means the drepl service is not running */
96 talloc_free(tmp_ctx);
97 return LDB_ERR_UNWILLING_TO_PERFORM;
100 status = imessaging_send(msg, servers[0], MSG_DREPL_ALLOCATE_RID, NULL);
102 /* Only error out if an error happened, not on STATUS_MORE_ENTRIES, ie a delayed message */
103 if (NT_STATUS_IS_ERR(status)) {
104 ldb_asprintf_errstring(ldb_module_get_ctx(module),
105 "Failed to send MSG_DREPL_ALLOCATE_RID to dreplsrv at %s: %s",
106 server_id_str(tmp_ctx, servers), nt_errstr(status));
107 talloc_free(tmp_ctx);
108 return LDB_ERR_UNWILLING_TO_PERFORM;
111 talloc_free(tmp_ctx);
112 return LDB_SUCCESS;
116 static const char * const ridalloc_ridset_attrs[] = {
117 "rIDAllocationPool",
118 "rIDPreviousAllocationPool",
119 "rIDNextRID",
120 "rIDUsedPool",
121 NULL
124 struct ridalloc_ridset_values {
125 uint64_t alloc_pool;
126 uint64_t prev_pool;
127 uint32_t next_rid;
128 uint32_t used_pool;
131 static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
133 v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
134 v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
135 v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
136 v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
139 static int ridalloc_set_ridset_values(struct ldb_module *module,
140 struct ldb_message *msg,
141 const struct ridalloc_ridset_values *o,
142 const struct ridalloc_ridset_values *n)
144 const uint32_t *o32, *n32;
145 const uint64_t *o64, *n64;
146 int ret;
148 #define SETUP_PTRS(field, optr, nptr, max) do { \
149 optr = &o->field; \
150 nptr = &n->field; \
151 if (o->field == max) { \
152 optr = NULL; \
154 if (n->field == max) { \
155 nptr = NULL; \
157 if (o->field == n->field) { \
158 optr = NULL; \
159 nptr = NULL; \
161 } while(0)
163 SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
164 ret = dsdb_msg_constrainted_update_uint64(module, msg,
165 "rIDAllocationPool",
166 o64, n64);
167 if (ret != LDB_SUCCESS) {
168 return ret;
171 SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
172 ret = dsdb_msg_constrainted_update_uint64(module, msg,
173 "rIDPreviousAllocationPool",
174 o64, n64);
175 if (ret != LDB_SUCCESS) {
176 return ret;
179 SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
180 ret = dsdb_msg_constrainted_update_uint32(module, msg,
181 "rIDNextRID",
182 o32, n32);
183 if (ret != LDB_SUCCESS) {
184 return ret;
187 SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
188 ret = dsdb_msg_constrainted_update_uint32(module, msg,
189 "rIDUsedPool",
190 o32, n32);
191 if (ret != LDB_SUCCESS) {
192 return ret;
194 #undef SETUP_PTRS
196 return LDB_SUCCESS;
200 allocate a new range of RIDs in the RID Manager object
202 static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool,
203 struct ldb_request *parent)
205 int ret;
206 TALLOC_CTX *tmp_ctx = talloc_new(module);
207 const char *attrs[] = { "rIDAvailablePool", NULL };
208 uint64_t rid_pool, new_rid_pool, dc_pool;
209 uint32_t rid_pool_lo, rid_pool_hi;
210 struct ldb_result *res;
211 struct ldb_context *ldb = ldb_module_get_ctx(module);
212 const unsigned alloc_size = 500;
214 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
215 attrs, DSDB_FLAG_NEXT_MODULE, parent);
216 if (ret != LDB_SUCCESS) {
217 ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
218 ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
219 talloc_free(tmp_ctx);
220 return ret;
223 rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
224 rid_pool_lo = rid_pool & 0xFFFFFFFF;
225 rid_pool_hi = rid_pool >> 32;
226 if (rid_pool_lo >= rid_pool_hi) {
227 ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
228 rid_pool_lo, rid_pool_hi);
229 talloc_free(tmp_ctx);
230 return ret;
233 /* lower part of new pool is the low part of the rIDAvailablePool */
234 dc_pool = rid_pool_lo;
236 /* allocate 500 RIDs to this DC */
237 rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
239 /* work out upper part of new pool */
240 dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
242 /* and new rIDAvailablePool value */
243 new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
245 ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
246 &rid_pool, &new_rid_pool, parent);
247 if (ret != LDB_SUCCESS) {
248 ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
249 ldb_errstring(ldb));
250 talloc_free(tmp_ctx);
251 return ret;
254 (*new_pool) = dc_pool;
255 talloc_free(tmp_ctx);
256 return LDB_SUCCESS;
260 create a RID Set object for the specified DC
262 static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
263 struct ldb_dn *rid_manager_dn,
264 struct ldb_dn *ntds_dn, struct ldb_dn **dn,
265 struct ldb_request *parent)
267 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
268 struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
269 int ret;
270 struct ldb_message *msg;
271 struct ldb_context *ldb = ldb_module_get_ctx(module);
272 static const struct ridalloc_ridset_values o = {
273 .alloc_pool = UINT64_MAX,
274 .prev_pool = UINT64_MAX,
275 .next_rid = UINT32_MAX,
276 .used_pool = UINT32_MAX,
278 struct ridalloc_ridset_values n = {
279 .alloc_pool = 0,
280 .prev_pool = 0,
281 .next_rid = 0,
282 .used_pool = 0,
284 const char *no_attrs[] = { NULL };
285 struct ldb_result *res;
288 steps:
290 find the machine object for the DC
291 construct the RID Set DN
292 load rIDAvailablePool to find next available set
293 modify RID Manager object to update rIDAvailablePool
294 add the RID Set object
295 link to the RID Set object in machine object
298 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
299 if (!server_dn) {
300 talloc_free(tmp_ctx);
301 return ldb_module_oom(module);
304 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
305 if (ret != LDB_SUCCESS) {
306 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
307 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
308 talloc_free(tmp_ctx);
309 return ret;
312 rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
313 if (rid_set_dn == NULL) {
314 talloc_free(tmp_ctx);
315 return ldb_module_oom(module);
318 if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
319 talloc_free(tmp_ctx);
320 return ldb_module_oom(module);
323 /* grab a pool from the RID Manager object */
324 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent);
325 if (ret != LDB_SUCCESS) {
326 talloc_free(tmp_ctx);
327 return ret;
330 /* create the RID Set object */
331 msg = ldb_msg_new(tmp_ctx);
332 msg->dn = rid_set_dn;
334 ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
335 if (ret != LDB_SUCCESS) {
336 talloc_free(tmp_ctx);
337 return ret;
340 ret = ridalloc_set_ridset_values(module, msg, &o, &n);
341 if (ret != LDB_SUCCESS) {
342 talloc_free(tmp_ctx);
343 return ret;
346 /* we need this to go all the way to the top of the module
347 * stack, as we need all the extra attributes added (including
348 * complex ones like ntsecuritydescriptor) */
349 ret = dsdb_module_add(module, msg, DSDB_FLAG_TOP_MODULE | DSDB_MODIFY_RELAX, parent);
350 if (ret != LDB_SUCCESS) {
351 ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
352 ldb_dn_get_linearized(msg->dn),
353 ldb_errstring(ldb));
354 talloc_free(tmp_ctx);
355 return ret;
358 /* add the rIDSetReferences link */
359 msg = ldb_msg_new(tmp_ctx);
360 msg->dn = machine_dn;
362 /* we need the extended DN of the RID Set object for
363 * rIDSetReferences */
364 ret = dsdb_module_search_dn(module, msg, &res, rid_set_dn, no_attrs,
365 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, parent);
366 if (ret != LDB_SUCCESS) {
367 ldb_asprintf_errstring(ldb, "Failed to find extended DN of RID Set %s - %s",
368 ldb_dn_get_linearized(msg->dn),
369 ldb_errstring(ldb));
370 talloc_free(tmp_ctx);
371 return ret;
373 rid_set_dn = res->msgs[0]->dn;
376 ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_extended_linearized(msg, rid_set_dn, 1));
377 if (ret != LDB_SUCCESS) {
378 talloc_free(tmp_ctx);
379 return ret;
381 msg->elements[0].flags = LDB_FLAG_MOD_ADD;
383 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
384 if (ret != LDB_SUCCESS) {
385 ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
386 ldb_dn_get_linearized(msg->dn),
387 ldb_errstring(ldb));
388 talloc_free(tmp_ctx);
389 return ret;
392 (*dn) = talloc_steal(mem_ctx, rid_set_dn);
394 talloc_free(tmp_ctx);
395 return LDB_SUCCESS;
400 create a RID Set object for this DC
402 static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
403 struct ldb_dn **dn, struct ldb_request *parent)
405 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
406 struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
407 int ret;
408 struct ldb_context *ldb = ldb_module_get_ctx(module);
409 struct GUID fsmo_role_guid;
410 const struct GUID *our_ntds_guid;
411 NTSTATUS status;
413 /* work out who is the RID Manager */
414 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
415 if (ret != LDB_SUCCESS) {
416 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
417 ldb_errstring(ldb));
418 talloc_free(tmp_ctx);
419 return ret;
422 /* find the DN of the RID Manager */
423 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
424 if (ret != LDB_SUCCESS) {
425 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
426 ldb_errstring(ldb));
427 talloc_free(tmp_ctx);
428 return ret;
431 status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID");
432 if (!NT_STATUS_IS_OK(status)) {
433 talloc_free(tmp_ctx);
434 return ldb_operr(ldb_module_get_ctx(module));
437 our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module));
438 if (!our_ntds_guid) {
439 talloc_free(tmp_ctx);
440 return ldb_operr(ldb_module_get_ctx(module));
443 if (!GUID_equal(&fsmo_role_guid, our_ntds_guid)) {
444 ret = ridalloc_poke_rid_manager(module);
445 if (ret != LDB_SUCCESS) {
446 ldb_asprintf_errstring(ldb,
447 "Request for remote creation of "
448 "RID Set for this DC failed: %s",
449 ldb_errstring(ldb));
450 } else {
451 ldb_asprintf_errstring(ldb,
452 "Remote RID Set creation needed");
454 talloc_free(tmp_ctx);
455 return LDB_ERR_UNWILLING_TO_PERFORM;
458 ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
459 talloc_free(tmp_ctx);
460 return ret;
464 get a new RID pool for ourselves
465 also returns the first rid for the new pool
467 static int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
469 TALLOC_CTX *tmp_ctx = talloc_new(module);
470 struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
471 int ret;
472 struct ldb_context *ldb = ldb_module_get_ctx(module);
473 bool is_us;
475 /* work out who is the RID Manager */
476 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
477 if (ret != LDB_SUCCESS) {
478 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
479 ldb_errstring(ldb));
480 talloc_free(tmp_ctx);
481 return ret;
484 /* find the DN of the RID Manager */
485 ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
486 if (ret != LDB_SUCCESS) {
487 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
488 ldb_errstring(ldb));
489 talloc_free(tmp_ctx);
490 return ret;
493 ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us);
494 if (ret != LDB_SUCCESS) {
495 ldb_asprintf_errstring(ldb, "Failed to confirm if our ntdsDsa is %s: %s",
496 ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb));
497 talloc_free(tmp_ctx);
498 return ret;
501 if (!is_us) {
502 ret = ridalloc_poke_rid_manager(module);
503 if (ret != LDB_SUCCESS) {
504 ldb_asprintf_errstring(ldb, "Request for remote refresh of RID Set allocation failed: %s",
505 ldb_errstring(ldb));
506 } else {
507 ldb_asprintf_errstring(ldb, "Remote RID Set refresh needed");
509 talloc_free(tmp_ctx);
510 return LDB_ERR_UNWILLING_TO_PERFORM;
513 /* grab a pool from the RID Manager object */
514 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
515 if (ret != LDB_SUCCESS) {
516 talloc_free(tmp_ctx);
517 return ret;
520 talloc_free(tmp_ctx);
521 return ret;
525 /* allocate a RID using our RID Set
526 If we run out of RIDs then allocate a new pool
527 either locally or by contacting the RID Manager
529 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
531 struct ldb_context *ldb;
532 int ret;
533 struct ldb_dn *rid_set_dn;
534 struct ldb_result *res;
535 struct ldb_message *msg;
536 struct ridalloc_ridset_values oridset;
537 struct ridalloc_ridset_values nridset;
538 uint32_t prev_pool_lo, prev_pool_hi;
539 TALLOC_CTX *tmp_ctx = talloc_new(module);
541 (*rid) = 0;
542 ldb = ldb_module_get_ctx(module);
544 ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
545 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
546 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
548 if (ret != LDB_SUCCESS) {
549 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
550 ldb_errstring(ldb));
551 talloc_free(tmp_ctx);
552 return ret;
555 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
556 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
557 if (ret != LDB_SUCCESS) {
558 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
559 ldb_dn_get_linearized(rid_set_dn));
560 talloc_free(tmp_ctx);
561 return ret;
564 ridalloc_get_ridset_values(res->msgs[0], &oridset);
565 if (oridset.alloc_pool == UINT64_MAX) {
566 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
567 ldb_dn_get_linearized(rid_set_dn));
568 talloc_free(tmp_ctx);
569 return LDB_ERR_OPERATIONS_ERROR;
572 nridset = oridset;
575 * If we never used a pool, setup out first pool
577 if (nridset.prev_pool == UINT64_MAX ||
578 nridset.next_rid == UINT32_MAX) {
579 nridset.prev_pool = nridset.alloc_pool;
580 nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
584 * Now check if our current pool is still usable
586 nridset.next_rid += 1;
587 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
588 prev_pool_hi = nridset.prev_pool >> 32;
589 if (nridset.next_rid > prev_pool_hi) {
591 * We need a new pool, check if we already have a new one
592 * Otherwise we need to get a new pool.
594 if (nridset.alloc_pool == nridset.prev_pool) {
596 * if we are the RID Manager,
597 * we can get a new pool localy.
598 * Otherwise we fail the operation and
599 * ask async for a new pool.
601 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
602 if (ret != LDB_SUCCESS) {
603 ldb_asprintf_errstring(ldb, "NO RID values available: %s",
604 ldb_errstring(ldb));
605 talloc_free(tmp_ctx);
606 return ret;
611 * increment the rIDUsedPool attribute
613 * Note: w2k8r2 doesn't update this attribute,
614 * at least if it's itself the rid master.
616 nridset.used_pool += 1;
618 /* now use the new pool */
619 nridset.prev_pool = nridset.alloc_pool;
620 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
621 prev_pool_hi = nridset.prev_pool >> 32;
622 nridset.next_rid = prev_pool_lo;
625 if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
626 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
627 (unsigned)nridset.next_rid,
628 (unsigned)prev_pool_lo,
629 (unsigned)prev_pool_hi);
630 talloc_free(tmp_ctx);
631 return LDB_ERR_OPERATIONS_ERROR;
635 * if we are half-exhausted then try to get a new pool.
637 if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2 &&
638 nridset.alloc_pool == nridset.prev_pool) {
640 * if we are the RID Manager,
641 * we can get a new pool localy.
642 * Otherwise we fail the operation and
643 * ask async for a new pool.
645 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
646 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
647 ldb_reset_err_string(ldb);
648 ret = LDB_SUCCESS;
650 if (ret != LDB_SUCCESS) {
651 talloc_free(tmp_ctx);
652 return ret;
657 * update the values
659 msg = ldb_msg_new(tmp_ctx);
660 if (msg == NULL) {
661 return ldb_module_oom(module);
663 msg->dn = rid_set_dn;
665 ret = ridalloc_set_ridset_values(module, msg,
666 &oridset, &nridset);
667 if (ret != LDB_SUCCESS) {
668 talloc_free(tmp_ctx);
669 return ret;
672 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
673 if (ret != LDB_SUCCESS) {
674 talloc_free(tmp_ctx);
675 return ret;
678 talloc_free(tmp_ctx);
679 *rid = nridset.next_rid;
680 return LDB_SUCCESS;
685 called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
687 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
688 struct ldb_request *parent)
690 struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
691 struct ldb_dn *rid_manager_dn;
692 TALLOC_CTX *tmp_ctx = talloc_new(module);
693 int ret;
694 struct ldb_context *ldb = ldb_module_get_ctx(module);
695 struct ldb_result *res;
696 struct ldb_message *msg;
697 struct ridalloc_ridset_values oridset, nridset;
699 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
700 if (ret != LDB_SUCCESS) {
701 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
702 GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
703 talloc_free(tmp_ctx);
704 return ret;
707 server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
708 if (!server_dn) {
709 talloc_free(tmp_ctx);
710 return ldb_module_oom(module);
713 ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
714 if (ret != LDB_SUCCESS) {
715 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
716 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
717 talloc_free(tmp_ctx);
718 return ret;
721 ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
722 if (ret != LDB_SUCCESS) {
723 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
724 ldb_errstring(ldb));
725 talloc_free(tmp_ctx);
726 return ret;
729 ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
730 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
731 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
732 talloc_free(tmp_ctx);
733 return ret;
736 if (ret != LDB_SUCCESS) {
737 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
738 ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
739 talloc_free(tmp_ctx);
740 return ret;
743 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
744 ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
745 if (ret != LDB_SUCCESS) {
746 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
747 ldb_dn_get_linearized(rid_set_dn));
748 talloc_free(tmp_ctx);
749 return ret;
752 ridalloc_get_ridset_values(res->msgs[0], &oridset);
753 if (oridset.alloc_pool == UINT64_MAX) {
754 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
755 ldb_dn_get_linearized(rid_set_dn));
756 talloc_free(tmp_ctx);
757 return LDB_ERR_OPERATIONS_ERROR;
760 nridset = oridset;
762 if (exop->fsmo_info != 0) {
764 if (nridset.alloc_pool != exop->fsmo_info) {
765 /* it has already been updated */
766 DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
767 (unsigned long long)exop->fsmo_info,
768 (unsigned long long)nridset.alloc_pool));
769 talloc_free(tmp_ctx);
770 return LDB_SUCCESS;
774 /* grab a pool from the RID Manager object */
775 ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
776 if (ret != LDB_SUCCESS) {
777 talloc_free(tmp_ctx);
778 return ret;
782 * update the values
784 msg = ldb_msg_new(tmp_ctx);
785 if (msg == NULL) {
786 return ldb_module_oom(module);
788 msg->dn = rid_set_dn;
790 ret = ridalloc_set_ridset_values(module, msg,
791 &oridset, &nridset);
792 if (ret != LDB_SUCCESS) {
793 talloc_free(tmp_ctx);
794 return ret;
797 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
798 if (ret != LDB_SUCCESS) {
799 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
800 ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
801 talloc_free(tmp_ctx);
802 return ret;
805 talloc_free(tmp_ctx);
806 return LDB_SUCCESS;