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