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/>.
24 * Component: RID allocation logic
26 * Description: manage RID Set and RID Manager objects
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:
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
;
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
);
78 msg
= imessaging_client_init(tmp_ctx
, lp_ctx
,
79 ldb_get_event_context(ldb
));
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"));
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 */
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
);
116 static const char * const ridalloc_ridset_attrs
[] = {
118 "rIDPreviousAllocationPool",
124 struct ridalloc_ridset_values
{
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
;
148 #define SETUP_PTRS(field, optr, nptr, max) do { \
151 if (o->field == max) { \
154 if (n->field == max) { \
157 if (o->field == n->field) { \
163 SETUP_PTRS(alloc_pool
, o64
, n64
, UINT64_MAX
);
164 ret
= dsdb_msg_constrainted_update_uint64(module
, msg
,
167 if (ret
!= LDB_SUCCESS
) {
171 SETUP_PTRS(prev_pool
, o64
, n64
, UINT64_MAX
);
172 ret
= dsdb_msg_constrainted_update_uint64(module
, msg
,
173 "rIDPreviousAllocationPool",
175 if (ret
!= LDB_SUCCESS
) {
179 SETUP_PTRS(next_rid
, o32
, n32
, UINT32_MAX
);
180 ret
= dsdb_msg_constrainted_update_uint32(module
, msg
,
183 if (ret
!= LDB_SUCCESS
) {
187 SETUP_PTRS(used_pool
, o32
, n32
, UINT32_MAX
);
188 ret
= dsdb_msg_constrainted_update_uint32(module
, msg
,
191 if (ret
!= 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
)
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
);
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
);
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",
250 talloc_free(tmp_ctx
);
254 (*new_pool
) = dc_pool
;
255 talloc_free(tmp_ctx
);
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
;
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
= {
284 const char *no_attrs
[] = { NULL
};
285 struct ldb_result
*res
;
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
);
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
);
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
);
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
);
340 ret
= ridalloc_set_ridset_values(module
, msg
, &o
, &n
);
341 if (ret
!= LDB_SUCCESS
) {
342 talloc_free(tmp_ctx
);
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
),
354 talloc_free(tmp_ctx
);
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
),
370 talloc_free(tmp_ctx
);
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
);
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
),
388 talloc_free(tmp_ctx
);
392 (*dn
) = talloc_steal(mem_ctx
, rid_set_dn
);
394 talloc_free(tmp_ctx
);
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
;
408 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
409 struct GUID fsmo_role_guid
;
410 const struct GUID
*our_ntds_guid
;
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",
418 talloc_free(tmp_ctx
);
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",
427 talloc_free(tmp_ctx
);
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",
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
);
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
;
472 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
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",
480 talloc_free(tmp_ctx
);
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",
489 talloc_free(tmp_ctx
);
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
);
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",
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
);
520 talloc_free(tmp_ctx
);
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
;
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
);
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",
551 talloc_free(tmp_ctx
);
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
);
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
;
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",
605 talloc_free(tmp_ctx
);
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
);
650 if (ret
!= LDB_SUCCESS
) {
651 talloc_free(tmp_ctx
);
659 msg
= ldb_msg_new(tmp_ctx
);
661 return ldb_module_oom(module
);
663 msg
->dn
= rid_set_dn
;
665 ret
= ridalloc_set_ridset_values(module
, msg
,
667 if (ret
!= LDB_SUCCESS
) {
668 talloc_free(tmp_ctx
);
672 ret
= dsdb_module_modify(module
, msg
, DSDB_FLAG_NEXT_MODULE
, parent
);
673 if (ret
!= LDB_SUCCESS
) {
674 talloc_free(tmp_ctx
);
678 talloc_free(tmp_ctx
);
679 *rid
= nridset
.next_rid
;
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
);
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
);
707 server_dn
= ldb_dn_get_parent(tmp_ctx
, ntds_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
);
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",
725 talloc_free(tmp_ctx
);
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
);
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
);
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
);
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
;
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
);
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
);
784 msg
= ldb_msg_new(tmp_ctx
);
786 return ldb_module_oom(module
);
788 msg
->dn
= rid_set_dn
;
790 ret
= ridalloc_set_ridset_values(module
, msg
,
792 if (ret
!= LDB_SUCCESS
) {
793 talloc_free(tmp_ctx
);
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
);
805 talloc_free(tmp_ctx
);