Line data Source code
1 : /*
2 : RID allocation helper functions
3 :
4 : Copyright (C) Andrew Bartlett 2010
5 : Copyright (C) Andrew Tridgell 2010
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
21 : /*
22 : * Name: ldb
23 : *
24 : * Component: RID allocation logic
25 : *
26 : * Description: manage RID Set and RID Manager objects
27 : *
28 : */
29 :
30 : #include "includes.h"
31 : #include "ldb_module.h"
32 : #include "lib/util/server_id.h"
33 : #include "dsdb/samdb/samdb.h"
34 : #include "dsdb/samdb/ldb_modules/util.h"
35 : #include "lib/messaging/irpc.h"
36 : #include "param/param.h"
37 : #include "librpc/gen_ndr/ndr_misc.h"
38 : #include "dsdb/samdb/ldb_modules/ridalloc.h"
39 :
40 : /*
41 : Note: the RID allocation attributes in AD are very badly named. Here
42 : is what we think they really do:
43 :
44 : in RID Set object:
45 : - rIDPreviousAllocationPool: the pool which a DC is currently
46 : pulling RIDs from. Managed by client DC
47 :
48 : - rIDAllocationPool: the pool that the DC will switch to next,
49 : when rIDPreviousAllocationPool is exhausted. Managed by RID Manager.
50 :
51 : - rIDNextRID: the last RID allocated by this DC. Managed by client DC
52 :
53 : in RID Manager object:
54 : - rIDAvailablePool: the pool where the RID Manager gets new rID
55 : pools from when it gets a EXOP_RID_ALLOC getncchanges call (or
56 : locally when the DC is the RID Manager)
57 : */
58 :
59 :
60 : /*
61 : make a IRPC call to the drepl task to ask it to get the RID
62 : Manager to give us another RID pool.
63 :
64 : This function just sends the message to the drepl task then
65 : returns immediately. It should be called well before we
66 : completely run out of RIDs
67 : */
68 246 : static int ridalloc_poke_rid_manager(struct ldb_module *module)
69 : {
70 0 : struct imessaging_context *msg;
71 0 : unsigned num_servers;
72 0 : struct server_id *servers;
73 246 : struct ldb_context *ldb = ldb_module_get_ctx(module);
74 0 : struct loadparm_context *lp_ctx =
75 246 : (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
76 246 : TALLOC_CTX *tmp_ctx = talloc_new(module);
77 0 : NTSTATUS status;
78 :
79 246 : msg = imessaging_client_init(tmp_ctx, lp_ctx,
80 : ldb_get_event_context(ldb));
81 246 : if (!msg) {
82 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
83 : "Failed to send MSG_DREPL_ALLOCATE_RID, "
84 : "unable init client messaging context");
85 0 : DEBUG(3,(__location__ ": Failed to create messaging context\n"));
86 0 : talloc_free(tmp_ctx);
87 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
88 : }
89 :
90 246 : status = irpc_servers_byname(msg, msg, "dreplsrv",
91 : &num_servers, &servers);
92 246 : if (!NT_STATUS_IS_OK(status)) {
93 240 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
94 : "Failed to send MSG_DREPL_ALLOCATE_RID, "
95 : "unable to locate dreplsrv");
96 : /* this means the drepl service is not running */
97 240 : talloc_free(tmp_ctx);
98 240 : return LDB_ERR_UNWILLING_TO_PERFORM;
99 : }
100 :
101 6 : status = imessaging_send(msg, servers[0], MSG_DREPL_ALLOCATE_RID, NULL);
102 :
103 : /* Only error out if an error happened, not on STATUS_MORE_ENTRIES, ie a delayed message */
104 6 : if (NT_STATUS_IS_ERR(status)) {
105 0 : struct server_id_buf idbuf;
106 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
107 : "Failed to send MSG_DREPL_ALLOCATE_RID to dreplsrv at %s: %s",
108 : server_id_str_buf(*servers, &idbuf),
109 : nt_errstr(status));
110 0 : talloc_free(tmp_ctx);
111 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
112 : }
113 :
114 6 : talloc_free(tmp_ctx);
115 6 : return LDB_SUCCESS;
116 : }
117 :
118 :
119 : static const char * const ridalloc_ridset_attrs[] = {
120 : "rIDAllocationPool",
121 : "rIDPreviousAllocationPool",
122 : "rIDNextRID",
123 : "rIDUsedPool",
124 : NULL
125 : };
126 :
127 : struct ridalloc_ridset_values {
128 : uint64_t alloc_pool;
129 : uint64_t prev_pool;
130 : uint32_t next_rid;
131 : uint32_t used_pool;
132 : };
133 :
134 34806 : static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
135 : {
136 34806 : v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
137 34806 : v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
138 34806 : v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
139 34806 : v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
140 34806 : }
141 :
142 34879 : static int ridalloc_set_ridset_values(struct ldb_module *module,
143 : struct ldb_message *msg,
144 : const struct ridalloc_ridset_values *o,
145 : const struct ridalloc_ridset_values *n)
146 : {
147 172 : const uint32_t *o32, *n32;
148 172 : const uint64_t *o64, *n64;
149 172 : int ret;
150 :
151 : #define SETUP_PTRS(field, optr, nptr, max) do { \
152 : optr = &o->field; \
153 : nptr = &n->field; \
154 : if (o->field == max) { \
155 : optr = NULL; \
156 : } \
157 : if (n->field == max) { \
158 : nptr = NULL; \
159 : } \
160 : if (o->field == n->field) { \
161 : optr = NULL; \
162 : nptr = NULL; \
163 : } \
164 : } while(0)
165 :
166 34879 : SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
167 34879 : ret = dsdb_msg_constrainted_update_uint64(module, msg,
168 : "rIDAllocationPool",
169 : o64, n64);
170 34879 : if (ret != LDB_SUCCESS) {
171 0 : return ret;
172 : }
173 :
174 34879 : SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
175 34879 : ret = dsdb_msg_constrainted_update_uint64(module, msg,
176 : "rIDPreviousAllocationPool",
177 : o64, n64);
178 34879 : if (ret != LDB_SUCCESS) {
179 0 : return ret;
180 : }
181 :
182 34879 : SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
183 34879 : ret = dsdb_msg_constrainted_update_uint32(module, msg,
184 : "rIDNextRID",
185 : o32, n32);
186 34879 : if (ret != LDB_SUCCESS) {
187 0 : return ret;
188 : }
189 :
190 34879 : SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
191 34879 : ret = dsdb_msg_constrainted_update_uint32(module, msg,
192 : "rIDUsedPool",
193 : o32, n32);
194 34879 : if (ret != LDB_SUCCESS) {
195 0 : return ret;
196 : }
197 : #undef SETUP_PTRS
198 :
199 34707 : return LDB_SUCCESS;
200 : }
201 :
202 : /*
203 : allocate a new range of RIDs in the RID Manager object
204 : */
205 145 : static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool,
206 : struct ldb_request *parent)
207 : {
208 0 : int ret;
209 145 : TALLOC_CTX *tmp_ctx = talloc_new(module);
210 145 : const char *attrs[] = { "rIDAvailablePool", NULL };
211 0 : uint64_t rid_pool, new_rid_pool, dc_pool;
212 0 : uint32_t rid_pool_lo, rid_pool_hi;
213 0 : struct ldb_result *res;
214 145 : struct ldb_context *ldb = ldb_module_get_ctx(module);
215 145 : const unsigned alloc_size = 500;
216 :
217 145 : ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
218 : attrs, DSDB_FLAG_NEXT_MODULE, parent);
219 145 : if (ret != LDB_SUCCESS) {
220 0 : ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
221 : ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
222 0 : talloc_free(tmp_ctx);
223 0 : return ret;
224 : }
225 :
226 145 : rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
227 145 : rid_pool_lo = rid_pool & 0xFFFFFFFF;
228 145 : rid_pool_hi = rid_pool >> 32;
229 145 : if (rid_pool_lo >= rid_pool_hi) {
230 0 : ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
231 : rid_pool_lo, rid_pool_hi);
232 0 : talloc_free(tmp_ctx);
233 0 : return ret;
234 : }
235 :
236 : /* lower part of new pool is the low part of the rIDAvailablePool */
237 145 : dc_pool = rid_pool_lo;
238 :
239 : /* allocate 500 RIDs to this DC */
240 145 : rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
241 :
242 : /* work out upper part of new pool */
243 145 : dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
244 :
245 : /* and new rIDAvailablePool value */
246 145 : new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
247 :
248 145 : ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
249 : &rid_pool, &new_rid_pool, parent);
250 145 : if (ret != LDB_SUCCESS) {
251 0 : ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
252 : ldb_errstring(ldb));
253 0 : talloc_free(tmp_ctx);
254 0 : return ret;
255 : }
256 :
257 145 : (*new_pool) = dc_pool;
258 145 : talloc_free(tmp_ctx);
259 145 : return LDB_SUCCESS;
260 : }
261 :
262 : /*
263 : create a RID Set object for the specified DC
264 : */
265 74 : static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
266 : struct ldb_dn *rid_manager_dn,
267 : struct ldb_dn *ntds_dn, struct ldb_dn **dn,
268 : struct ldb_request *parent)
269 : {
270 74 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
271 0 : struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
272 0 : int ret;
273 0 : struct ldb_message *msg;
274 74 : struct ldb_context *ldb = ldb_module_get_ctx(module);
275 0 : static const struct ridalloc_ridset_values o = {
276 : .alloc_pool = UINT64_MAX,
277 : .prev_pool = UINT64_MAX,
278 : .next_rid = UINT32_MAX,
279 : .used_pool = UINT32_MAX,
280 : };
281 74 : struct ridalloc_ridset_values n = {
282 : .alloc_pool = 0,
283 : .prev_pool = 0,
284 : .next_rid = 0,
285 : .used_pool = 0,
286 : };
287 74 : const char *no_attrs[] = { NULL };
288 0 : struct ldb_result *res;
289 :
290 : /*
291 : steps:
292 :
293 : find the machine object for the DC
294 : construct the RID Set DN
295 : load rIDAvailablePool to find next available set
296 : modify RID Manager object to update rIDAvailablePool
297 : add the RID Set object
298 : link to the RID Set object in machine object
299 : */
300 :
301 74 : server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
302 74 : if (!server_dn) {
303 0 : talloc_free(tmp_ctx);
304 0 : return ldb_module_oom(module);
305 : }
306 :
307 74 : ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
308 74 : if (ret != LDB_SUCCESS) {
309 0 : ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
310 : ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
311 0 : talloc_free(tmp_ctx);
312 0 : return ret;
313 : }
314 :
315 74 : rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
316 74 : if (rid_set_dn == NULL) {
317 0 : talloc_free(tmp_ctx);
318 0 : return ldb_module_oom(module);
319 : }
320 :
321 74 : if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
322 0 : talloc_free(tmp_ctx);
323 0 : return ldb_module_oom(module);
324 : }
325 :
326 : /* grab a pool from the RID Manager object */
327 74 : ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent);
328 74 : if (ret != LDB_SUCCESS) {
329 0 : talloc_free(tmp_ctx);
330 0 : return ret;
331 : }
332 :
333 : /* create the RID Set object */
334 74 : msg = ldb_msg_new(tmp_ctx);
335 74 : msg->dn = rid_set_dn;
336 :
337 74 : ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
338 74 : if (ret != LDB_SUCCESS) {
339 0 : talloc_free(tmp_ctx);
340 0 : return ret;
341 : }
342 :
343 74 : ret = ridalloc_set_ridset_values(module, msg, &o, &n);
344 74 : if (ret != LDB_SUCCESS) {
345 0 : talloc_free(tmp_ctx);
346 0 : return ret;
347 : }
348 :
349 : /* we need this to go all the way to the top of the module
350 : * stack, as we need all the extra attributes added (including
351 : * complex ones like ntsecuritydescriptor). We must do this
352 : * as system, otherwise a user might end up owning the RID
353 : * set, and that would be bad... */
354 74 : ret = dsdb_module_add(module, msg,
355 : DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM
356 : | DSDB_MODIFY_RELAX, parent);
357 74 : if (ret != LDB_SUCCESS) {
358 2 : ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
359 : ldb_dn_get_linearized(msg->dn),
360 : ldb_errstring(ldb));
361 2 : talloc_free(tmp_ctx);
362 2 : return ret;
363 : }
364 :
365 : /* add the rIDSetReferences link */
366 72 : msg = ldb_msg_new(tmp_ctx);
367 72 : msg->dn = machine_dn;
368 :
369 : /* we need the extended DN of the RID Set object for
370 : * rIDSetReferences */
371 72 : ret = dsdb_module_search_dn(module, msg, &res, rid_set_dn, no_attrs,
372 : DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, parent);
373 72 : if (ret != LDB_SUCCESS) {
374 0 : ldb_asprintf_errstring(ldb, "Failed to find extended DN of RID Set %s - %s",
375 : ldb_dn_get_linearized(msg->dn),
376 : ldb_errstring(ldb));
377 0 : talloc_free(tmp_ctx);
378 0 : return ret;
379 : }
380 72 : rid_set_dn = res->msgs[0]->dn;
381 :
382 :
383 72 : ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_extended_linearized(msg, rid_set_dn, 1));
384 72 : if (ret != LDB_SUCCESS) {
385 0 : talloc_free(tmp_ctx);
386 0 : return ret;
387 : }
388 72 : msg->elements[0].flags = LDB_FLAG_MOD_ADD;
389 :
390 72 : ret = dsdb_module_modify(module, msg,
391 : DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM,
392 : parent);
393 72 : if (ret != LDB_SUCCESS) {
394 0 : ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
395 : ldb_dn_get_linearized(msg->dn),
396 : ldb_errstring(ldb));
397 0 : talloc_free(tmp_ctx);
398 0 : return ret;
399 : }
400 :
401 72 : (*dn) = talloc_steal(mem_ctx, rid_set_dn);
402 :
403 72 : talloc_free(tmp_ctx);
404 72 : return LDB_SUCCESS;
405 : }
406 :
407 :
408 : /*
409 : create a RID Set object for this DC
410 : */
411 42 : int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
412 : struct ldb_dn **dn, struct ldb_request *parent)
413 : {
414 42 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
415 0 : struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
416 0 : int ret;
417 42 : struct ldb_context *ldb = ldb_module_get_ctx(module);
418 0 : struct GUID fsmo_role_guid;
419 0 : const struct GUID *our_ntds_guid;
420 0 : NTSTATUS status;
421 :
422 : /* work out who is the RID Manager */
423 42 : ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
424 42 : if (ret != LDB_SUCCESS) {
425 0 : ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
426 : ldb_errstring(ldb));
427 0 : talloc_free(tmp_ctx);
428 0 : return ret;
429 : }
430 :
431 : /* find the DN of the RID Manager */
432 42 : ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
433 42 : if (ret != LDB_SUCCESS) {
434 0 : ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
435 : ldb_errstring(ldb));
436 0 : talloc_free(tmp_ctx);
437 0 : return ret;
438 : }
439 :
440 42 : status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID");
441 42 : if (!NT_STATUS_IS_OK(status)) {
442 0 : talloc_free(tmp_ctx);
443 0 : return ldb_operr(ldb_module_get_ctx(module));
444 : }
445 :
446 : /* clear the cache so we don't get an old ntds_guid */
447 42 : if (ldb_set_opaque(ldb, "cache.ntds_guid", NULL) != LDB_SUCCESS) {
448 0 : talloc_free(tmp_ctx);
449 0 : return ldb_operr(ldb_module_get_ctx(module));
450 : }
451 :
452 42 : our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module));
453 42 : if (!our_ntds_guid) {
454 0 : talloc_free(tmp_ctx);
455 0 : return ldb_operr(ldb_module_get_ctx(module));
456 : }
457 :
458 42 : if (!GUID_equal(&fsmo_role_guid, our_ntds_guid)) {
459 0 : ret = ridalloc_poke_rid_manager(module);
460 0 : if (ret != LDB_SUCCESS) {
461 0 : ldb_asprintf_errstring(ldb,
462 : "Request for remote creation of "
463 : "RID Set for this DC failed: %s",
464 : ldb_errstring(ldb));
465 : } else {
466 0 : ldb_asprintf_errstring(ldb,
467 : "Remote RID Set creation needed");
468 : }
469 0 : talloc_free(tmp_ctx);
470 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
471 : }
472 :
473 42 : ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
474 42 : talloc_free(tmp_ctx);
475 42 : return ret;
476 : }
477 :
478 : /*
479 : get a new RID pool for ourselves
480 : also returns the first rid for the new pool
481 : */
482 :
483 312 : int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
484 : {
485 312 : TALLOC_CTX *tmp_ctx = talloc_new(module);
486 0 : struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
487 0 : int ret;
488 312 : struct ldb_context *ldb = ldb_module_get_ctx(module);
489 0 : bool is_us;
490 :
491 : /* work out who is the RID Manager */
492 312 : ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
493 312 : if (ret != LDB_SUCCESS) {
494 0 : ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
495 : ldb_errstring(ldb));
496 0 : talloc_free(tmp_ctx);
497 0 : return ret;
498 : }
499 :
500 : /* find the DN of the RID Manager */
501 312 : ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
502 312 : if (ret != LDB_SUCCESS) {
503 0 : ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
504 : ldb_errstring(ldb));
505 0 : talloc_free(tmp_ctx);
506 0 : return ret;
507 : }
508 :
509 312 : ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us);
510 312 : if (ret != LDB_SUCCESS) {
511 0 : ldb_asprintf_errstring(ldb, "Failed to confirm if our ntdsDsa is %s: %s",
512 : ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb));
513 0 : talloc_free(tmp_ctx);
514 0 : return ret;
515 : }
516 :
517 312 : if (!is_us) {
518 246 : ret = ridalloc_poke_rid_manager(module);
519 246 : if (ret != LDB_SUCCESS) {
520 240 : ldb_asprintf_errstring(ldb, "Request for remote refresh of RID Set allocation failed: %s",
521 : ldb_errstring(ldb));
522 : } else {
523 6 : ldb_asprintf_errstring(ldb, "Remote RID Set refresh needed");
524 : }
525 246 : talloc_free(tmp_ctx);
526 246 : return LDB_ERR_UNWILLING_TO_PERFORM;
527 : }
528 :
529 : /* grab a pool from the RID Manager object */
530 66 : ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
531 66 : if (ret != LDB_SUCCESS) {
532 0 : talloc_free(tmp_ctx);
533 0 : return ret;
534 : }
535 :
536 66 : talloc_free(tmp_ctx);
537 66 : return ret;
538 : }
539 :
540 :
541 : /* allocate a RID using our RID Set
542 : If we run out of RIDs then allocate a new pool
543 : either locally or by contacting the RID Manager
544 : */
545 34802 : int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
546 : {
547 172 : struct ldb_context *ldb;
548 172 : int ret;
549 172 : struct ldb_dn *rid_set_dn;
550 172 : struct ldb_result *res;
551 172 : struct ldb_message *msg;
552 172 : struct ridalloc_ridset_values oridset;
553 172 : struct ridalloc_ridset_values nridset;
554 172 : uint32_t prev_pool_lo, prev_pool_hi;
555 34802 : TALLOC_CTX *tmp_ctx = talloc_new(module);
556 :
557 34802 : (*rid) = 0;
558 34802 : ldb = ldb_module_get_ctx(module);
559 :
560 34802 : ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
561 34802 : if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
562 3 : ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
563 : }
564 34802 : if (ret != LDB_SUCCESS) {
565 1 : ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
566 : ldb_errstring(ldb));
567 1 : talloc_free(tmp_ctx);
568 1 : return ret;
569 : }
570 :
571 34801 : ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
572 : ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
573 34801 : if (ret != LDB_SUCCESS) {
574 0 : ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
575 : ldb_dn_get_linearized(rid_set_dn));
576 0 : talloc_free(tmp_ctx);
577 0 : return ret;
578 : }
579 :
580 34801 : ridalloc_get_ridset_values(res->msgs[0], &oridset);
581 34801 : if (oridset.alloc_pool == UINT64_MAX) {
582 1 : ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
583 : ldb_dn_get_linearized(rid_set_dn));
584 1 : talloc_free(tmp_ctx);
585 1 : return LDB_ERR_OPERATIONS_ERROR;
586 : }
587 :
588 34800 : nridset = oridset;
589 :
590 : /*
591 : * If we never used a pool, setup out first pool
592 : */
593 34800 : if (nridset.prev_pool == UINT64_MAX ||
594 34795 : nridset.next_rid == UINT32_MAX) {
595 6 : nridset.prev_pool = nridset.alloc_pool;
596 6 : nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
597 : } else {
598 34794 : nridset.next_rid += 1;
599 : }
600 :
601 : /*
602 : * Now check if our current pool is still usable
603 : */
604 34800 : prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
605 34800 : prev_pool_hi = nridset.prev_pool >> 32;
606 34800 : if (nridset.next_rid > prev_pool_hi) {
607 : /*
608 : * We need a new pool, check if we already have a new one
609 : * Otherwise we need to get a new pool.
610 : */
611 62 : if (nridset.alloc_pool == nridset.prev_pool) {
612 : /*
613 : * if we are the RID Manager,
614 : * we can get a new pool locally.
615 : * Otherwise we fail the operation and
616 : * ask async for a new pool.
617 : */
618 1 : ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
619 1 : if (ret != LDB_SUCCESS) {
620 0 : ldb_asprintf_errstring(ldb, "NO RID values available: %s",
621 : ldb_errstring(ldb));
622 0 : talloc_free(tmp_ctx);
623 0 : return ret;
624 : }
625 : }
626 :
627 : /*
628 : * increment the rIDUsedPool attribute
629 : *
630 : * Note: w2k8r2 doesn't update this attribute,
631 : * at least if it's itself the rid master.
632 : */
633 62 : nridset.used_pool += 1;
634 :
635 : /* now use the new pool */
636 62 : nridset.prev_pool = nridset.alloc_pool;
637 62 : prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
638 62 : prev_pool_hi = nridset.prev_pool >> 32;
639 62 : nridset.next_rid = prev_pool_lo;
640 : }
641 :
642 34800 : if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
643 0 : ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
644 0 : (unsigned)nridset.next_rid,
645 : (unsigned)prev_pool_lo,
646 : (unsigned)prev_pool_hi);
647 0 : talloc_free(tmp_ctx);
648 0 : return LDB_ERR_OPERATIONS_ERROR;
649 : }
650 :
651 : /*
652 : * if we are half-exhausted then try to get a new pool.
653 : */
654 34800 : if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2 &&
655 15339 : nridset.alloc_pool == nridset.prev_pool) {
656 : /*
657 : * if we are the RID Manager,
658 : * we can get a new pool locally.
659 : * Otherwise we fail the operation and
660 : * ask async for a new pool.
661 : */
662 311 : ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
663 311 : if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
664 246 : ldb_reset_err_string(ldb);
665 246 : ret = LDB_SUCCESS;
666 : }
667 311 : if (ret != LDB_SUCCESS) {
668 0 : talloc_free(tmp_ctx);
669 0 : return ret;
670 : }
671 : }
672 :
673 : /*
674 : * update the values
675 : */
676 34800 : msg = ldb_msg_new(tmp_ctx);
677 34800 : if (msg == NULL) {
678 0 : return ldb_module_oom(module);
679 : }
680 34800 : msg->dn = rid_set_dn;
681 :
682 34800 : ret = ridalloc_set_ridset_values(module, msg,
683 : &oridset, &nridset);
684 34800 : if (ret != LDB_SUCCESS) {
685 0 : talloc_free(tmp_ctx);
686 0 : return ret;
687 : }
688 :
689 34800 : ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, parent);
690 34800 : if (ret != LDB_SUCCESS) {
691 0 : talloc_free(tmp_ctx);
692 0 : return ret;
693 : }
694 :
695 34800 : talloc_free(tmp_ctx);
696 34800 : *rid = nridset.next_rid;
697 34800 : return LDB_SUCCESS;
698 : }
699 :
700 :
701 : /*
702 : called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
703 :
704 : This is for the DRS server to allocate a RID Pool for another server.
705 :
706 : Called by another server over DRS (which calls this extended
707 : operation), it runs on the RID Manager only.
708 : */
709 37 : int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
710 : struct ldb_request *parent)
711 : {
712 0 : struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
713 0 : struct ldb_dn *rid_manager_dn;
714 37 : TALLOC_CTX *tmp_ctx = talloc_new(module);
715 0 : int ret;
716 37 : struct ldb_context *ldb = ldb_module_get_ctx(module);
717 0 : struct ldb_result *res;
718 0 : struct ldb_message *msg;
719 0 : struct ridalloc_ridset_values oridset, nridset;
720 :
721 37 : ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
722 37 : if (ret != LDB_SUCCESS) {
723 0 : ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
724 0 : GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
725 0 : talloc_free(tmp_ctx);
726 0 : return ret;
727 : }
728 :
729 37 : server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
730 37 : if (!server_dn) {
731 0 : talloc_free(tmp_ctx);
732 0 : return ldb_module_oom(module);
733 : }
734 :
735 37 : ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
736 37 : if (ret != LDB_SUCCESS) {
737 0 : ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
738 : ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
739 0 : talloc_free(tmp_ctx);
740 0 : return ret;
741 : }
742 :
743 37 : ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
744 37 : if (ret != LDB_SUCCESS) {
745 0 : ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
746 : ldb_errstring(ldb));
747 0 : talloc_free(tmp_ctx);
748 0 : return ret;
749 : }
750 :
751 37 : ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
752 37 : if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
753 32 : ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
754 32 : talloc_free(tmp_ctx);
755 32 : return ret;
756 : }
757 :
758 5 : if (ret != LDB_SUCCESS) {
759 0 : ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
760 : ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
761 0 : talloc_free(tmp_ctx);
762 0 : return ret;
763 : }
764 :
765 5 : ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
766 : ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
767 5 : if (ret != LDB_SUCCESS) {
768 0 : ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
769 : ldb_dn_get_linearized(rid_set_dn));
770 0 : talloc_free(tmp_ctx);
771 0 : return ret;
772 : }
773 :
774 5 : ridalloc_get_ridset_values(res->msgs[0], &oridset);
775 5 : if (oridset.alloc_pool == UINT64_MAX) {
776 0 : ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
777 : ldb_dn_get_linearized(rid_set_dn));
778 0 : talloc_free(tmp_ctx);
779 0 : return LDB_ERR_OPERATIONS_ERROR;
780 : }
781 :
782 5 : nridset = oridset;
783 :
784 5 : if (exop->fsmo_info != 0) {
785 :
786 2 : if (nridset.alloc_pool != exop->fsmo_info) {
787 : /* it has already been updated */
788 0 : DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
789 : (unsigned long long)exop->fsmo_info,
790 : (unsigned long long)nridset.alloc_pool));
791 0 : talloc_free(tmp_ctx);
792 0 : return LDB_SUCCESS;
793 : }
794 : }
795 :
796 : /* grab a pool from the RID Manager object */
797 5 : ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
798 5 : if (ret != LDB_SUCCESS) {
799 0 : talloc_free(tmp_ctx);
800 0 : return ret;
801 : }
802 :
803 : /*
804 : * update the values
805 : */
806 5 : msg = ldb_msg_new(tmp_ctx);
807 5 : if (msg == NULL) {
808 0 : return ldb_module_oom(module);
809 : }
810 5 : msg->dn = rid_set_dn;
811 :
812 5 : ret = ridalloc_set_ridset_values(module, msg,
813 : &oridset, &nridset);
814 5 : if (ret != LDB_SUCCESS) {
815 0 : talloc_free(tmp_ctx);
816 0 : return ret;
817 : }
818 :
819 5 : ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, parent);
820 5 : if (ret != LDB_SUCCESS) {
821 0 : ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
822 : ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
823 0 : talloc_free(tmp_ctx);
824 0 : return ret;
825 : }
826 :
827 5 : talloc_free(tmp_ctx);
828 5 : return LDB_SUCCESS;
829 : }
|