/src/samba/source4/dsdb/samdb/ldb_modules/ridalloc.c
Line | Count | Source |
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 | | static int ridalloc_poke_rid_manager(struct ldb_module *module) |
69 | 0 | { |
70 | 0 | struct imessaging_context *msg; |
71 | 0 | unsigned num_servers; |
72 | 0 | struct server_id *servers; |
73 | 0 | struct ldb_context *ldb = ldb_module_get_ctx(module); |
74 | 0 | struct loadparm_context *lp_ctx = |
75 | 0 | (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"); |
76 | 0 | TALLOC_CTX *tmp_ctx = talloc_new(module); |
77 | 0 | NTSTATUS status; |
78 | |
|
79 | 0 | msg = imessaging_client_init(tmp_ctx, lp_ctx, |
80 | 0 | ldb_get_event_context(ldb)); |
81 | 0 | if (!msg) { |
82 | 0 | ldb_asprintf_errstring(ldb_module_get_ctx(module), |
83 | 0 | "Failed to send MSG_DREPL_ALLOCATE_RID, " |
84 | 0 | "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 | 0 | } |
89 | | |
90 | 0 | status = irpc_servers_byname(msg, msg, "dreplsrv", |
91 | 0 | &num_servers, &servers); |
92 | 0 | if (!NT_STATUS_IS_OK(status)) { |
93 | 0 | ldb_asprintf_errstring(ldb_module_get_ctx(module), |
94 | 0 | "Failed to send MSG_DREPL_ALLOCATE_RID, " |
95 | 0 | "unable to locate dreplsrv"); |
96 | | /* this means the drepl service is not running */ |
97 | 0 | talloc_free(tmp_ctx); |
98 | 0 | return LDB_ERR_UNWILLING_TO_PERFORM; |
99 | 0 | } |
100 | | |
101 | 0 | 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 | 0 | if (NT_STATUS_IS_ERR(status)) { |
105 | 0 | struct server_id_buf idbuf; |
106 | 0 | ldb_asprintf_errstring(ldb_module_get_ctx(module), |
107 | 0 | "Failed to send MSG_DREPL_ALLOCATE_RID to dreplsrv at %s: %s", |
108 | 0 | server_id_str_buf(*servers, &idbuf), |
109 | 0 | nt_errstr(status)); |
110 | 0 | talloc_free(tmp_ctx); |
111 | 0 | return LDB_ERR_UNWILLING_TO_PERFORM; |
112 | 0 | } |
113 | | |
114 | 0 | talloc_free(tmp_ctx); |
115 | 0 | return LDB_SUCCESS; |
116 | 0 | } |
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 | | static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v) |
135 | 0 | { |
136 | 0 | v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX); |
137 | 0 | v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX); |
138 | 0 | v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX); |
139 | 0 | v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX); |
140 | 0 | } |
141 | | |
142 | | 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 | 0 | { |
147 | 0 | const uint32_t *o32, *n32; |
148 | 0 | const uint64_t *o64, *n64; |
149 | 0 | int ret; |
150 | |
|
151 | 0 | #define SETUP_PTRS(field, optr, nptr, max) do { \ |
152 | 0 | optr = &o->field; \ |
153 | 0 | nptr = &n->field; \ |
154 | 0 | if (o->field == max) { \ |
155 | 0 | optr = NULL; \ |
156 | 0 | } \ |
157 | 0 | if (n->field == max) { \ |
158 | 0 | nptr = NULL; \ |
159 | 0 | } \ |
160 | 0 | if (o->field == n->field) { \ |
161 | 0 | optr = NULL; \ |
162 | 0 | nptr = NULL; \ |
163 | 0 | } \ |
164 | 0 | } while(0) |
165 | |
|
166 | 0 | SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX); |
167 | 0 | ret = dsdb_msg_constrainted_update_uint64(module, msg, |
168 | 0 | "rIDAllocationPool", |
169 | 0 | o64, n64); |
170 | 0 | if (ret != LDB_SUCCESS) { |
171 | 0 | return ret; |
172 | 0 | } |
173 | | |
174 | 0 | SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX); |
175 | 0 | ret = dsdb_msg_constrainted_update_uint64(module, msg, |
176 | 0 | "rIDPreviousAllocationPool", |
177 | 0 | o64, n64); |
178 | 0 | if (ret != LDB_SUCCESS) { |
179 | 0 | return ret; |
180 | 0 | } |
181 | | |
182 | 0 | SETUP_PTRS(next_rid, o32, n32, UINT32_MAX); |
183 | 0 | ret = dsdb_msg_constrainted_update_uint32(module, msg, |
184 | 0 | "rIDNextRID", |
185 | 0 | o32, n32); |
186 | 0 | if (ret != LDB_SUCCESS) { |
187 | 0 | return ret; |
188 | 0 | } |
189 | | |
190 | 0 | SETUP_PTRS(used_pool, o32, n32, UINT32_MAX); |
191 | 0 | ret = dsdb_msg_constrainted_update_uint32(module, msg, |
192 | 0 | "rIDUsedPool", |
193 | 0 | o32, n32); |
194 | 0 | if (ret != LDB_SUCCESS) { |
195 | 0 | return ret; |
196 | 0 | } |
197 | 0 | #undef SETUP_PTRS |
198 | | |
199 | 0 | return LDB_SUCCESS; |
200 | 0 | } |
201 | | |
202 | | /* |
203 | | allocate a new range of RIDs in the RID Manager object |
204 | | */ |
205 | | 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 | 0 | { |
208 | 0 | int ret; |
209 | 0 | TALLOC_CTX *tmp_ctx = talloc_new(module); |
210 | 0 | 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 | 0 | struct ldb_context *ldb = ldb_module_get_ctx(module); |
215 | 0 | const unsigned alloc_size = 500; |
216 | |
|
217 | 0 | ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn, |
218 | 0 | attrs, DSDB_FLAG_NEXT_MODULE, parent); |
219 | 0 | if (ret != LDB_SUCCESS) { |
220 | 0 | ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s", |
221 | 0 | ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb)); |
222 | 0 | talloc_free(tmp_ctx); |
223 | 0 | return ret; |
224 | 0 | } |
225 | | |
226 | 0 | rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0); |
227 | 0 | rid_pool_lo = rid_pool & 0xFFFFFFFF; |
228 | 0 | rid_pool_hi = rid_pool >> 32; |
229 | 0 | if (rid_pool_lo >= rid_pool_hi) { |
230 | 0 | ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u", |
231 | 0 | rid_pool_lo, rid_pool_hi); |
232 | 0 | talloc_free(tmp_ctx); |
233 | 0 | return ret; |
234 | 0 | } |
235 | | |
236 | | /* lower part of new pool is the low part of the rIDAvailablePool */ |
237 | 0 | dc_pool = rid_pool_lo; |
238 | | |
239 | | /* allocate 500 RIDs to this DC */ |
240 | 0 | rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size); |
241 | | |
242 | | /* work out upper part of new pool */ |
243 | 0 | dc_pool |= (((uint64_t)rid_pool_lo-1)<<32); |
244 | | |
245 | | /* and new rIDAvailablePool value */ |
246 | 0 | new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32); |
247 | |
|
248 | 0 | ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool", |
249 | 0 | &rid_pool, &new_rid_pool, parent); |
250 | 0 | if (ret != LDB_SUCCESS) { |
251 | 0 | ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s", |
252 | 0 | ldb_errstring(ldb)); |
253 | 0 | talloc_free(tmp_ctx); |
254 | 0 | return ret; |
255 | 0 | } |
256 | | |
257 | 0 | (*new_pool) = dc_pool; |
258 | 0 | talloc_free(tmp_ctx); |
259 | 0 | return LDB_SUCCESS; |
260 | 0 | } |
261 | | |
262 | | /* |
263 | | create a RID Set object for the specified DC |
264 | | */ |
265 | | 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 | 0 | { |
270 | 0 | 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 | 0 | struct ldb_context *ldb = ldb_module_get_ctx(module); |
275 | 0 | static const struct ridalloc_ridset_values o = { |
276 | 0 | .alloc_pool = UINT64_MAX, |
277 | 0 | .prev_pool = UINT64_MAX, |
278 | 0 | .next_rid = UINT32_MAX, |
279 | 0 | .used_pool = UINT32_MAX, |
280 | 0 | }; |
281 | 0 | struct ridalloc_ridset_values n = { |
282 | 0 | .alloc_pool = 0, |
283 | 0 | .prev_pool = 0, |
284 | 0 | .next_rid = 0, |
285 | 0 | .used_pool = 0, |
286 | 0 | }; |
287 | 0 | 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 | 0 | server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn); |
302 | 0 | if (!server_dn) { |
303 | 0 | talloc_free(tmp_ctx); |
304 | 0 | return ldb_module_oom(module); |
305 | 0 | } |
306 | | |
307 | 0 | ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent); |
308 | 0 | if (ret != LDB_SUCCESS) { |
309 | 0 | ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s", |
310 | 0 | ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)); |
311 | 0 | talloc_free(tmp_ctx); |
312 | 0 | return ret; |
313 | 0 | } |
314 | | |
315 | 0 | rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn); |
316 | 0 | if (rid_set_dn == NULL) { |
317 | 0 | talloc_free(tmp_ctx); |
318 | 0 | return ldb_module_oom(module); |
319 | 0 | } |
320 | | |
321 | 0 | 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 | 0 | } |
325 | | |
326 | | /* grab a pool from the RID Manager object */ |
327 | 0 | ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent); |
328 | 0 | if (ret != LDB_SUCCESS) { |
329 | 0 | talloc_free(tmp_ctx); |
330 | 0 | return ret; |
331 | 0 | } |
332 | | |
333 | | /* create the RID Set object */ |
334 | 0 | msg = ldb_msg_new(tmp_ctx); |
335 | 0 | msg->dn = rid_set_dn; |
336 | |
|
337 | 0 | ret = ldb_msg_add_string(msg, "objectClass", "rIDSet"); |
338 | 0 | if (ret != LDB_SUCCESS) { |
339 | 0 | talloc_free(tmp_ctx); |
340 | 0 | return ret; |
341 | 0 | } |
342 | | |
343 | 0 | ret = ridalloc_set_ridset_values(module, msg, &o, &n); |
344 | 0 | if (ret != LDB_SUCCESS) { |
345 | 0 | talloc_free(tmp_ctx); |
346 | 0 | return ret; |
347 | 0 | } |
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 | 0 | ret = dsdb_module_add(module, msg, |
355 | 0 | DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM |
356 | 0 | | DSDB_MODIFY_RELAX, parent); |
357 | 0 | if (ret != LDB_SUCCESS) { |
358 | 0 | ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s", |
359 | 0 | ldb_dn_get_linearized(msg->dn), |
360 | 0 | ldb_errstring(ldb)); |
361 | 0 | talloc_free(tmp_ctx); |
362 | 0 | return ret; |
363 | 0 | } |
364 | | |
365 | | /* add the rIDSetReferences link */ |
366 | 0 | msg = ldb_msg_new(tmp_ctx); |
367 | 0 | msg->dn = machine_dn; |
368 | | |
369 | | /* we need the extended DN of the RID Set object for |
370 | | * rIDSetReferences */ |
371 | 0 | ret = dsdb_module_search_dn(module, msg, &res, rid_set_dn, no_attrs, |
372 | 0 | DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, parent); |
373 | 0 | if (ret != LDB_SUCCESS) { |
374 | 0 | ldb_asprintf_errstring(ldb, "Failed to find extended DN of RID Set %s - %s", |
375 | 0 | ldb_dn_get_linearized(msg->dn), |
376 | 0 | ldb_errstring(ldb)); |
377 | 0 | talloc_free(tmp_ctx); |
378 | 0 | return ret; |
379 | 0 | } |
380 | 0 | rid_set_dn = res->msgs[0]->dn; |
381 | | |
382 | |
|
383 | 0 | ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_extended_linearized(msg, rid_set_dn, 1)); |
384 | 0 | if (ret != LDB_SUCCESS) { |
385 | 0 | talloc_free(tmp_ctx); |
386 | 0 | return ret; |
387 | 0 | } |
388 | 0 | msg->elements[0].flags = LDB_FLAG_MOD_ADD; |
389 | |
|
390 | 0 | ret = dsdb_module_modify(module, msg, |
391 | 0 | DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, |
392 | 0 | parent); |
393 | 0 | if (ret != LDB_SUCCESS) { |
394 | 0 | ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s", |
395 | 0 | ldb_dn_get_linearized(msg->dn), |
396 | 0 | ldb_errstring(ldb)); |
397 | 0 | talloc_free(tmp_ctx); |
398 | 0 | return ret; |
399 | 0 | } |
400 | | |
401 | 0 | (*dn) = talloc_steal(mem_ctx, rid_set_dn); |
402 | |
|
403 | 0 | talloc_free(tmp_ctx); |
404 | 0 | return LDB_SUCCESS; |
405 | 0 | } |
406 | | |
407 | | |
408 | | /* |
409 | | create a RID Set object for this DC |
410 | | */ |
411 | | int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx, |
412 | | struct ldb_dn **dn, struct ldb_request *parent) |
413 | 0 | { |
414 | 0 | TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); |
415 | 0 | struct ldb_dn *rid_manager_dn, *fsmo_role_dn; |
416 | 0 | int ret; |
417 | 0 | 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 | 0 | ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent); |
424 | 0 | if (ret != LDB_SUCCESS) { |
425 | 0 | ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s", |
426 | 0 | ldb_errstring(ldb)); |
427 | 0 | talloc_free(tmp_ctx); |
428 | 0 | return ret; |
429 | 0 | } |
430 | | |
431 | | /* find the DN of the RID Manager */ |
432 | 0 | ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent); |
433 | 0 | if (ret != LDB_SUCCESS) { |
434 | 0 | ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s", |
435 | 0 | ldb_errstring(ldb)); |
436 | 0 | talloc_free(tmp_ctx); |
437 | 0 | return ret; |
438 | 0 | } |
439 | | |
440 | 0 | status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID"); |
441 | 0 | if (!NT_STATUS_IS_OK(status)) { |
442 | 0 | talloc_free(tmp_ctx); |
443 | 0 | return ldb_operr(ldb_module_get_ctx(module)); |
444 | 0 | } |
445 | | |
446 | | /* clear the cache so we don't get an old ntds_guid */ |
447 | 0 | 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 | 0 | } |
451 | | |
452 | 0 | our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module)); |
453 | 0 | if (!our_ntds_guid) { |
454 | 0 | talloc_free(tmp_ctx); |
455 | 0 | return ldb_operr(ldb_module_get_ctx(module)); |
456 | 0 | } |
457 | | |
458 | 0 | 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 | 0 | "Request for remote creation of " |
463 | 0 | "RID Set for this DC failed: %s", |
464 | 0 | ldb_errstring(ldb)); |
465 | 0 | } else { |
466 | 0 | ldb_asprintf_errstring(ldb, |
467 | 0 | "Remote RID Set creation needed"); |
468 | 0 | } |
469 | 0 | talloc_free(tmp_ctx); |
470 | 0 | return LDB_ERR_UNWILLING_TO_PERFORM; |
471 | 0 | } |
472 | | |
473 | 0 | ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent); |
474 | 0 | talloc_free(tmp_ctx); |
475 | 0 | return ret; |
476 | 0 | } |
477 | | |
478 | | /* |
479 | | get a new RID pool for ourselves |
480 | | also returns the first rid for the new pool |
481 | | */ |
482 | | |
483 | | int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent) |
484 | 0 | { |
485 | 0 | TALLOC_CTX *tmp_ctx = talloc_new(module); |
486 | 0 | struct ldb_dn *rid_manager_dn, *fsmo_role_dn; |
487 | 0 | int ret; |
488 | 0 | struct ldb_context *ldb = ldb_module_get_ctx(module); |
489 | 0 | bool is_us; |
490 | | |
491 | | /* work out who is the RID Manager */ |
492 | 0 | ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent); |
493 | 0 | if (ret != LDB_SUCCESS) { |
494 | 0 | ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s", |
495 | 0 | ldb_errstring(ldb)); |
496 | 0 | talloc_free(tmp_ctx); |
497 | 0 | return ret; |
498 | 0 | } |
499 | | |
500 | | /* find the DN of the RID Manager */ |
501 | 0 | ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent); |
502 | 0 | if (ret != LDB_SUCCESS) { |
503 | 0 | ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s", |
504 | 0 | ldb_errstring(ldb)); |
505 | 0 | talloc_free(tmp_ctx); |
506 | 0 | return ret; |
507 | 0 | } |
508 | | |
509 | 0 | ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us); |
510 | 0 | if (ret != LDB_SUCCESS) { |
511 | 0 | ldb_asprintf_errstring(ldb, "Failed to confirm if our ntdsDsa is %s: %s", |
512 | 0 | ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb)); |
513 | 0 | talloc_free(tmp_ctx); |
514 | 0 | return ret; |
515 | 0 | } |
516 | | |
517 | 0 | if (!is_us) { |
518 | 0 | ret = ridalloc_poke_rid_manager(module); |
519 | 0 | if (ret != LDB_SUCCESS) { |
520 | 0 | ldb_asprintf_errstring(ldb, "Request for remote refresh of RID Set allocation failed: %s", |
521 | 0 | ldb_errstring(ldb)); |
522 | 0 | } else { |
523 | 0 | ldb_asprintf_errstring(ldb, "Remote RID Set refresh needed"); |
524 | 0 | } |
525 | 0 | talloc_free(tmp_ctx); |
526 | 0 | return LDB_ERR_UNWILLING_TO_PERFORM; |
527 | 0 | } |
528 | | |
529 | | /* grab a pool from the RID Manager object */ |
530 | 0 | ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent); |
531 | 0 | if (ret != LDB_SUCCESS) { |
532 | 0 | talloc_free(tmp_ctx); |
533 | 0 | return ret; |
534 | 0 | } |
535 | | |
536 | 0 | talloc_free(tmp_ctx); |
537 | 0 | return ret; |
538 | 0 | } |
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 | | int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent) |
546 | 0 | { |
547 | 0 | struct ldb_context *ldb; |
548 | 0 | int ret; |
549 | 0 | struct ldb_dn *rid_set_dn; |
550 | 0 | struct ldb_result *res; |
551 | 0 | struct ldb_message *msg; |
552 | 0 | struct ridalloc_ridset_values oridset; |
553 | 0 | struct ridalloc_ridset_values nridset; |
554 | 0 | uint32_t prev_pool_lo, prev_pool_hi; |
555 | 0 | TALLOC_CTX *tmp_ctx = talloc_new(module); |
556 | |
|
557 | 0 | (*rid) = 0; |
558 | 0 | ldb = ldb_module_get_ctx(module); |
559 | |
|
560 | 0 | ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn); |
561 | 0 | if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { |
562 | 0 | ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent); |
563 | 0 | } |
564 | 0 | if (ret != LDB_SUCCESS) { |
565 | 0 | ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s", |
566 | 0 | ldb_errstring(ldb)); |
567 | 0 | talloc_free(tmp_ctx); |
568 | 0 | return ret; |
569 | 0 | } |
570 | | |
571 | 0 | ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, |
572 | 0 | ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent); |
573 | 0 | if (ret != LDB_SUCCESS) { |
574 | 0 | ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s", |
575 | 0 | ldb_dn_get_linearized(rid_set_dn)); |
576 | 0 | talloc_free(tmp_ctx); |
577 | 0 | return ret; |
578 | 0 | } |
579 | | |
580 | 0 | ridalloc_get_ridset_values(res->msgs[0], &oridset); |
581 | 0 | if (oridset.alloc_pool == UINT64_MAX) { |
582 | 0 | ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s", |
583 | 0 | ldb_dn_get_linearized(rid_set_dn)); |
584 | 0 | talloc_free(tmp_ctx); |
585 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
586 | 0 | } |
587 | | |
588 | 0 | nridset = oridset; |
589 | | |
590 | | /* |
591 | | * If we never used a pool, setup out first pool |
592 | | */ |
593 | 0 | if (nridset.prev_pool == UINT64_MAX || |
594 | 0 | nridset.next_rid == UINT32_MAX) { |
595 | 0 | nridset.prev_pool = nridset.alloc_pool; |
596 | 0 | nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF; |
597 | 0 | } else { |
598 | 0 | nridset.next_rid += 1; |
599 | 0 | } |
600 | | |
601 | | /* |
602 | | * Now check if our current pool is still usable |
603 | | */ |
604 | 0 | prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF; |
605 | 0 | prev_pool_hi = nridset.prev_pool >> 32; |
606 | 0 | 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 | 0 | 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 | 0 | ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent); |
619 | 0 | if (ret != LDB_SUCCESS) { |
620 | 0 | ldb_asprintf_errstring(ldb, "NO RID values available: %s", |
621 | 0 | ldb_errstring(ldb)); |
622 | 0 | talloc_free(tmp_ctx); |
623 | 0 | return ret; |
624 | 0 | } |
625 | 0 | } |
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 | 0 | nridset.used_pool += 1; |
634 | | |
635 | | /* now use the new pool */ |
636 | 0 | nridset.prev_pool = nridset.alloc_pool; |
637 | 0 | prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF; |
638 | 0 | prev_pool_hi = nridset.prev_pool >> 32; |
639 | 0 | nridset.next_rid = prev_pool_lo; |
640 | 0 | } |
641 | | |
642 | 0 | 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 | 0 | (unsigned)prev_pool_lo, |
646 | 0 | (unsigned)prev_pool_hi); |
647 | 0 | talloc_free(tmp_ctx); |
648 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
649 | 0 | } |
650 | | |
651 | | /* |
652 | | * if we are half-exhausted then try to get a new pool. |
653 | | */ |
654 | 0 | if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2 && |
655 | 0 | 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 | 0 | ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent); |
663 | 0 | if (ret == LDB_ERR_UNWILLING_TO_PERFORM) { |
664 | 0 | ldb_reset_err_string(ldb); |
665 | 0 | ret = LDB_SUCCESS; |
666 | 0 | } |
667 | 0 | if (ret != LDB_SUCCESS) { |
668 | 0 | talloc_free(tmp_ctx); |
669 | 0 | return ret; |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | | /* |
674 | | * update the values |
675 | | */ |
676 | 0 | msg = ldb_msg_new(tmp_ctx); |
677 | 0 | if (msg == NULL) { |
678 | 0 | return ldb_module_oom(module); |
679 | 0 | } |
680 | 0 | msg->dn = rid_set_dn; |
681 | |
|
682 | 0 | ret = ridalloc_set_ridset_values(module, msg, |
683 | 0 | &oridset, &nridset); |
684 | 0 | if (ret != LDB_SUCCESS) { |
685 | 0 | talloc_free(tmp_ctx); |
686 | 0 | return ret; |
687 | 0 | } |
688 | | |
689 | 0 | ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, parent); |
690 | 0 | if (ret != LDB_SUCCESS) { |
691 | 0 | talloc_free(tmp_ctx); |
692 | 0 | return ret; |
693 | 0 | } |
694 | | |
695 | 0 | talloc_free(tmp_ctx); |
696 | 0 | *rid = nridset.next_rid; |
697 | 0 | return LDB_SUCCESS; |
698 | 0 | } |
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 | | int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop, |
710 | | struct ldb_request *parent) |
711 | 0 | { |
712 | 0 | struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn; |
713 | 0 | struct ldb_dn *rid_manager_dn; |
714 | 0 | TALLOC_CTX *tmp_ctx = talloc_new(module); |
715 | 0 | int ret; |
716 | 0 | 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 | 0 | ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent); |
722 | 0 | 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 | 0 | } |
728 | | |
729 | 0 | server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn); |
730 | 0 | if (!server_dn) { |
731 | 0 | talloc_free(tmp_ctx); |
732 | 0 | return ldb_module_oom(module); |
733 | 0 | } |
734 | | |
735 | 0 | ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent); |
736 | 0 | if (ret != LDB_SUCCESS) { |
737 | 0 | ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s", |
738 | 0 | ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)); |
739 | 0 | talloc_free(tmp_ctx); |
740 | 0 | return ret; |
741 | 0 | } |
742 | | |
743 | 0 | ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent); |
744 | 0 | if (ret != LDB_SUCCESS) { |
745 | 0 | ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s", |
746 | 0 | ldb_errstring(ldb)); |
747 | 0 | talloc_free(tmp_ctx); |
748 | 0 | return ret; |
749 | 0 | } |
750 | | |
751 | 0 | ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent); |
752 | 0 | if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { |
753 | 0 | ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent); |
754 | 0 | talloc_free(tmp_ctx); |
755 | 0 | return ret; |
756 | 0 | } |
757 | | |
758 | 0 | if (ret != LDB_SUCCESS) { |
759 | 0 | ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s", |
760 | 0 | ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb)); |
761 | 0 | talloc_free(tmp_ctx); |
762 | 0 | return ret; |
763 | 0 | } |
764 | | |
765 | 0 | ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, |
766 | 0 | ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent); |
767 | 0 | if (ret != LDB_SUCCESS) { |
768 | 0 | ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s", |
769 | 0 | ldb_dn_get_linearized(rid_set_dn)); |
770 | 0 | talloc_free(tmp_ctx); |
771 | 0 | return ret; |
772 | 0 | } |
773 | | |
774 | 0 | ridalloc_get_ridset_values(res->msgs[0], &oridset); |
775 | 0 | if (oridset.alloc_pool == UINT64_MAX) { |
776 | 0 | ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s", |
777 | 0 | ldb_dn_get_linearized(rid_set_dn)); |
778 | 0 | talloc_free(tmp_ctx); |
779 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
780 | 0 | } |
781 | | |
782 | 0 | nridset = oridset; |
783 | |
|
784 | 0 | if (exop->fsmo_info != 0) { |
785 | |
|
786 | 0 | 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 | 0 | (unsigned long long)exop->fsmo_info, |
790 | 0 | (unsigned long long)nridset.alloc_pool)); |
791 | 0 | talloc_free(tmp_ctx); |
792 | 0 | return LDB_SUCCESS; |
793 | 0 | } |
794 | 0 | } |
795 | | |
796 | | /* grab a pool from the RID Manager object */ |
797 | 0 | ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent); |
798 | 0 | if (ret != LDB_SUCCESS) { |
799 | 0 | talloc_free(tmp_ctx); |
800 | 0 | return ret; |
801 | 0 | } |
802 | | |
803 | | /* |
804 | | * update the values |
805 | | */ |
806 | 0 | msg = ldb_msg_new(tmp_ctx); |
807 | 0 | if (msg == NULL) { |
808 | 0 | return ldb_module_oom(module); |
809 | 0 | } |
810 | 0 | msg->dn = rid_set_dn; |
811 | |
|
812 | 0 | ret = ridalloc_set_ridset_values(module, msg, |
813 | 0 | &oridset, &nridset); |
814 | 0 | if (ret != LDB_SUCCESS) { |
815 | 0 | talloc_free(tmp_ctx); |
816 | 0 | return ret; |
817 | 0 | } |
818 | | |
819 | 0 | ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, parent); |
820 | 0 | if (ret != LDB_SUCCESS) { |
821 | 0 | ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s", |
822 | 0 | ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)); |
823 | 0 | talloc_free(tmp_ctx); |
824 | 0 | return ret; |
825 | 0 | } |
826 | | |
827 | 0 | talloc_free(tmp_ctx); |
828 | 0 | return LDB_SUCCESS; |
829 | 0 | } |