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