91d48ba47bc8c203b8aeced6e5a217be28b9f372
[kamenim/samba.git] / source4 / dsdb / samdb / ldb_modules / ridalloc.c
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 "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
38 /*
39   Note: the RID allocation attributes in AD are very badly named. Here
40   is what we think they really do:
41
42   in RID Set object:
43     - rIDPreviousAllocationPool: the pool which a DC is currently
44       pulling RIDs from. Managed by client DC
45
46     - rIDAllocationPool: the pool that the DC will switch to next,
47       when rIDPreviousAllocationPool is exhausted. Managed by RID Manager.
48
49     - rIDNextRID: the last RID allocated by this DC. Managed by client DC
50
51   in RID Manager object:
52     - rIDAvailablePool: the pool where the RID Manager gets new rID
53       pools from when it gets a EXOP_RID_ALLOC getncchanges call (or
54       locally when the DC is the RID Manager)
55  */
56
57
58 /*
59   make a IRPC call to the drepl task to ask it to get the RID
60   Manager to give us another RID pool.
61
62   This function just sends the message to the drepl task then
63   returns immediately. It should be called well before we
64   completely run out of RIDs
65  */
66 static void ridalloc_poke_rid_manager(struct ldb_module *module)
67 {
68         struct messaging_context *msg;
69         struct server_id *server;
70         struct ldb_context *ldb = ldb_module_get_ctx(module);
71         struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm");
72         TALLOC_CTX *tmp_ctx = talloc_new(module);
73
74         msg = messaging_client_init(tmp_ctx, lp_messaging_path(tmp_ctx, lp_ctx),
75                                     ldb_get_event_context(ldb));
76         if (!msg) {
77                 DEBUG(3,(__location__ ": Failed to create messaging context\n"));
78                 talloc_free(tmp_ctx);
79                 return;
80         }
81
82         server = irpc_servers_byname(msg, msg, "dreplsrv");
83         if (!server) {
84                 /* this means the drepl service is not running */
85                 talloc_free(tmp_ctx);
86                 return;
87         }
88
89         messaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL);
90
91         /* we don't care if the message got through */
92         talloc_free(tmp_ctx);
93 }
94
95
96 /*
97   allocate a new range of RIDs in the RID Manager object
98  */
99 static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool)
100 {
101         int ret;
102         TALLOC_CTX *tmp_ctx = talloc_new(module);
103         const char *attrs[] = { "rIDAvailablePool", NULL };
104         uint64_t rid_pool, new_rid_pool, dc_pool;
105         uint32_t rid_pool_lo, rid_pool_hi;
106         struct ldb_result *res;
107         struct ldb_context *ldb = ldb_module_get_ctx(module);
108         const unsigned alloc_size = 500;
109
110         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
111                                     attrs, DSDB_FLAG_NEXT_MODULE);
112         if (ret != LDB_SUCCESS) {
113                 ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
114                                        ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
115                 talloc_free(tmp_ctx);
116                 return ret;
117         }
118
119         rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
120         rid_pool_lo = rid_pool & 0xFFFFFFFF;
121         rid_pool_hi = rid_pool >> 32;
122         if (rid_pool_lo >= rid_pool_hi) {
123                 ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
124                                        rid_pool_lo, rid_pool_hi);
125                 talloc_free(tmp_ctx);
126                 return ret;
127         }
128
129         /* lower part of new pool is the low part of the rIDAvailablePool */
130         dc_pool = rid_pool_lo;
131
132         /* allocate 500 RIDs to this DC */
133         rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
134
135         /* work out upper part of new pool */
136         dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
137
138         /* and new rIDAvailablePool value */
139         new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
140
141         ret = dsdb_module_constrainted_update_integer(module, rid_manager_dn, "rIDAvailablePool",
142                                                       rid_pool, new_rid_pool);
143         if (ret != LDB_SUCCESS) {
144                 ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
145                                        ldb_errstring(ldb));
146                 talloc_free(tmp_ctx);
147                 return ret;
148         }
149
150         (*new_pool) = dc_pool;
151         talloc_free(tmp_ctx);
152         return LDB_SUCCESS;
153 }
154
155 /*
156   create a RID Set object for the specified DC
157  */
158 static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
159                                         struct ldb_dn *rid_manager_dn,
160                                         struct ldb_dn *ntds_dn, struct ldb_dn **dn)
161 {
162         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
163         struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
164         int ret;
165         uint64_t dc_pool;
166         struct ldb_message *msg;
167         struct ldb_context *ldb = ldb_module_get_ctx(module);
168
169         /*
170           steps:
171
172           find the machine object for the DC
173           construct the RID Set DN
174           load rIDAvailablePool to find next available set
175           modify RID Manager object to update rIDAvailablePool
176           add the RID Set object
177           link to the RID Set object in machine object
178          */
179
180         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
181         if (!server_dn) {
182                 talloc_free(tmp_ctx);
183                 return ldb_module_oom(module);
184         }
185
186         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
187         if (ret != LDB_SUCCESS) {
188                 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
189                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
190                 talloc_free(tmp_ctx);
191                 return ret;
192         }
193
194         rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
195         if (rid_set_dn == NULL) {
196                 talloc_free(tmp_ctx);
197                 return ldb_module_oom(module);
198         }
199
200         if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
201                 talloc_free(tmp_ctx);
202                 return ldb_module_oom(module);
203         }
204
205         /* grab a pool from the RID Manager object */
206         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &dc_pool);
207         if (ret != LDB_SUCCESS) {
208                 talloc_free(tmp_ctx);
209                 return ret;
210         }
211
212         /* create the RID Set object */
213         msg = ldb_msg_new(tmp_ctx);
214         msg->dn = rid_set_dn;
215
216         ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
217         if (ret != LDB_SUCCESS) {
218                 talloc_free(tmp_ctx);
219                 return ret;
220         }
221         ret = ldb_msg_add_fmt(msg, "rIDAllocationPool", "%llu", (unsigned long long)dc_pool);
222         if (ret != LDB_SUCCESS) {
223                 talloc_free(tmp_ctx);
224                 return ret;
225         }
226
227         /* w2k8-r2 sets these to zero when first created */
228         ret = ldb_msg_add_fmt(msg, "rIDPreviousAllocationPool", "0");
229         if (ret != LDB_SUCCESS) {
230                 talloc_free(tmp_ctx);
231                 return ret;
232         }
233         ret = ldb_msg_add_fmt(msg, "rIDUsedPool", "0");
234         if (ret != LDB_SUCCESS) {
235                 talloc_free(tmp_ctx);
236                 return ret;
237         }
238         ret = ldb_msg_add_fmt(msg, "rIDNextRID", "0");
239         if (ret != LDB_SUCCESS) {
240                 talloc_free(tmp_ctx);
241                 return ret;
242         }
243
244         /* we need this to go all the way to the top of the module
245          * stack, as we need all the extra attributes added (including
246          * complex ones like ntsecuritydescriptor) */
247         ret = dsdb_module_add(module, msg, DSDB_FLAG_TOP_MODULE | DSDB_MODIFY_RELAX);
248         if (ret != LDB_SUCCESS) {
249                 ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
250                                        ldb_dn_get_linearized(msg->dn),
251                                        ldb_errstring(ldb));
252                 talloc_free(tmp_ctx);
253                 return ret;
254         }
255
256         /* add the rIDSetReferences link */
257         msg = ldb_msg_new(tmp_ctx);
258         msg->dn = machine_dn;
259
260         ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_linearized(rid_set_dn));
261         if (ret != LDB_SUCCESS) {
262                 talloc_free(tmp_ctx);
263                 return ret;
264         }
265         msg->elements[0].flags = LDB_FLAG_MOD_ADD;
266
267         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
268         if (ret != LDB_SUCCESS) {
269                 ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
270                                        ldb_dn_get_linearized(msg->dn),
271                                        ldb_errstring(ldb));
272                 talloc_free(tmp_ctx);
273                 return ret;
274         }
275
276         (*dn) = talloc_steal(mem_ctx, rid_set_dn);
277
278         talloc_free(tmp_ctx);
279         return LDB_SUCCESS;
280 }
281
282
283 /*
284   create a RID Set object for this DC
285  */
286 static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
287                                        struct ldb_dn **dn)
288 {
289         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
290         struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
291         int ret;
292         struct ldb_context *ldb = ldb_module_get_ctx(module);
293
294         /* work out who is the RID Manager */
295         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
296         if (ret != LDB_SUCCESS) {
297                 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
298                                        ldb_errstring(ldb));
299                 talloc_free(tmp_ctx);
300                 return ret;
301         }
302
303         /* find the DN of the RID Manager */
304         ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
305         if (ret != LDB_SUCCESS) {
306                 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
307                                        ldb_errstring(ldb));
308                 talloc_free(tmp_ctx);
309                 return ret;
310         }
311
312         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
313                 ridalloc_poke_rid_manager(module);
314                 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
315                 talloc_free(tmp_ctx);
316                 return LDB_ERR_UNWILLING_TO_PERFORM;
317         }
318
319         ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn);
320         talloc_free(tmp_ctx);
321         return ret;
322 }
323
324 /*
325   refresh a RID Set object for the specified DC
326   also returns the first RID for the new pool
327  */
328 static int ridalloc_refresh_rid_set_ntds(struct ldb_module *module,
329                                          struct ldb_dn *rid_manager_dn,
330                                          struct ldb_dn *ntds_dn, uint64_t *new_pool)
331 {
332         TALLOC_CTX *tmp_ctx = talloc_new(module);
333         struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
334         struct ldb_context *ldb = ldb_module_get_ctx(module);
335         int ret;
336
337         /* grab a pool from the RID Manager object */
338         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool);
339         if (ret != LDB_SUCCESS) {
340                 talloc_free(tmp_ctx);
341                 return ret;
342         }
343
344         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
345         if (!server_dn) {
346                 talloc_free(tmp_ctx);
347                 return ldb_module_oom(module);
348         }
349
350         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
351         if (ret != LDB_SUCCESS) {
352                 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
353                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
354                 talloc_free(tmp_ctx);
355                 return ret;
356         }
357
358         ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn);
359         if (ret != LDB_SUCCESS) {
360                 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
361                                        ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
362                 talloc_free(tmp_ctx);
363                 return ret;
364         }
365
366         ret = dsdb_module_set_integer(module, rid_set_dn, "rIDAllocationPool", *new_pool);
367         if (ret != LDB_SUCCESS) {
368                 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
369                                        ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
370                 talloc_free(tmp_ctx);
371                 return ret;
372         }
373
374         talloc_free(tmp_ctx);
375         return LDB_SUCCESS;
376 }
377
378
379 /*
380   get a new RID pool for ourselves
381   also returns the first rid for the new pool
382  */
383 static int ridalloc_refresh_own_pool(struct ldb_module *module, uint64_t *new_pool)
384 {
385         TALLOC_CTX *tmp_ctx = talloc_new(module);
386         struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
387         int ret;
388         struct ldb_context *ldb = ldb_module_get_ctx(module);
389
390         /* work out who is the RID Manager */
391         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
392         if (ret != LDB_SUCCESS) {
393                 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
394                                        ldb_errstring(ldb));
395                 talloc_free(tmp_ctx);
396                 return ret;
397         }
398
399         /* find the DN of the RID Manager */
400         ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
401         if (ret != LDB_SUCCESS) {
402                 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
403                                        ldb_errstring(ldb));
404                 talloc_free(tmp_ctx);
405                 return ret;
406         }
407
408         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
409                 ridalloc_poke_rid_manager(module);
410                 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
411                 talloc_free(tmp_ctx);
412                 return LDB_ERR_UNWILLING_TO_PERFORM;
413         }
414
415         ret = ridalloc_refresh_rid_set_ntds(module, rid_manager_dn, fsmo_role_dn, new_pool);
416         talloc_free(tmp_ctx);
417         return ret;
418 }
419
420
421 /* allocate a RID using our RID Set
422    If we run out of RIDs then allocate a new pool
423    either locally or by contacting the RID Manager
424 */
425 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
426 {
427         struct ldb_context *ldb;
428         static const char * const attrs[] = { "rIDAllocationPool", "rIDPreviousAllocationPool",
429                                               "rIDNextRID" , "rIDUsedPool", NULL };
430         int ret;
431         struct ldb_dn *rid_set_dn;
432         struct ldb_result *res;
433         uint64_t alloc_pool, prev_alloc_pool;
434         uint32_t prev_alloc_pool_lo, prev_alloc_pool_hi;
435         uint32_t rid_used_pool;
436         int prev_rid;
437         TALLOC_CTX *tmp_ctx = talloc_new(module);
438
439         (*rid) = 0;
440         ldb = ldb_module_get_ctx(module);
441
442         ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
443         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
444                 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn);
445         }
446         if (ret != LDB_SUCCESS) {
447                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
448                                        ldb_errstring(ldb));
449                 talloc_free(tmp_ctx);
450                 return ret;
451         }
452
453         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
454                                     attrs, DSDB_FLAG_NEXT_MODULE);
455         if (ret != LDB_SUCCESS) {
456                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
457                                        ldb_dn_get_linearized(rid_set_dn));
458                 talloc_free(tmp_ctx);
459                 return ret;
460         }
461
462         prev_alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDPreviousAllocationPool", 0);
463         alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
464         prev_rid = ldb_msg_find_attr_as_int(res->msgs[0], "rIDNextRID", 0);
465         rid_used_pool = ldb_msg_find_attr_as_int(res->msgs[0], "rIDUsedPool", 0);
466         if (alloc_pool == 0) {
467                 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
468                                        ldb_dn_get_linearized(rid_set_dn));
469                 talloc_free(tmp_ctx);
470                 return LDB_ERR_OPERATIONS_ERROR;
471         }
472
473         prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
474         prev_alloc_pool_hi = prev_alloc_pool >> 32;
475         if (prev_rid >= prev_alloc_pool_hi) {
476                 if (prev_alloc_pool == 0) {
477                         ret = dsdb_module_set_integer(module, rid_set_dn, "rIDPreviousAllocationPool", alloc_pool);
478                 } else {
479                         ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool",
480                                                                       prev_alloc_pool, alloc_pool);
481                 }
482                 if (ret != LDB_SUCCESS) {
483                         ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s",
484                                                ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
485                         talloc_free(tmp_ctx);
486                         return ret;
487                 }
488                 prev_alloc_pool = alloc_pool;
489                 prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
490                 prev_alloc_pool_hi = prev_alloc_pool >> 32;
491
492                 /*
493                  * update the rIDUsedPool attribute
494                  *
495                  * Note: w2k8r2 doesn't update this attribute,
496                  *       at least if it's itself the rid master.
497                  */
498                 ret = dsdb_module_set_integer(module, rid_set_dn, "rIDUsedPool", rid_used_pool+1);
499                 if (ret != LDB_SUCCESS) {
500                         ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDUsedPool on %s - %s",
501                                                ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
502                         talloc_free(tmp_ctx);
503                         return ret;
504                 }
505
506                 (*rid) = prev_alloc_pool_lo;
507         }
508
509         /* see if we are still out of RIDs, and if so then ask
510            the RID Manager to give us more */
511         if (prev_rid >= prev_alloc_pool_hi) {
512                 uint64_t new_pool;
513                 ret = ridalloc_refresh_own_pool(module, &new_pool);
514                 if (ret != LDB_SUCCESS) {
515                         talloc_free(tmp_ctx);
516                         return ret;
517                 }
518                 ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool",
519                                                               prev_alloc_pool, new_pool);
520                 if (ret != LDB_SUCCESS) {
521                         ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s",
522                                                ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
523                         talloc_free(tmp_ctx);
524                         return ret;
525                 }
526                 prev_alloc_pool = new_pool;
527                 prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
528                 prev_alloc_pool_hi = prev_alloc_pool >> 32;
529                 (*rid) = prev_alloc_pool_lo;
530         } else {
531                 /* despite the name, rIDNextRID is the value of the last user
532                  * added by this DC, not the next available RID */
533                 if (*rid == 0) {
534                         (*rid) = prev_rid + 1;
535                 }
536         }
537
538         if (*rid < prev_alloc_pool_lo || *rid > prev_alloc_pool_hi) {
539                 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
540                                        (unsigned)*rid, (unsigned)prev_alloc_pool_lo,
541                                        (unsigned)prev_alloc_pool_hi);
542                 talloc_free(tmp_ctx);
543                 return LDB_ERR_OPERATIONS_ERROR;
544         }
545
546         /* now modify the RID Set to use up this RID using a
547          * constrained delete/add if possible */
548         if (prev_rid == 0) {
549                 ret = dsdb_module_set_integer(module, rid_set_dn, "rIDNextRID", *rid);
550         } else {
551                 ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDNextRID", prev_rid, *rid);
552         }
553
554         /* if we are half-exhausted then ask the repl task to start
555          * getting another one */
556         if (*rid > (prev_alloc_pool_hi + prev_alloc_pool_lo)/2) {
557                 ridalloc_poke_rid_manager(module);
558         }
559
560         talloc_free(tmp_ctx);
561
562         return ret;
563 }
564
565
566 /*
567   called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
568  */
569 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop)
570 {
571         struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
572         struct ldb_dn *rid_manager_dn;
573         TALLOC_CTX *tmp_ctx = talloc_new(module);
574         int ret;
575         struct ldb_context *ldb = ldb_module_get_ctx(module);
576         uint64_t new_pool;
577
578         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn);
579         if (ret != LDB_SUCCESS) {
580                 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
581                                        GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
582                 talloc_free(tmp_ctx);
583                 return ret;
584         }
585
586         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
587         if (!server_dn) {
588                 talloc_free(tmp_ctx);
589                 return ldb_module_oom(module);
590         }
591
592         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
593         if (ret != LDB_SUCCESS) {
594                 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
595                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
596                 talloc_free(tmp_ctx);
597                 return ret;
598         }
599
600
601         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
602         if (ret != LDB_SUCCESS) {
603                 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
604                                        ldb_errstring(ldb));
605                 talloc_free(tmp_ctx);
606                 return ret;
607         }
608
609         ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn);
610         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
611                 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn);
612                 talloc_free(tmp_ctx);
613                 return ret;
614         }
615
616         if (ret != LDB_SUCCESS) {
617                 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
618                                        ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
619                 talloc_free(tmp_ctx);
620                 return ret;
621         }
622
623         if (exop->fsmo_info != 0) {
624                 const char *attrs[] = { "rIDAllocationPool", NULL };
625                 struct ldb_result *res;
626                 uint64_t alloc_pool;
627
628                 ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
629                                             attrs, DSDB_FLAG_NEXT_MODULE);
630                 if (ret != LDB_SUCCESS) {
631                         ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
632                                                ldb_dn_get_linearized(rid_set_dn));
633                         talloc_free(tmp_ctx);
634                         return ret;
635                 }
636
637                 alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
638                 if (alloc_pool != exop->fsmo_info) {
639                         /* it has already been updated */
640                         DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
641                                  (unsigned long long)exop->fsmo_info,
642                                  (unsigned long long)alloc_pool));
643                         talloc_free(tmp_ctx);
644                         return LDB_SUCCESS;
645                 }
646         }
647
648         ret = ridalloc_refresh_rid_set_ntds(module, rid_manager_dn, ntds_dn, &new_pool);
649         talloc_free(tmp_ctx);
650         return ret;
651 }