s4-loadparm: 2nd half of lp_ to lpcfg_ conversion
[garming/samba-autobuild/.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, lpcfg_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 static const char * const ridalloc_ridset_attrs[] = {
98         "rIDAllocationPool",
99         "rIDPreviousAllocationPool",
100         "rIDNextRID",
101         "rIDUsedPool",
102         NULL
103 };
104
105 struct ridalloc_ridset_values {
106         uint64_t alloc_pool;
107         uint64_t prev_pool;
108         uint32_t next_rid;
109         uint32_t used_pool;
110 };
111
112 static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
113 {
114         v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
115         v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
116         v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
117         v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
118 }
119
120 static int ridalloc_set_ridset_values(struct ldb_module *module,
121                                       struct ldb_message *msg,
122                                       const struct ridalloc_ridset_values *o,
123                                       const struct ridalloc_ridset_values *n)
124 {
125         const uint32_t *o32, *n32;
126         const uint64_t *o64, *n64;
127         int ret;
128
129 #define SETUP_PTRS(field, optr, nptr, max) do { \
130         optr = &o->field; \
131         nptr = &n->field; \
132         if (o->field == max) { \
133                 optr = NULL; \
134         } \
135         if (n->field == max) { \
136                 nptr = NULL; \
137         } \
138         if (o->field == n->field) { \
139                 optr = NULL; \
140                 nptr = NULL; \
141         } \
142 } while(0)
143
144         SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
145         ret = dsdb_msg_constrainted_update_uint64(module, msg,
146                                                   "rIDAllocationPool",
147                                                   o64, n64);
148         if (ret != LDB_SUCCESS) {
149                 return ret;
150         }
151
152         SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
153         ret = dsdb_msg_constrainted_update_uint64(module, msg,
154                                                   "rIDPreviousAllocationPool",
155                                                   o64, n64);
156         if (ret != LDB_SUCCESS) {
157                 return ret;
158         }
159
160         SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
161         ret = dsdb_msg_constrainted_update_uint32(module, msg,
162                                                   "rIDNextRID",
163                                                   o32, n32);
164         if (ret != LDB_SUCCESS) {
165                 return ret;
166         }
167
168         SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
169         ret = dsdb_msg_constrainted_update_uint32(module, msg,
170                                                   "rIDUsedPool",
171                                                   o32, n32);
172         if (ret != LDB_SUCCESS) {
173                 return ret;
174         }
175 #undef SETUP_PTRS
176
177         return LDB_SUCCESS;
178 }
179
180 /*
181   allocate a new range of RIDs in the RID Manager object
182  */
183 static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool)
184 {
185         int ret;
186         TALLOC_CTX *tmp_ctx = talloc_new(module);
187         const char *attrs[] = { "rIDAvailablePool", NULL };
188         uint64_t rid_pool, new_rid_pool, dc_pool;
189         uint32_t rid_pool_lo, rid_pool_hi;
190         struct ldb_result *res;
191         struct ldb_context *ldb = ldb_module_get_ctx(module);
192         const unsigned alloc_size = 500;
193
194         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
195                                     attrs, DSDB_FLAG_NEXT_MODULE);
196         if (ret != LDB_SUCCESS) {
197                 ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
198                                        ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
199                 talloc_free(tmp_ctx);
200                 return ret;
201         }
202
203         rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
204         rid_pool_lo = rid_pool & 0xFFFFFFFF;
205         rid_pool_hi = rid_pool >> 32;
206         if (rid_pool_lo >= rid_pool_hi) {
207                 ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
208                                        rid_pool_lo, rid_pool_hi);
209                 talloc_free(tmp_ctx);
210                 return ret;
211         }
212
213         /* lower part of new pool is the low part of the rIDAvailablePool */
214         dc_pool = rid_pool_lo;
215
216         /* allocate 500 RIDs to this DC */
217         rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
218
219         /* work out upper part of new pool */
220         dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
221
222         /* and new rIDAvailablePool value */
223         new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
224
225         ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
226                                                      &rid_pool, &new_rid_pool);
227         if (ret != LDB_SUCCESS) {
228                 ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
229                                        ldb_errstring(ldb));
230                 talloc_free(tmp_ctx);
231                 return ret;
232         }
233
234         (*new_pool) = dc_pool;
235         talloc_free(tmp_ctx);
236         return LDB_SUCCESS;
237 }
238
239 /*
240   create a RID Set object for the specified DC
241  */
242 static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
243                                         struct ldb_dn *rid_manager_dn,
244                                         struct ldb_dn *ntds_dn, struct ldb_dn **dn)
245 {
246         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
247         struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
248         int ret;
249         struct ldb_message *msg;
250         struct ldb_context *ldb = ldb_module_get_ctx(module);
251         static const struct ridalloc_ridset_values o = {
252                 .alloc_pool     = UINT64_MAX,
253                 .prev_pool      = UINT64_MAX,
254                 .next_rid       = UINT32_MAX,
255                 .used_pool      = UINT32_MAX,
256         };
257         struct ridalloc_ridset_values n = {
258                 .alloc_pool     = 0,
259                 .prev_pool      = 0,
260                 .next_rid       = 0,
261                 .used_pool      = 0,
262         };
263
264         /*
265           steps:
266
267           find the machine object for the DC
268           construct the RID Set DN
269           load rIDAvailablePool to find next available set
270           modify RID Manager object to update rIDAvailablePool
271           add the RID Set object
272           link to the RID Set object in machine object
273          */
274
275         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
276         if (!server_dn) {
277                 talloc_free(tmp_ctx);
278                 return ldb_module_oom(module);
279         }
280
281         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
282         if (ret != LDB_SUCCESS) {
283                 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
284                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
285                 talloc_free(tmp_ctx);
286                 return ret;
287         }
288
289         rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
290         if (rid_set_dn == NULL) {
291                 talloc_free(tmp_ctx);
292                 return ldb_module_oom(module);
293         }
294
295         if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
296                 talloc_free(tmp_ctx);
297                 return ldb_module_oom(module);
298         }
299
300         /* grab a pool from the RID Manager object */
301         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool);
302         if (ret != LDB_SUCCESS) {
303                 talloc_free(tmp_ctx);
304                 return ret;
305         }
306
307         /* create the RID Set object */
308         msg = ldb_msg_new(tmp_ctx);
309         msg->dn = rid_set_dn;
310
311         ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
312         if (ret != LDB_SUCCESS) {
313                 talloc_free(tmp_ctx);
314                 return ret;
315         }
316
317         ret = ridalloc_set_ridset_values(module, msg, &o, &n);
318         if (ret != LDB_SUCCESS) {
319                 talloc_free(tmp_ctx);
320                 return ret;
321         }
322
323         /* we need this to go all the way to the top of the module
324          * stack, as we need all the extra attributes added (including
325          * complex ones like ntsecuritydescriptor) */
326         ret = dsdb_module_add(module, msg, DSDB_FLAG_TOP_MODULE | DSDB_MODIFY_RELAX);
327         if (ret != LDB_SUCCESS) {
328                 ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
329                                        ldb_dn_get_linearized(msg->dn),
330                                        ldb_errstring(ldb));
331                 talloc_free(tmp_ctx);
332                 return ret;
333         }
334
335         /* add the rIDSetReferences link */
336         msg = ldb_msg_new(tmp_ctx);
337         msg->dn = machine_dn;
338
339         ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_linearized(rid_set_dn));
340         if (ret != LDB_SUCCESS) {
341                 talloc_free(tmp_ctx);
342                 return ret;
343         }
344         msg->elements[0].flags = LDB_FLAG_MOD_ADD;
345
346         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
347         if (ret != LDB_SUCCESS) {
348                 ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
349                                        ldb_dn_get_linearized(msg->dn),
350                                        ldb_errstring(ldb));
351                 talloc_free(tmp_ctx);
352                 return ret;
353         }
354
355         (*dn) = talloc_steal(mem_ctx, rid_set_dn);
356
357         talloc_free(tmp_ctx);
358         return LDB_SUCCESS;
359 }
360
361
362 /*
363   create a RID Set object for this DC
364  */
365 static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
366                                        struct ldb_dn **dn)
367 {
368         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
369         struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
370         int ret;
371         struct ldb_context *ldb = ldb_module_get_ctx(module);
372
373         /* work out who is the RID Manager */
374         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
375         if (ret != LDB_SUCCESS) {
376                 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
377                                        ldb_errstring(ldb));
378                 talloc_free(tmp_ctx);
379                 return ret;
380         }
381
382         /* find the DN of the RID Manager */
383         ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
384         if (ret != LDB_SUCCESS) {
385                 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
386                                        ldb_errstring(ldb));
387                 talloc_free(tmp_ctx);
388                 return ret;
389         }
390
391         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
392                 ridalloc_poke_rid_manager(module);
393                 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
394                 talloc_free(tmp_ctx);
395                 return LDB_ERR_UNWILLING_TO_PERFORM;
396         }
397
398         ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn);
399         talloc_free(tmp_ctx);
400         return ret;
401 }
402
403 /*
404   get a new RID pool for ourselves
405   also returns the first rid for the new pool
406  */
407 static int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool)
408 {
409         TALLOC_CTX *tmp_ctx = talloc_new(module);
410         struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
411         int ret;
412         struct ldb_context *ldb = ldb_module_get_ctx(module);
413
414         /* work out who is the RID Manager */
415         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
416         if (ret != LDB_SUCCESS) {
417                 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
418                                        ldb_errstring(ldb));
419                 talloc_free(tmp_ctx);
420                 return ret;
421         }
422
423         /* find the DN of the RID Manager */
424         ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
425         if (ret != LDB_SUCCESS) {
426                 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
427                                        ldb_errstring(ldb));
428                 talloc_free(tmp_ctx);
429                 return ret;
430         }
431
432         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
433                 ridalloc_poke_rid_manager(module);
434                 ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
435                 talloc_free(tmp_ctx);
436                 return LDB_ERR_UNWILLING_TO_PERFORM;
437         }
438
439         /* grab a pool from the RID Manager object */
440         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool);
441         if (ret != LDB_SUCCESS) {
442                 talloc_free(tmp_ctx);
443                 return ret;
444         }
445
446         talloc_free(tmp_ctx);
447         return ret;
448 }
449
450
451 /* allocate a RID using our RID Set
452    If we run out of RIDs then allocate a new pool
453    either locally or by contacting the RID Manager
454 */
455 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
456 {
457         struct ldb_context *ldb;
458         int ret;
459         struct ldb_dn *rid_set_dn;
460         struct ldb_result *res;
461         struct ldb_message *msg;
462         struct ridalloc_ridset_values oridset;
463         struct ridalloc_ridset_values nridset;
464         uint32_t prev_pool_lo, prev_pool_hi;
465         TALLOC_CTX *tmp_ctx = talloc_new(module);
466
467         (*rid) = 0;
468         ldb = ldb_module_get_ctx(module);
469
470         ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
471         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
472                 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn);
473         }
474         if (ret != LDB_SUCCESS) {
475                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
476                                        ldb_errstring(ldb));
477                 talloc_free(tmp_ctx);
478                 return ret;
479         }
480
481         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
482                                     ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE);
483         if (ret != LDB_SUCCESS) {
484                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
485                                        ldb_dn_get_linearized(rid_set_dn));
486                 talloc_free(tmp_ctx);
487                 return ret;
488         }
489
490         ridalloc_get_ridset_values(res->msgs[0], &oridset);
491         if (oridset.alloc_pool == UINT64_MAX) {
492                 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
493                                        ldb_dn_get_linearized(rid_set_dn));
494                 talloc_free(tmp_ctx);
495                 return LDB_ERR_OPERATIONS_ERROR;
496         }
497
498         nridset = oridset;
499
500         /*
501          * If we never used a pool, setup out first pool
502          */
503         if (nridset.prev_pool == UINT64_MAX ||
504             nridset.next_rid == UINT32_MAX) {
505                 nridset.prev_pool = nridset.alloc_pool;
506                 nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
507         }
508
509         /*
510          * Now check if our current pool is still usable
511          */
512         nridset.next_rid += 1;
513         prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
514         prev_pool_hi = nridset.prev_pool >> 32;
515         if (nridset.next_rid > prev_pool_hi) {
516                 /*
517                  * We need a new pool, check if we already have a new one
518                  * Otherwise we need to get a new pool.
519                  */
520                 if (nridset.alloc_pool == nridset.prev_pool) {
521                         /*
522                          * if we are the RID Manager,
523                          * we can get a new pool localy.
524                          * Otherwise we fail the operation and
525                          * ask async for a new pool.
526                          */
527                         ret = ridalloc_new_own_pool(module, &nridset.alloc_pool);
528                         if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
529                                 ridalloc_poke_rid_manager(module);
530                                 talloc_free(tmp_ctx);
531                                 return ret;
532                         }
533                         if (ret != LDB_SUCCESS) {
534                                 talloc_free(tmp_ctx);
535                                 return ret;
536                         }
537                 }
538
539                 /*
540                  * increment the rIDUsedPool attribute
541                  *
542                  * Note: w2k8r2 doesn't update this attribute,
543                  *       at least if it's itself the rid master.
544                  */
545                 nridset.used_pool += 1;
546
547                 /* now use the new pool */
548                 nridset.prev_pool = nridset.alloc_pool;
549                 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
550                 prev_pool_hi = nridset.prev_pool >> 32;
551                 nridset.next_rid = prev_pool_lo;
552         }
553
554         if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
555                 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
556                                        (unsigned)nridset.next_rid,
557                                        (unsigned)prev_pool_lo,
558                                        (unsigned)prev_pool_hi);
559                 talloc_free(tmp_ctx);
560                 return LDB_ERR_OPERATIONS_ERROR;
561         }
562
563         /*
564          * if we are half-exhausted then try to get a new pool.
565          */
566         if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2) {
567                 /*
568                  * if we are the RID Manager,
569                  * we can get a new pool localy.
570                  * Otherwise we fail the operation and
571                  * ask async for a new pool.
572                  */
573                 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool);
574                 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
575                         ridalloc_poke_rid_manager(module);
576                         ret = LDB_SUCCESS;
577                 }
578                 if (ret != LDB_SUCCESS) {
579                         talloc_free(tmp_ctx);
580                         return ret;
581                 }
582         }
583
584         /*
585          * update the values
586          */
587         msg = ldb_msg_new(tmp_ctx);
588         if (msg == NULL) {
589                 return ldb_module_oom(module);
590         }
591         msg->dn = rid_set_dn;
592
593         ret = ridalloc_set_ridset_values(module, msg,
594                                          &oridset, &nridset);
595         if (ret != LDB_SUCCESS) {
596                 talloc_free(tmp_ctx);
597                 return ret;
598         }
599
600         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
601         if (ret != LDB_SUCCESS) {
602                 talloc_free(tmp_ctx);
603                 return ret;
604         }
605
606         talloc_free(tmp_ctx);
607         *rid = nridset.next_rid;
608         return LDB_SUCCESS;
609 }
610
611
612 /*
613   called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
614  */
615 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop)
616 {
617         struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
618         struct ldb_dn *rid_manager_dn;
619         TALLOC_CTX *tmp_ctx = talloc_new(module);
620         int ret;
621         struct ldb_context *ldb = ldb_module_get_ctx(module);
622         struct ldb_result *res;
623         struct ldb_message *msg;
624         struct ridalloc_ridset_values oridset, nridset;
625
626         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn);
627         if (ret != LDB_SUCCESS) {
628                 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
629                                        GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
630                 talloc_free(tmp_ctx);
631                 return ret;
632         }
633
634         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
635         if (!server_dn) {
636                 talloc_free(tmp_ctx);
637                 return ldb_module_oom(module);
638         }
639
640         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn);
641         if (ret != LDB_SUCCESS) {
642                 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
643                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
644                 talloc_free(tmp_ctx);
645                 return ret;
646         }
647
648         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn);
649         if (ret != LDB_SUCCESS) {
650                 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
651                                        ldb_errstring(ldb));
652                 talloc_free(tmp_ctx);
653                 return ret;
654         }
655
656         ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn);
657         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
658                 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn);
659                 talloc_free(tmp_ctx);
660                 return ret;
661         }
662
663         if (ret != LDB_SUCCESS) {
664                 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
665                                        ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
666                 talloc_free(tmp_ctx);
667                 return ret;
668         }
669
670         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
671                                     ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE);
672         if (ret != LDB_SUCCESS) {
673                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
674                                        ldb_dn_get_linearized(rid_set_dn));
675                 talloc_free(tmp_ctx);
676                 return ret;
677         }
678
679         ridalloc_get_ridset_values(res->msgs[0], &oridset);
680         if (oridset.alloc_pool == UINT64_MAX) {
681                 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
682                                        ldb_dn_get_linearized(rid_set_dn));
683                 talloc_free(tmp_ctx);
684                 return LDB_ERR_OPERATIONS_ERROR;
685         }
686
687         nridset = oridset;
688
689         if (exop->fsmo_info != 0) {
690
691                 if (nridset.alloc_pool != exop->fsmo_info) {
692                         /* it has already been updated */
693                         DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
694                                  (unsigned long long)exop->fsmo_info,
695                                  (unsigned long long)nridset.alloc_pool));
696                         talloc_free(tmp_ctx);
697                         return LDB_SUCCESS;
698                 }
699         }
700
701         /* grab a pool from the RID Manager object */
702         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool);
703         if (ret != LDB_SUCCESS) {
704                 talloc_free(tmp_ctx);
705                 return ret;
706         }
707
708         /*
709          * update the values
710          */
711         msg = ldb_msg_new(tmp_ctx);
712         if (msg == NULL) {
713                 return ldb_module_oom(module);
714         }
715         msg->dn = rid_set_dn;
716
717         ret = ridalloc_set_ridset_values(module, msg,
718                                          &oridset, &nridset);
719         if (ret != LDB_SUCCESS) {
720                 talloc_free(tmp_ctx);
721                 return ret;
722         }
723
724         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
725         if (ret != LDB_SUCCESS) {
726                 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
727                                        ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
728                 talloc_free(tmp_ctx);
729                 return ret;
730         }
731
732         talloc_free(tmp_ctx);
733         return LDB_SUCCESS;
734 }