lib: Add lib/util/server_id.h
[sfrench/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 "lib/util/server_id.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "dsdb/samdb/ldb_modules/util.h"
35 #include "lib/messaging/irpc.h"
36 #include "param/param.h"
37 #include "librpc/gen_ndr/ndr_misc.h"
38 #include "dsdb/samdb/ldb_modules/ridalloc.h"
39
40 /*
41   Note: the RID allocation attributes in AD are very badly named. Here
42   is what we think they really do:
43
44   in RID Set object:
45     - rIDPreviousAllocationPool: the pool which a DC is currently
46       pulling RIDs from. Managed by client DC
47
48     - rIDAllocationPool: the pool that the DC will switch to next,
49       when rIDPreviousAllocationPool is exhausted. Managed by RID Manager.
50
51     - rIDNextRID: the last RID allocated by this DC. Managed by client DC
52
53   in RID Manager object:
54     - rIDAvailablePool: the pool where the RID Manager gets new rID
55       pools from when it gets a EXOP_RID_ALLOC getncchanges call (or
56       locally when the DC is the RID Manager)
57  */
58
59
60 /*
61   make a IRPC call to the drepl task to ask it to get the RID
62   Manager to give us another RID pool.
63
64   This function just sends the message to the drepl task then
65   returns immediately. It should be called well before we
66   completely run out of RIDs
67  */
68 static int ridalloc_poke_rid_manager(struct ldb_module *module)
69 {
70         struct imessaging_context *msg;
71         unsigned num_servers;
72         struct server_id *servers;
73         struct ldb_context *ldb = ldb_module_get_ctx(module);
74         struct loadparm_context *lp_ctx =
75                 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
76         TALLOC_CTX *tmp_ctx = talloc_new(module);
77         NTSTATUS status;
78
79         msg = imessaging_client_init(tmp_ctx, lp_ctx,
80                                     ldb_get_event_context(ldb));
81         if (!msg) {
82                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
83                                 "Failed to send MSG_DREPL_ALLOCATE_RID, "
84                                 "unable init client messaging context");
85                 DEBUG(3,(__location__ ": Failed to create messaging context\n"));
86                 talloc_free(tmp_ctx);
87                 return LDB_ERR_UNWILLING_TO_PERFORM;
88         }
89
90         status = irpc_servers_byname(msg, msg, "dreplsrv",
91                                      &num_servers, &servers);
92         if (!NT_STATUS_IS_OK(status)) {
93                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
94                                 "Failed to send MSG_DREPL_ALLOCATE_RID, "
95                                 "unable to locate dreplsrv");
96                 /* this means the drepl service is not running */
97                 talloc_free(tmp_ctx);
98                 return LDB_ERR_UNWILLING_TO_PERFORM;
99         }
100
101         status = imessaging_send(msg, servers[0], MSG_DREPL_ALLOCATE_RID, NULL);
102
103         /* Only error out if an error happened, not on STATUS_MORE_ENTRIES, ie a delayed message */
104         if (NT_STATUS_IS_ERR(status)) {
105                 struct server_id_buf idbuf;
106                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
107                                 "Failed to send MSG_DREPL_ALLOCATE_RID to dreplsrv at %s: %s",
108                                 server_id_str_buf(*servers, &idbuf),
109                                 nt_errstr(status));
110                 talloc_free(tmp_ctx);
111                 return LDB_ERR_UNWILLING_TO_PERFORM;
112         }
113
114         talloc_free(tmp_ctx);
115         return LDB_SUCCESS;
116 }
117
118
119 static const char * const ridalloc_ridset_attrs[] = {
120         "rIDAllocationPool",
121         "rIDPreviousAllocationPool",
122         "rIDNextRID",
123         "rIDUsedPool",
124         NULL
125 };
126
127 struct ridalloc_ridset_values {
128         uint64_t alloc_pool;
129         uint64_t prev_pool;
130         uint32_t next_rid;
131         uint32_t used_pool;
132 };
133
134 static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
135 {
136         v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
137         v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
138         v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
139         v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
140 }
141
142 static int ridalloc_set_ridset_values(struct ldb_module *module,
143                                       struct ldb_message *msg,
144                                       const struct ridalloc_ridset_values *o,
145                                       const struct ridalloc_ridset_values *n)
146 {
147         const uint32_t *o32, *n32;
148         const uint64_t *o64, *n64;
149         int ret;
150
151 #define SETUP_PTRS(field, optr, nptr, max) do { \
152         optr = &o->field; \
153         nptr = &n->field; \
154         if (o->field == max) { \
155                 optr = NULL; \
156         } \
157         if (n->field == max) { \
158                 nptr = NULL; \
159         } \
160         if (o->field == n->field) { \
161                 optr = NULL; \
162                 nptr = NULL; \
163         } \
164 } while(0)
165
166         SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
167         ret = dsdb_msg_constrainted_update_uint64(module, msg,
168                                                   "rIDAllocationPool",
169                                                   o64, n64);
170         if (ret != LDB_SUCCESS) {
171                 return ret;
172         }
173
174         SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
175         ret = dsdb_msg_constrainted_update_uint64(module, msg,
176                                                   "rIDPreviousAllocationPool",
177                                                   o64, n64);
178         if (ret != LDB_SUCCESS) {
179                 return ret;
180         }
181
182         SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
183         ret = dsdb_msg_constrainted_update_uint32(module, msg,
184                                                   "rIDNextRID",
185                                                   o32, n32);
186         if (ret != LDB_SUCCESS) {
187                 return ret;
188         }
189
190         SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
191         ret = dsdb_msg_constrainted_update_uint32(module, msg,
192                                                   "rIDUsedPool",
193                                                   o32, n32);
194         if (ret != LDB_SUCCESS) {
195                 return ret;
196         }
197 #undef SETUP_PTRS
198
199         return LDB_SUCCESS;
200 }
201
202 /*
203   allocate a new range of RIDs in the RID Manager object
204  */
205 static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool,
206                                          struct ldb_request *parent)
207 {
208         int ret;
209         TALLOC_CTX *tmp_ctx = talloc_new(module);
210         const char *attrs[] = { "rIDAvailablePool", NULL };
211         uint64_t rid_pool, new_rid_pool, dc_pool;
212         uint32_t rid_pool_lo, rid_pool_hi;
213         struct ldb_result *res;
214         struct ldb_context *ldb = ldb_module_get_ctx(module);
215         const unsigned alloc_size = 500;
216
217         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
218                                     attrs, DSDB_FLAG_NEXT_MODULE, parent);
219         if (ret != LDB_SUCCESS) {
220                 ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
221                                        ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
222                 talloc_free(tmp_ctx);
223                 return ret;
224         }
225
226         rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
227         rid_pool_lo = rid_pool & 0xFFFFFFFF;
228         rid_pool_hi = rid_pool >> 32;
229         if (rid_pool_lo >= rid_pool_hi) {
230                 ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
231                                        rid_pool_lo, rid_pool_hi);
232                 talloc_free(tmp_ctx);
233                 return ret;
234         }
235
236         /* lower part of new pool is the low part of the rIDAvailablePool */
237         dc_pool = rid_pool_lo;
238
239         /* allocate 500 RIDs to this DC */
240         rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
241
242         /* work out upper part of new pool */
243         dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
244
245         /* and new rIDAvailablePool value */
246         new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
247
248         ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
249                                                      &rid_pool, &new_rid_pool, parent);
250         if (ret != LDB_SUCCESS) {
251                 ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
252                                        ldb_errstring(ldb));
253                 talloc_free(tmp_ctx);
254                 return ret;
255         }
256
257         (*new_pool) = dc_pool;
258         talloc_free(tmp_ctx);
259         return LDB_SUCCESS;
260 }
261
262 /*
263   create a RID Set object for the specified DC
264  */
265 static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
266                                         struct ldb_dn *rid_manager_dn,
267                                         struct ldb_dn *ntds_dn, struct ldb_dn **dn,
268                                         struct ldb_request *parent)
269 {
270         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
271         struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
272         int ret;
273         struct ldb_message *msg;
274         struct ldb_context *ldb = ldb_module_get_ctx(module);
275         static const struct ridalloc_ridset_values o = {
276                 .alloc_pool     = UINT64_MAX,
277                 .prev_pool      = UINT64_MAX,
278                 .next_rid       = UINT32_MAX,
279                 .used_pool      = UINT32_MAX,
280         };
281         struct ridalloc_ridset_values n = {
282                 .alloc_pool     = 0,
283                 .prev_pool      = 0,
284                 .next_rid       = 0,
285                 .used_pool      = 0,
286         };
287         const char *no_attrs[] = { NULL };
288         struct ldb_result *res;
289
290         /*
291           steps:
292
293           find the machine object for the DC
294           construct the RID Set DN
295           load rIDAvailablePool to find next available set
296           modify RID Manager object to update rIDAvailablePool
297           add the RID Set object
298           link to the RID Set object in machine object
299          */
300
301         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
302         if (!server_dn) {
303                 talloc_free(tmp_ctx);
304                 return ldb_module_oom(module);
305         }
306
307         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
308         if (ret != LDB_SUCCESS) {
309                 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
310                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
311                 talloc_free(tmp_ctx);
312                 return ret;
313         }
314
315         rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
316         if (rid_set_dn == NULL) {
317                 talloc_free(tmp_ctx);
318                 return ldb_module_oom(module);
319         }
320
321         if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
322                 talloc_free(tmp_ctx);
323                 return ldb_module_oom(module);
324         }
325
326         /* grab a pool from the RID Manager object */
327         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent);
328         if (ret != LDB_SUCCESS) {
329                 talloc_free(tmp_ctx);
330                 return ret;
331         }
332
333         /* create the RID Set object */
334         msg = ldb_msg_new(tmp_ctx);
335         msg->dn = rid_set_dn;
336
337         ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
338         if (ret != LDB_SUCCESS) {
339                 talloc_free(tmp_ctx);
340                 return ret;
341         }
342
343         ret = ridalloc_set_ridset_values(module, msg, &o, &n);
344         if (ret != LDB_SUCCESS) {
345                 talloc_free(tmp_ctx);
346                 return ret;
347         }
348
349         /* we need this to go all the way to the top of the module
350          * stack, as we need all the extra attributes added (including
351          * complex ones like ntsecuritydescriptor).  We must do this
352          * as system, otherwise a user might end up owning the RID
353          * set, and that would be bad... */
354         ret = dsdb_module_add(module, msg,
355                               DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM
356                               | DSDB_MODIFY_RELAX, parent);
357         if (ret != LDB_SUCCESS) {
358                 ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
359                                        ldb_dn_get_linearized(msg->dn),
360                                        ldb_errstring(ldb));
361                 talloc_free(tmp_ctx);
362                 return ret;
363         }
364
365         /* add the rIDSetReferences link */
366         msg = ldb_msg_new(tmp_ctx);
367         msg->dn = machine_dn;
368
369         /* we need the extended DN of the RID Set object for
370          * rIDSetReferences */
371         ret = dsdb_module_search_dn(module, msg, &res, rid_set_dn, no_attrs,
372                                     DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, parent);
373         if (ret != LDB_SUCCESS) {
374                 ldb_asprintf_errstring(ldb, "Failed to find extended DN of RID Set %s - %s",
375                                        ldb_dn_get_linearized(msg->dn),
376                                        ldb_errstring(ldb));
377                 talloc_free(tmp_ctx);
378                 return ret;
379         }
380         rid_set_dn = res->msgs[0]->dn;
381
382
383         ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_extended_linearized(msg, rid_set_dn, 1));
384         if (ret != LDB_SUCCESS) {
385                 talloc_free(tmp_ctx);
386                 return ret;
387         }
388         msg->elements[0].flags = LDB_FLAG_MOD_ADD;
389
390         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
391         if (ret != LDB_SUCCESS) {
392                 ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
393                                        ldb_dn_get_linearized(msg->dn),
394                                        ldb_errstring(ldb));
395                 talloc_free(tmp_ctx);
396                 return ret;
397         }
398
399         (*dn) = talloc_steal(mem_ctx, rid_set_dn);
400
401         talloc_free(tmp_ctx);
402         return LDB_SUCCESS;
403 }
404
405
406 /*
407   create a RID Set object for this DC
408  */
409 int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
410                                 struct ldb_dn **dn, struct ldb_request *parent)
411 {
412         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
413         struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
414         int ret;
415         struct ldb_context *ldb = ldb_module_get_ctx(module);
416         struct GUID fsmo_role_guid;
417         const struct GUID *our_ntds_guid;
418         NTSTATUS status;
419
420         /* work out who is the RID Manager */
421         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
422         if (ret != LDB_SUCCESS) {
423                 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
424                                        ldb_errstring(ldb));
425                 talloc_free(tmp_ctx);
426                 return ret;
427         }
428
429         /* find the DN of the RID Manager */
430         ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
431         if (ret != LDB_SUCCESS) {
432                 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
433                                        ldb_errstring(ldb));
434                 talloc_free(tmp_ctx);
435                 return ret;
436         }
437
438         status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID");
439         if (!NT_STATUS_IS_OK(status)) {
440                 talloc_free(tmp_ctx);
441                 return ldb_operr(ldb_module_get_ctx(module));
442         }
443
444         our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module));
445         if (!our_ntds_guid) {
446                 talloc_free(tmp_ctx);
447                 return ldb_operr(ldb_module_get_ctx(module));
448         }
449
450         if (!GUID_equal(&fsmo_role_guid, our_ntds_guid)) {
451                 ret = ridalloc_poke_rid_manager(module);
452                 if (ret != LDB_SUCCESS) {
453                         ldb_asprintf_errstring(ldb,
454                                         "Request for remote creation of "
455                                         "RID Set for this DC failed: %s",
456                                         ldb_errstring(ldb));
457                 } else {
458                         ldb_asprintf_errstring(ldb,
459                                         "Remote RID Set creation needed");
460                 }
461                 talloc_free(tmp_ctx);
462                 return LDB_ERR_UNWILLING_TO_PERFORM;
463         }
464
465         ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
466         talloc_free(tmp_ctx);
467         return ret;
468 }
469
470 /*
471   get a new RID pool for ourselves
472   also returns the first rid for the new pool
473  */
474
475 int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
476 {
477         TALLOC_CTX *tmp_ctx = talloc_new(module);
478         struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
479         int ret;
480         struct ldb_context *ldb = ldb_module_get_ctx(module);
481         bool is_us;
482
483         /* work out who is the RID Manager */
484         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
485         if (ret != LDB_SUCCESS) {
486                 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
487                                        ldb_errstring(ldb));
488                 talloc_free(tmp_ctx);
489                 return ret;
490         }
491
492         /* find the DN of the RID Manager */
493         ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
494         if (ret != LDB_SUCCESS) {
495                 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
496                                        ldb_errstring(ldb));
497                 talloc_free(tmp_ctx);
498                 return ret;
499         }
500
501         ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us);
502         if (ret != LDB_SUCCESS) {
503                 ldb_asprintf_errstring(ldb, "Failed to confirm if our ntdsDsa is %s: %s",
504                                        ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb));
505                 talloc_free(tmp_ctx);
506                 return ret;
507         }
508         
509         if (!is_us) {
510                 ret = ridalloc_poke_rid_manager(module);
511                 if (ret != LDB_SUCCESS) {
512                         ldb_asprintf_errstring(ldb, "Request for remote refresh of RID Set allocation failed: %s",
513                                                ldb_errstring(ldb));
514                 } else {
515                         ldb_asprintf_errstring(ldb, "Remote RID Set refresh needed");
516                 }
517                 talloc_free(tmp_ctx);
518                 return LDB_ERR_UNWILLING_TO_PERFORM;
519         }
520
521         /* grab a pool from the RID Manager object */
522         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
523         if (ret != LDB_SUCCESS) {
524                 talloc_free(tmp_ctx);
525                 return ret;
526         }
527
528         talloc_free(tmp_ctx);
529         return ret;
530 }
531
532
533 /* allocate a RID using our RID Set
534    If we run out of RIDs then allocate a new pool
535    either locally or by contacting the RID Manager
536 */
537 int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
538 {
539         struct ldb_context *ldb;
540         int ret;
541         struct ldb_dn *rid_set_dn;
542         struct ldb_result *res;
543         struct ldb_message *msg;
544         struct ridalloc_ridset_values oridset;
545         struct ridalloc_ridset_values nridset;
546         uint32_t prev_pool_lo, prev_pool_hi;
547         TALLOC_CTX *tmp_ctx = talloc_new(module);
548
549         (*rid) = 0;
550         ldb = ldb_module_get_ctx(module);
551
552         ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
553         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
554                 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
555         }
556         if (ret != LDB_SUCCESS) {
557                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
558                                        ldb_errstring(ldb));
559                 talloc_free(tmp_ctx);
560                 return ret;
561         }
562
563         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
564                                     ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
565         if (ret != LDB_SUCCESS) {
566                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
567                                        ldb_dn_get_linearized(rid_set_dn));
568                 talloc_free(tmp_ctx);
569                 return ret;
570         }
571
572         ridalloc_get_ridset_values(res->msgs[0], &oridset);
573         if (oridset.alloc_pool == UINT64_MAX) {
574                 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
575                                        ldb_dn_get_linearized(rid_set_dn));
576                 talloc_free(tmp_ctx);
577                 return LDB_ERR_OPERATIONS_ERROR;
578         }
579
580         nridset = oridset;
581
582         /*
583          * If we never used a pool, setup out first pool
584          */
585         if (nridset.prev_pool == UINT64_MAX ||
586             nridset.next_rid == UINT32_MAX) {
587                 nridset.prev_pool = nridset.alloc_pool;
588                 nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
589         }
590
591         /*
592          * Now check if our current pool is still usable
593          */
594         nridset.next_rid += 1;
595         prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
596         prev_pool_hi = nridset.prev_pool >> 32;
597         if (nridset.next_rid > prev_pool_hi) {
598                 /*
599                  * We need a new pool, check if we already have a new one
600                  * Otherwise we need to get a new pool.
601                  */
602                 if (nridset.alloc_pool == nridset.prev_pool) {
603                         /*
604                          * if we are the RID Manager,
605                          * we can get a new pool localy.
606                          * Otherwise we fail the operation and
607                          * ask async for a new pool.
608                          */
609                         ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
610                         if (ret != LDB_SUCCESS) {
611                                 ldb_asprintf_errstring(ldb, "NO RID values available: %s",
612                                                        ldb_errstring(ldb));
613                                 talloc_free(tmp_ctx);
614                                 return ret;
615                         }
616                 }
617
618                 /*
619                  * increment the rIDUsedPool attribute
620                  *
621                  * Note: w2k8r2 doesn't update this attribute,
622                  *       at least if it's itself the rid master.
623                  */
624                 nridset.used_pool += 1;
625
626                 /* now use the new pool */
627                 nridset.prev_pool = nridset.alloc_pool;
628                 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
629                 prev_pool_hi = nridset.prev_pool >> 32;
630                 nridset.next_rid = prev_pool_lo;
631         }
632
633         if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
634                 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
635                                        (unsigned)nridset.next_rid,
636                                        (unsigned)prev_pool_lo,
637                                        (unsigned)prev_pool_hi);
638                 talloc_free(tmp_ctx);
639                 return LDB_ERR_OPERATIONS_ERROR;
640         }
641
642         /*
643          * if we are half-exhausted then try to get a new pool.
644          */
645         if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2 &&
646             nridset.alloc_pool == nridset.prev_pool) {
647                 /*
648                  * if we are the RID Manager,
649                  * we can get a new pool localy.
650                  * Otherwise we fail the operation and
651                  * ask async for a new pool.
652                  */
653                 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
654                 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
655                         ldb_reset_err_string(ldb);
656                         ret = LDB_SUCCESS;
657                 }
658                 if (ret != LDB_SUCCESS) {
659                         talloc_free(tmp_ctx);
660                         return ret;
661                 }
662         }
663
664         /*
665          * update the values
666          */
667         msg = ldb_msg_new(tmp_ctx);
668         if (msg == NULL) {
669                 return ldb_module_oom(module);
670         }
671         msg->dn = rid_set_dn;
672
673         ret = ridalloc_set_ridset_values(module, msg,
674                                          &oridset, &nridset);
675         if (ret != LDB_SUCCESS) {
676                 talloc_free(tmp_ctx);
677                 return ret;
678         }
679
680         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
681         if (ret != LDB_SUCCESS) {
682                 talloc_free(tmp_ctx);
683                 return ret;
684         }
685
686         talloc_free(tmp_ctx);
687         *rid = nridset.next_rid;
688         return LDB_SUCCESS;
689 }
690
691
692 /*
693   called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
694
695   This is for the DRS server to allocate a RID Pool for another server.
696
697   Called by another server over DRS (which calls this extended
698   operation), it runs on the RID Manager only.
699  */
700 int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
701                                     struct ldb_request *parent)
702 {
703         struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
704         struct ldb_dn *rid_manager_dn;
705         TALLOC_CTX *tmp_ctx = talloc_new(module);
706         int ret;
707         struct ldb_context *ldb = ldb_module_get_ctx(module);
708         struct ldb_result *res;
709         struct ldb_message *msg;
710         struct ridalloc_ridset_values oridset, nridset;
711
712         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
713         if (ret != LDB_SUCCESS) {
714                 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
715                                        GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
716                 talloc_free(tmp_ctx);
717                 return ret;
718         }
719
720         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
721         if (!server_dn) {
722                 talloc_free(tmp_ctx);
723                 return ldb_module_oom(module);
724         }
725
726         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
727         if (ret != LDB_SUCCESS) {
728                 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
729                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
730                 talloc_free(tmp_ctx);
731                 return ret;
732         }
733
734         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
735         if (ret != LDB_SUCCESS) {
736                 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
737                                        ldb_errstring(ldb));
738                 talloc_free(tmp_ctx);
739                 return ret;
740         }
741
742         ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
743         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
744                 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
745                 talloc_free(tmp_ctx);
746                 return ret;
747         }
748
749         if (ret != LDB_SUCCESS) {
750                 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
751                                        ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
752                 talloc_free(tmp_ctx);
753                 return ret;
754         }
755
756         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
757                                     ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
758         if (ret != LDB_SUCCESS) {
759                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
760                                        ldb_dn_get_linearized(rid_set_dn));
761                 talloc_free(tmp_ctx);
762                 return ret;
763         }
764
765         ridalloc_get_ridset_values(res->msgs[0], &oridset);
766         if (oridset.alloc_pool == UINT64_MAX) {
767                 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
768                                        ldb_dn_get_linearized(rid_set_dn));
769                 talloc_free(tmp_ctx);
770                 return LDB_ERR_OPERATIONS_ERROR;
771         }
772
773         nridset = oridset;
774
775         if (exop->fsmo_info != 0) {
776
777                 if (nridset.alloc_pool != exop->fsmo_info) {
778                         /* it has already been updated */
779                         DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
780                                  (unsigned long long)exop->fsmo_info,
781                                  (unsigned long long)nridset.alloc_pool));
782                         talloc_free(tmp_ctx);
783                         return LDB_SUCCESS;
784                 }
785         }
786
787         /* grab a pool from the RID Manager object */
788         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
789         if (ret != LDB_SUCCESS) {
790                 talloc_free(tmp_ctx);
791                 return ret;
792         }
793
794         /*
795          * update the values
796          */
797         msg = ldb_msg_new(tmp_ctx);
798         if (msg == NULL) {
799                 return ldb_module_oom(module);
800         }
801         msg->dn = rid_set_dn;
802
803         ret = ridalloc_set_ridset_values(module, msg,
804                                          &oridset, &nridset);
805         if (ret != LDB_SUCCESS) {
806                 talloc_free(tmp_ctx);
807                 return ret;
808         }
809
810         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
811         if (ret != LDB_SUCCESS) {
812                 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
813                                        ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
814                 talloc_free(tmp_ctx);
815                 return ret;
816         }
817
818         talloc_free(tmp_ctx);
819         return LDB_SUCCESS;
820 }