LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - ridalloc.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 228 378 60.3 %
Date: 2024-02-28 12:06:22 Functions: 9 9 100.0 %

          Line data    Source code
       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         246 : static int ridalloc_poke_rid_manager(struct ldb_module *module)
      69             : {
      70           0 :         struct imessaging_context *msg;
      71           0 :         unsigned num_servers;
      72           0 :         struct server_id *servers;
      73         246 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
      74           0 :         struct loadparm_context *lp_ctx =
      75         246 :                 (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
      76         246 :         TALLOC_CTX *tmp_ctx = talloc_new(module);
      77           0 :         NTSTATUS status;
      78             : 
      79         246 :         msg = imessaging_client_init(tmp_ctx, lp_ctx,
      80             :                                     ldb_get_event_context(ldb));
      81         246 :         if (!msg) {
      82           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
      83             :                                 "Failed to send MSG_DREPL_ALLOCATE_RID, "
      84             :                                 "unable init client messaging context");
      85           0 :                 DEBUG(3,(__location__ ": Failed to create messaging context\n"));
      86           0 :                 talloc_free(tmp_ctx);
      87           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
      88             :         }
      89             : 
      90         246 :         status = irpc_servers_byname(msg, msg, "dreplsrv",
      91             :                                      &num_servers, &servers);
      92         246 :         if (!NT_STATUS_IS_OK(status)) {
      93         240 :                 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         240 :                 talloc_free(tmp_ctx);
      98         240 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
      99             :         }
     100             : 
     101           6 :         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           6 :         if (NT_STATUS_IS_ERR(status)) {
     105           0 :                 struct server_id_buf idbuf;
     106           0 :                 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           0 :                 talloc_free(tmp_ctx);
     111           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     112             :         }
     113             : 
     114           6 :         talloc_free(tmp_ctx);
     115           6 :         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       34547 : static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
     135             : {
     136       34547 :         v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
     137       34547 :         v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
     138       34547 :         v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
     139       34547 :         v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
     140       34547 : }
     141             : 
     142       34620 : 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         172 :         const uint32_t *o32, *n32;
     148         172 :         const uint64_t *o64, *n64;
     149         172 :         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       34620 :         SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
     167       34620 :         ret = dsdb_msg_constrainted_update_uint64(module, msg,
     168             :                                                   "rIDAllocationPool",
     169             :                                                   o64, n64);
     170       34620 :         if (ret != LDB_SUCCESS) {
     171           0 :                 return ret;
     172             :         }
     173             : 
     174       34620 :         SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
     175       34620 :         ret = dsdb_msg_constrainted_update_uint64(module, msg,
     176             :                                                   "rIDPreviousAllocationPool",
     177             :                                                   o64, n64);
     178       34620 :         if (ret != LDB_SUCCESS) {
     179           0 :                 return ret;
     180             :         }
     181             : 
     182       34620 :         SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
     183       34620 :         ret = dsdb_msg_constrainted_update_uint32(module, msg,
     184             :                                                   "rIDNextRID",
     185             :                                                   o32, n32);
     186       34620 :         if (ret != LDB_SUCCESS) {
     187           0 :                 return ret;
     188             :         }
     189             : 
     190       34620 :         SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
     191       34620 :         ret = dsdb_msg_constrainted_update_uint32(module, msg,
     192             :                                                   "rIDUsedPool",
     193             :                                                   o32, n32);
     194       34620 :         if (ret != LDB_SUCCESS) {
     195           0 :                 return ret;
     196             :         }
     197             : #undef SETUP_PTRS
     198             : 
     199       34448 :         return LDB_SUCCESS;
     200             : }
     201             : 
     202             : /*
     203             :   allocate a new range of RIDs in the RID Manager object
     204             :  */
     205         144 : 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           0 :         int ret;
     209         144 :         TALLOC_CTX *tmp_ctx = talloc_new(module);
     210         144 :         const char *attrs[] = { "rIDAvailablePool", NULL };
     211           0 :         uint64_t rid_pool, new_rid_pool, dc_pool;
     212           0 :         uint32_t rid_pool_lo, rid_pool_hi;
     213           0 :         struct ldb_result *res;
     214         144 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     215         144 :         const unsigned alloc_size = 500;
     216             : 
     217         144 :         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
     218             :                                     attrs, DSDB_FLAG_NEXT_MODULE, parent);
     219         144 :         if (ret != LDB_SUCCESS) {
     220           0 :                 ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
     221             :                                        ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
     222           0 :                 talloc_free(tmp_ctx);
     223           0 :                 return ret;
     224             :         }
     225             : 
     226         144 :         rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
     227         144 :         rid_pool_lo = rid_pool & 0xFFFFFFFF;
     228         144 :         rid_pool_hi = rid_pool >> 32;
     229         144 :         if (rid_pool_lo >= rid_pool_hi) {
     230           0 :                 ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
     231             :                                        rid_pool_lo, rid_pool_hi);
     232           0 :                 talloc_free(tmp_ctx);
     233           0 :                 return ret;
     234             :         }
     235             : 
     236             :         /* lower part of new pool is the low part of the rIDAvailablePool */
     237         144 :         dc_pool = rid_pool_lo;
     238             : 
     239             :         /* allocate 500 RIDs to this DC */
     240         144 :         rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
     241             : 
     242             :         /* work out upper part of new pool */
     243         144 :         dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
     244             : 
     245             :         /* and new rIDAvailablePool value */
     246         144 :         new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
     247             : 
     248         144 :         ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
     249             :                                                      &rid_pool, &new_rid_pool, parent);
     250         144 :         if (ret != LDB_SUCCESS) {
     251           0 :                 ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
     252             :                                        ldb_errstring(ldb));
     253           0 :                 talloc_free(tmp_ctx);
     254           0 :                 return ret;
     255             :         }
     256             : 
     257         144 :         (*new_pool) = dc_pool;
     258         144 :         talloc_free(tmp_ctx);
     259         144 :         return LDB_SUCCESS;
     260             : }
     261             : 
     262             : /*
     263             :   create a RID Set object for the specified DC
     264             :  */
     265          74 : 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          74 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     271           0 :         struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
     272           0 :         int ret;
     273           0 :         struct ldb_message *msg;
     274          74 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     275           0 :         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          74 :         struct ridalloc_ridset_values n = {
     282             :                 .alloc_pool     = 0,
     283             :                 .prev_pool      = 0,
     284             :                 .next_rid       = 0,
     285             :                 .used_pool      = 0,
     286             :         };
     287          74 :         const char *no_attrs[] = { NULL };
     288           0 :         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          74 :         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
     302          74 :         if (!server_dn) {
     303           0 :                 talloc_free(tmp_ctx);
     304           0 :                 return ldb_module_oom(module);
     305             :         }
     306             : 
     307          74 :         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
     308          74 :         if (ret != LDB_SUCCESS) {
     309           0 :                 ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
     310             :                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
     311           0 :                 talloc_free(tmp_ctx);
     312           0 :                 return ret;
     313             :         }
     314             : 
     315          74 :         rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
     316          74 :         if (rid_set_dn == NULL) {
     317           0 :                 talloc_free(tmp_ctx);
     318           0 :                 return ldb_module_oom(module);
     319             :         }
     320             : 
     321          74 :         if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
     322           0 :                 talloc_free(tmp_ctx);
     323           0 :                 return ldb_module_oom(module);
     324             :         }
     325             : 
     326             :         /* grab a pool from the RID Manager object */
     327          74 :         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent);
     328          74 :         if (ret != LDB_SUCCESS) {
     329           0 :                 talloc_free(tmp_ctx);
     330           0 :                 return ret;
     331             :         }
     332             : 
     333             :         /* create the RID Set object */
     334          74 :         msg = ldb_msg_new(tmp_ctx);
     335          74 :         msg->dn = rid_set_dn;
     336             : 
     337          74 :         ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
     338          74 :         if (ret != LDB_SUCCESS) {
     339           0 :                 talloc_free(tmp_ctx);
     340           0 :                 return ret;
     341             :         }
     342             : 
     343          74 :         ret = ridalloc_set_ridset_values(module, msg, &o, &n);
     344          74 :         if (ret != LDB_SUCCESS) {
     345           0 :                 talloc_free(tmp_ctx);
     346           0 :                 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          74 :         ret = dsdb_module_add(module, msg,
     355             :                               DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM
     356             :                               | DSDB_MODIFY_RELAX, parent);
     357          74 :         if (ret != LDB_SUCCESS) {
     358           2 :                 ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
     359             :                                        ldb_dn_get_linearized(msg->dn),
     360             :                                        ldb_errstring(ldb));
     361           2 :                 talloc_free(tmp_ctx);
     362           2 :                 return ret;
     363             :         }
     364             : 
     365             :         /* add the rIDSetReferences link */
     366          72 :         msg = ldb_msg_new(tmp_ctx);
     367          72 :         msg->dn = machine_dn;
     368             : 
     369             :         /* we need the extended DN of the RID Set object for
     370             :          * rIDSetReferences */
     371          72 :         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          72 :         if (ret != LDB_SUCCESS) {
     374           0 :                 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           0 :                 talloc_free(tmp_ctx);
     378           0 :                 return ret;
     379             :         }
     380          72 :         rid_set_dn = res->msgs[0]->dn;
     381             : 
     382             : 
     383          72 :         ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_extended_linearized(msg, rid_set_dn, 1));
     384          72 :         if (ret != LDB_SUCCESS) {
     385           0 :                 talloc_free(tmp_ctx);
     386           0 :                 return ret;
     387             :         }
     388          72 :         msg->elements[0].flags = LDB_FLAG_MOD_ADD;
     389             : 
     390          72 :         ret = dsdb_module_modify(module, msg,
     391             :                                  DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM,
     392             :                                  parent);
     393          72 :         if (ret != LDB_SUCCESS) {
     394           0 :                 ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
     395             :                                        ldb_dn_get_linearized(msg->dn),
     396             :                                        ldb_errstring(ldb));
     397           0 :                 talloc_free(tmp_ctx);
     398           0 :                 return ret;
     399             :         }
     400             : 
     401          72 :         (*dn) = talloc_steal(mem_ctx, rid_set_dn);
     402             : 
     403          72 :         talloc_free(tmp_ctx);
     404          72 :         return LDB_SUCCESS;
     405             : }
     406             : 
     407             : 
     408             : /*
     409             :   create a RID Set object for this DC
     410             :  */
     411          42 : int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
     412             :                                 struct ldb_dn **dn, struct ldb_request *parent)
     413             : {
     414          42 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     415           0 :         struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
     416           0 :         int ret;
     417          42 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     418           0 :         struct GUID fsmo_role_guid;
     419           0 :         const struct GUID *our_ntds_guid;
     420           0 :         NTSTATUS status;
     421             : 
     422             :         /* work out who is the RID Manager */
     423          42 :         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
     424          42 :         if (ret != LDB_SUCCESS) {
     425           0 :                 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
     426             :                                        ldb_errstring(ldb));
     427           0 :                 talloc_free(tmp_ctx);
     428           0 :                 return ret;
     429             :         }
     430             : 
     431             :         /* find the DN of the RID Manager */
     432          42 :         ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
     433          42 :         if (ret != LDB_SUCCESS) {
     434           0 :                 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
     435             :                                        ldb_errstring(ldb));
     436           0 :                 talloc_free(tmp_ctx);
     437           0 :                 return ret;
     438             :         }
     439             : 
     440          42 :         status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID");
     441          42 :         if (!NT_STATUS_IS_OK(status)) {
     442           0 :                 talloc_free(tmp_ctx);
     443           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     444             :         }
     445             : 
     446             :         /* clear the cache so we don't get an old ntds_guid */
     447          42 :         if (ldb_set_opaque(ldb, "cache.ntds_guid", NULL) != LDB_SUCCESS) {
     448           0 :                 talloc_free(tmp_ctx);
     449           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     450             :         }
     451             : 
     452          42 :         our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module));
     453          42 :         if (!our_ntds_guid) {
     454           0 :                 talloc_free(tmp_ctx);
     455           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     456             :         }
     457             : 
     458          42 :         if (!GUID_equal(&fsmo_role_guid, our_ntds_guid)) {
     459           0 :                 ret = ridalloc_poke_rid_manager(module);
     460           0 :                 if (ret != LDB_SUCCESS) {
     461           0 :                         ldb_asprintf_errstring(ldb,
     462             :                                         "Request for remote creation of "
     463             :                                         "RID Set for this DC failed: %s",
     464             :                                         ldb_errstring(ldb));
     465             :                 } else {
     466           0 :                         ldb_asprintf_errstring(ldb,
     467             :                                         "Remote RID Set creation needed");
     468             :                 }
     469           0 :                 talloc_free(tmp_ctx);
     470           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     471             :         }
     472             : 
     473          42 :         ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
     474          42 :         talloc_free(tmp_ctx);
     475          42 :         return ret;
     476             : }
     477             : 
     478             : /*
     479             :   get a new RID pool for ourselves
     480             :   also returns the first rid for the new pool
     481             :  */
     482             : 
     483         311 : int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
     484             : {
     485         311 :         TALLOC_CTX *tmp_ctx = talloc_new(module);
     486           0 :         struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
     487           0 :         int ret;
     488         311 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     489           0 :         bool is_us;
     490             : 
     491             :         /* work out who is the RID Manager */
     492         311 :         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
     493         311 :         if (ret != LDB_SUCCESS) {
     494           0 :                 ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
     495             :                                        ldb_errstring(ldb));
     496           0 :                 talloc_free(tmp_ctx);
     497           0 :                 return ret;
     498             :         }
     499             : 
     500             :         /* find the DN of the RID Manager */
     501         311 :         ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
     502         311 :         if (ret != LDB_SUCCESS) {
     503           0 :                 ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
     504             :                                        ldb_errstring(ldb));
     505           0 :                 talloc_free(tmp_ctx);
     506           0 :                 return ret;
     507             :         }
     508             : 
     509         311 :         ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us);
     510         311 :         if (ret != LDB_SUCCESS) {
     511           0 :                 ldb_asprintf_errstring(ldb, "Failed to confirm if our ntdsDsa is %s: %s",
     512             :                                        ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb));
     513           0 :                 talloc_free(tmp_ctx);
     514           0 :                 return ret;
     515             :         }
     516             :         
     517         311 :         if (!is_us) {
     518         246 :                 ret = ridalloc_poke_rid_manager(module);
     519         246 :                 if (ret != LDB_SUCCESS) {
     520         240 :                         ldb_asprintf_errstring(ldb, "Request for remote refresh of RID Set allocation failed: %s",
     521             :                                                ldb_errstring(ldb));
     522             :                 } else {
     523           6 :                         ldb_asprintf_errstring(ldb, "Remote RID Set refresh needed");
     524             :                 }
     525         246 :                 talloc_free(tmp_ctx);
     526         246 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     527             :         }
     528             : 
     529             :         /* grab a pool from the RID Manager object */
     530          65 :         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
     531          65 :         if (ret != LDB_SUCCESS) {
     532           0 :                 talloc_free(tmp_ctx);
     533           0 :                 return ret;
     534             :         }
     535             : 
     536          65 :         talloc_free(tmp_ctx);
     537          65 :         return ret;
     538             : }
     539             : 
     540             : 
     541             : /* allocate a RID using our RID Set
     542             :    If we run out of RIDs then allocate a new pool
     543             :    either locally or by contacting the RID Manager
     544             : */
     545       34543 : int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
     546             : {
     547         172 :         struct ldb_context *ldb;
     548         172 :         int ret;
     549         172 :         struct ldb_dn *rid_set_dn;
     550         172 :         struct ldb_result *res;
     551         172 :         struct ldb_message *msg;
     552         172 :         struct ridalloc_ridset_values oridset;
     553         172 :         struct ridalloc_ridset_values nridset;
     554         172 :         uint32_t prev_pool_lo, prev_pool_hi;
     555       34543 :         TALLOC_CTX *tmp_ctx = talloc_new(module);
     556             : 
     557       34543 :         (*rid) = 0;
     558       34543 :         ldb = ldb_module_get_ctx(module);
     559             : 
     560       34543 :         ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
     561       34543 :         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     562           3 :                 ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
     563             :         }
     564       34543 :         if (ret != LDB_SUCCESS) {
     565           1 :                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
     566             :                                        ldb_errstring(ldb));
     567           1 :                 talloc_free(tmp_ctx);
     568           1 :                 return ret;
     569             :         }
     570             : 
     571       34542 :         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
     572             :                                     ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
     573       34542 :         if (ret != LDB_SUCCESS) {
     574           0 :                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
     575             :                                        ldb_dn_get_linearized(rid_set_dn));
     576           0 :                 talloc_free(tmp_ctx);
     577           0 :                 return ret;
     578             :         }
     579             : 
     580       34542 :         ridalloc_get_ridset_values(res->msgs[0], &oridset);
     581       34542 :         if (oridset.alloc_pool == UINT64_MAX) {
     582           1 :                 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
     583             :                                        ldb_dn_get_linearized(rid_set_dn));
     584           1 :                 talloc_free(tmp_ctx);
     585           1 :                 return LDB_ERR_OPERATIONS_ERROR;
     586             :         }
     587             : 
     588       34541 :         nridset = oridset;
     589             : 
     590             :         /*
     591             :          * If we never used a pool, setup out first pool
     592             :          */
     593       34541 :         if (nridset.prev_pool == UINT64_MAX ||
     594       34536 :             nridset.next_rid == UINT32_MAX) {
     595           6 :                 nridset.prev_pool = nridset.alloc_pool;
     596           6 :                 nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
     597             :         } else {
     598       34535 :                 nridset.next_rid += 1;
     599             :         }
     600             : 
     601             :         /*
     602             :          * Now check if our current pool is still usable
     603             :          */
     604       34541 :         prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
     605       34541 :         prev_pool_hi = nridset.prev_pool >> 32;
     606       34541 :         if (nridset.next_rid > prev_pool_hi) {
     607             :                 /*
     608             :                  * We need a new pool, check if we already have a new one
     609             :                  * Otherwise we need to get a new pool.
     610             :                  */
     611          62 :                 if (nridset.alloc_pool == nridset.prev_pool) {
     612             :                         /*
     613             :                          * if we are the RID Manager,
     614             :                          * we can get a new pool locally.
     615             :                          * Otherwise we fail the operation and
     616             :                          * ask async for a new pool.
     617             :                          */
     618           1 :                         ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
     619           1 :                         if (ret != LDB_SUCCESS) {
     620           0 :                                 ldb_asprintf_errstring(ldb, "NO RID values available: %s",
     621             :                                                        ldb_errstring(ldb));
     622           0 :                                 talloc_free(tmp_ctx);
     623           0 :                                 return ret;
     624             :                         }
     625             :                 }
     626             : 
     627             :                 /*
     628             :                  * increment the rIDUsedPool attribute
     629             :                  *
     630             :                  * Note: w2k8r2 doesn't update this attribute,
     631             :                  *       at least if it's itself the rid master.
     632             :                  */
     633          62 :                 nridset.used_pool += 1;
     634             : 
     635             :                 /* now use the new pool */
     636          62 :                 nridset.prev_pool = nridset.alloc_pool;
     637          62 :                 prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
     638          62 :                 prev_pool_hi = nridset.prev_pool >> 32;
     639          62 :                 nridset.next_rid = prev_pool_lo;
     640             :         }
     641             : 
     642       34541 :         if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
     643           0 :                 ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
     644           0 :                                        (unsigned)nridset.next_rid,
     645             :                                        (unsigned)prev_pool_lo,
     646             :                                        (unsigned)prev_pool_hi);
     647           0 :                 talloc_free(tmp_ctx);
     648           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     649             :         }
     650             : 
     651             :         /*
     652             :          * if we are half-exhausted then try to get a new pool.
     653             :          */
     654       34541 :         if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2 &&
     655       15282 :             nridset.alloc_pool == nridset.prev_pool) {
     656             :                 /*
     657             :                  * if we are the RID Manager,
     658             :                  * we can get a new pool locally.
     659             :                  * Otherwise we fail the operation and
     660             :                  * ask async for a new pool.
     661             :                  */
     662         310 :                 ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
     663         310 :                 if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
     664         246 :                         ldb_reset_err_string(ldb);
     665         246 :                         ret = LDB_SUCCESS;
     666             :                 }
     667         310 :                 if (ret != LDB_SUCCESS) {
     668           0 :                         talloc_free(tmp_ctx);
     669           0 :                         return ret;
     670             :                 }
     671             :         }
     672             : 
     673             :         /*
     674             :          * update the values
     675             :          */
     676       34541 :         msg = ldb_msg_new(tmp_ctx);
     677       34541 :         if (msg == NULL) {
     678           0 :                 return ldb_module_oom(module);
     679             :         }
     680       34541 :         msg->dn = rid_set_dn;
     681             : 
     682       34541 :         ret = ridalloc_set_ridset_values(module, msg,
     683             :                                          &oridset, &nridset);
     684       34541 :         if (ret != LDB_SUCCESS) {
     685           0 :                 talloc_free(tmp_ctx);
     686           0 :                 return ret;
     687             :         }
     688             : 
     689       34541 :         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, parent);
     690       34541 :         if (ret != LDB_SUCCESS) {
     691           0 :                 talloc_free(tmp_ctx);
     692           0 :                 return ret;
     693             :         }
     694             : 
     695       34541 :         talloc_free(tmp_ctx);
     696       34541 :         *rid = nridset.next_rid;
     697       34541 :         return LDB_SUCCESS;
     698             : }
     699             : 
     700             : 
     701             : /*
     702             :   called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
     703             : 
     704             :   This is for the DRS server to allocate a RID Pool for another server.
     705             : 
     706             :   Called by another server over DRS (which calls this extended
     707             :   operation), it runs on the RID Manager only.
     708             :  */
     709          37 : int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
     710             :                                     struct ldb_request *parent)
     711             : {
     712           0 :         struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
     713           0 :         struct ldb_dn *rid_manager_dn;
     714          37 :         TALLOC_CTX *tmp_ctx = talloc_new(module);
     715           0 :         int ret;
     716          37 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     717           0 :         struct ldb_result *res;
     718           0 :         struct ldb_message *msg;
     719           0 :         struct ridalloc_ridset_values oridset, nridset;
     720             : 
     721          37 :         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
     722          37 :         if (ret != LDB_SUCCESS) {
     723           0 :                 ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
     724           0 :                                        GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
     725           0 :                 talloc_free(tmp_ctx);
     726           0 :                 return ret;
     727             :         }
     728             : 
     729          37 :         server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
     730          37 :         if (!server_dn) {
     731           0 :                 talloc_free(tmp_ctx);
     732           0 :                 return ldb_module_oom(module);
     733             :         }
     734             : 
     735          37 :         ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
     736          37 :         if (ret != LDB_SUCCESS) {
     737           0 :                 ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
     738             :                                        ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
     739           0 :                 talloc_free(tmp_ctx);
     740           0 :                 return ret;
     741             :         }
     742             : 
     743          37 :         ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
     744          37 :         if (ret != LDB_SUCCESS) {
     745           0 :                 ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
     746             :                                        ldb_errstring(ldb));
     747           0 :                 talloc_free(tmp_ctx);
     748           0 :                 return ret;
     749             :         }
     750             : 
     751          37 :         ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
     752          37 :         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     753          32 :                 ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
     754          32 :                 talloc_free(tmp_ctx);
     755          32 :                 return ret;
     756             :         }
     757             : 
     758           5 :         if (ret != LDB_SUCCESS) {
     759           0 :                 ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
     760             :                                        ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
     761           0 :                 talloc_free(tmp_ctx);
     762           0 :                 return ret;
     763             :         }
     764             : 
     765           5 :         ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
     766             :                                     ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
     767           5 :         if (ret != LDB_SUCCESS) {
     768           0 :                 ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
     769             :                                        ldb_dn_get_linearized(rid_set_dn));
     770           0 :                 talloc_free(tmp_ctx);
     771           0 :                 return ret;
     772             :         }
     773             : 
     774           5 :         ridalloc_get_ridset_values(res->msgs[0], &oridset);
     775           5 :         if (oridset.alloc_pool == UINT64_MAX) {
     776           0 :                 ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
     777             :                                        ldb_dn_get_linearized(rid_set_dn));
     778           0 :                 talloc_free(tmp_ctx);
     779           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     780             :         }
     781             : 
     782           5 :         nridset = oridset;
     783             : 
     784           5 :         if (exop->fsmo_info != 0) {
     785             : 
     786           2 :                 if (nridset.alloc_pool != exop->fsmo_info) {
     787             :                         /* it has already been updated */
     788           0 :                         DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
     789             :                                  (unsigned long long)exop->fsmo_info,
     790             :                                  (unsigned long long)nridset.alloc_pool));
     791           0 :                         talloc_free(tmp_ctx);
     792           0 :                         return LDB_SUCCESS;
     793             :                 }
     794             :         }
     795             : 
     796             :         /* grab a pool from the RID Manager object */
     797           5 :         ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
     798           5 :         if (ret != LDB_SUCCESS) {
     799           0 :                 talloc_free(tmp_ctx);
     800           0 :                 return ret;
     801             :         }
     802             : 
     803             :         /*
     804             :          * update the values
     805             :          */
     806           5 :         msg = ldb_msg_new(tmp_ctx);
     807           5 :         if (msg == NULL) {
     808           0 :                 return ldb_module_oom(module);
     809             :         }
     810           5 :         msg->dn = rid_set_dn;
     811             : 
     812           5 :         ret = ridalloc_set_ridset_values(module, msg,
     813             :                                          &oridset, &nridset);
     814           5 :         if (ret != LDB_SUCCESS) {
     815           0 :                 talloc_free(tmp_ctx);
     816           0 :                 return ret;
     817             :         }
     818             : 
     819           5 :         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, parent);
     820           5 :         if (ret != LDB_SUCCESS) {
     821           0 :                 ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
     822             :                                        ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
     823           0 :                 talloc_free(tmp_ctx);
     824           0 :                 return ret;
     825             :         }
     826             : 
     827           5 :         talloc_free(tmp_ctx);
     828           5 :         return LDB_SUCCESS;
     829             : }

Generated by: LCOV version 1.14