/* allocate a RID using our RID Set If we run out of RIDs then allocate a new pool either locally or by contacting the RID Manager */ int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent) { struct ldb_context *ldb; int ret; struct ldb_dn *rid_set_dn; struct ldb_result *res; struct ldb_message *msg; struct ridalloc_ridset_values oridset; struct ridalloc_ridset_values nridset; uint32_t prev_pool_lo, prev_pool_hi; TALLOC_CTX *tmp_ctx = talloc_new(module); (*rid) = 0; ldb = ldb_module_get_ctx(module); ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn); if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent); } if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s", ldb_errstring(ldb)); talloc_free(tmp_ctx); return ret; } ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s", ldb_dn_get_linearized(rid_set_dn)); talloc_free(tmp_ctx); return ret; } ridalloc_get_ridset_values(res->msgs[0], &oridset); if (oridset.alloc_pool == UINT64_MAX) { ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s", ldb_dn_get_linearized(rid_set_dn)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } nridset = oridset; /* * If we never used a pool, setup out first pool */ if (nridset.prev_pool == UINT64_MAX || nridset.next_rid == UINT32_MAX) { nridset.prev_pool = nridset.alloc_pool; nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF; } /* * Now check if our current pool is still usable */ nridset.next_rid += 1; prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF; prev_pool_hi = nridset.prev_pool >> 32; if (nridset.next_rid > prev_pool_hi) { /* * We need a new pool, check if we already have a new one * Otherwise we need to get a new pool. */ if (nridset.alloc_pool == nridset.prev_pool) { /* * if we are the RID Manager, * we can get a new pool localy. * Otherwise we fail the operation and * ask async for a new pool. */ ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent); if (ret == LDB_ERR_UNWILLING_TO_PERFORM) { ridalloc_poke_rid_manager(module); talloc_free(tmp_ctx); return ret; } if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } } /* * increment the rIDUsedPool attribute * * Note: w2k8r2 doesn't update this attribute, * at least if it's itself the rid master. */ nridset.used_pool += 1; /* now use the new pool */ nridset.prev_pool = nridset.alloc_pool; prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF; prev_pool_hi = nridset.prev_pool >> 32; nridset.next_rid = prev_pool_lo; } if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) { ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u", (unsigned)nridset.next_rid, (unsigned)prev_pool_lo, (unsigned)prev_pool_hi); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } /* * if we are half-exhausted then try to get a new pool. */ if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2) { /* * if we are the RID Manager, * we can get a new pool localy. * Otherwise we fail the operation and * ask async for a new pool. */ ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent); if (ret == LDB_ERR_UNWILLING_TO_PERFORM) { ridalloc_poke_rid_manager(module); ret = LDB_SUCCESS; } if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } } /* * update the values */ msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { return ldb_module_oom(module); } msg->dn = rid_set_dn; ret = ridalloc_set_ridset_values(module, msg, &oridset, &nridset); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } talloc_free(tmp_ctx); *rid = nridset.next_rid; return LDB_SUCCESS; }
/* allocate a RID using our RID Set If we run out of RIDs then allocate a new pool either locally or by contacting the RID Manager */ int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid) { struct ldb_context *ldb; static const char * const attrs[] = { "rIDAllocationPool", "rIDPreviousAllocationPool", "rIDNextRID" , "rIDUsedPool", NULL }; int ret; struct ldb_dn *rid_set_dn; struct ldb_result *res; uint64_t alloc_pool, prev_alloc_pool; uint32_t prev_alloc_pool_lo, prev_alloc_pool_hi; uint32_t rid_used_pool; int prev_rid; TALLOC_CTX *tmp_ctx = talloc_new(module); (*rid) = 0; ldb = ldb_module_get_ctx(module); ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn); if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn); } if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s", ldb_errstring(ldb)); talloc_free(tmp_ctx); return ret; } ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, attrs, 0); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s", ldb_dn_get_linearized(rid_set_dn)); talloc_free(tmp_ctx); return ret; } prev_alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDPreviousAllocationPool", 0); alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0); prev_rid = ldb_msg_find_attr_as_int(res->msgs[0], "rIDNextRID", 0); rid_used_pool = ldb_msg_find_attr_as_int(res->msgs[0], "rIDUsedPool", 0); if (alloc_pool == 0) { ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s", ldb_dn_get_linearized(rid_set_dn)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF; prev_alloc_pool_hi = prev_alloc_pool >> 32; if (prev_rid >= prev_alloc_pool_hi) { if (prev_alloc_pool == 0) { ret = dsdb_module_set_integer(module, rid_set_dn, "rIDPreviousAllocationPool", alloc_pool); } else { ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool", prev_alloc_pool, alloc_pool); } if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s", ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)); talloc_free(tmp_ctx); return ret; } prev_alloc_pool = alloc_pool; prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF; prev_alloc_pool_hi = prev_alloc_pool >> 32; /* update the rIDUsedPool attribute */ ret = dsdb_module_set_integer(module, rid_set_dn, "rIDUsedPool", rid_used_pool+1); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDUsedPool on %s - %s", ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)); talloc_free(tmp_ctx); return ret; } (*rid) = prev_alloc_pool_lo; } /* see if we are still out of RIDs, and if so then ask the RID Manager to give us more */ if (prev_rid >= prev_alloc_pool_hi) { uint64_t new_pool; ret = ridalloc_refresh_own_pool(module, &new_pool); if (ret != LDB_SUCCESS) { return ret; } ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool", prev_alloc_pool, new_pool); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s", ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)); talloc_free(tmp_ctx); return ret; } prev_alloc_pool = new_pool; prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF; prev_alloc_pool_hi = prev_alloc_pool >> 32; (*rid) = prev_alloc_pool_lo; } else {