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