Line data Source code
1 : /*
2 : Unix SMB/CIFS Implementation.
3 :
4 : DSDB replication service - RID allocation code
5 :
6 : Copyright (C) Andrew Tridgell 2010
7 : Copyright (C) Andrew Bartlett 2010
8 :
9 : based on drepl_notify.c
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 :
24 : */
25 :
26 : #include "includes.h"
27 : #include "ldb_module.h"
28 : #include "dsdb/samdb/samdb.h"
29 : #include "samba/service.h"
30 : #include "dsdb/repl/drepl_service.h"
31 : #include "param/param.h"
32 :
33 : #undef DBGC_CLASS
34 : #define DBGC_CLASS DBGC_DRS_REPL
35 :
36 : /*
37 : called when a rid allocation request has completed
38 : */
39 2 : static void drepl_new_rid_pool_callback(struct dreplsrv_service *service,
40 : WERROR werr,
41 : enum drsuapi_DsExtendedError ext_err,
42 : void *cb_data)
43 : {
44 2 : if (!W_ERROR_IS_OK(werr)) {
45 0 : DEBUG(0,(__location__ ": RID Manager failed RID allocation - %s - extended_ret[0x%X]\n",
46 : win_errstr(werr), ext_err));
47 : } else {
48 2 : DEBUG(3,(__location__ ": RID Manager completed RID allocation OK\n"));
49 : }
50 :
51 2 : service->rid_alloc_in_progress = false;
52 2 : }
53 :
54 : /*
55 : schedule a getncchanges request to the RID Manager to ask for a new
56 : set of RIDs using DRSUAPI_EXOP_FSMO_RID_ALLOC
57 : */
58 2 : static WERROR drepl_request_new_rid_pool(struct dreplsrv_service *service,
59 : struct ldb_dn *rid_manager_dn, struct ldb_dn *fsmo_role_dn,
60 : uint64_t alloc_pool)
61 : {
62 2 : WERROR werr = drepl_request_extended_op(service,
63 : rid_manager_dn,
64 : fsmo_role_dn,
65 : DRSUAPI_EXOP_FSMO_RID_ALLOC,
66 : alloc_pool,
67 : 0,
68 : drepl_new_rid_pool_callback, NULL);
69 2 : if (W_ERROR_IS_OK(werr)) {
70 2 : service->rid_alloc_in_progress = true;
71 : }
72 2 : return werr;
73 : }
74 :
75 :
76 : /*
77 : see if we are on the last pool we have
78 : */
79 17 : static int drepl_ridalloc_pool_exhausted(struct ldb_context *ldb,
80 : bool *exhausted,
81 : uint64_t *_alloc_pool)
82 : {
83 0 : struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
84 17 : TALLOC_CTX *tmp_ctx = talloc_new(ldb);
85 0 : uint64_t alloc_pool;
86 0 : uint64_t prev_pool;
87 0 : uint32_t prev_pool_lo, prev_pool_hi;
88 0 : uint32_t next_rid;
89 0 : static const char * const attrs[] = {
90 : "rIDAllocationPool",
91 : "rIDPreviousAllocationPool",
92 : "rIDNextRid",
93 : NULL
94 : };
95 0 : int ret;
96 0 : struct ldb_result *res;
97 :
98 17 : *exhausted = false;
99 17 : *_alloc_pool = UINT64_MAX;
100 :
101 17 : server_dn = ldb_dn_get_parent(tmp_ctx, samdb_ntds_settings_dn(ldb, tmp_ctx));
102 17 : if (!server_dn) {
103 0 : talloc_free(tmp_ctx);
104 0 : return ldb_operr(ldb);
105 : }
106 :
107 17 : ret = samdb_reference_dn(ldb, tmp_ctx, server_dn, "serverReference", &machine_dn);
108 17 : if (ret != LDB_SUCCESS) {
109 0 : DEBUG(0,(__location__ ": Failed to find serverReference in %s - %s\n",
110 : ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
111 0 : talloc_free(tmp_ctx);
112 0 : return ret;
113 : }
114 :
115 17 : ret = samdb_reference_dn(ldb, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn);
116 17 : if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
117 0 : *exhausted = true;
118 0 : *_alloc_pool = 0;
119 0 : talloc_free(tmp_ctx);
120 0 : return LDB_SUCCESS;
121 : }
122 17 : if (ret != LDB_SUCCESS) {
123 0 : DEBUG(0,(__location__ ": Failed to find rIDSetReferences in %s - %s\n",
124 : ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb)));
125 0 : talloc_free(tmp_ctx);
126 0 : return ret;
127 : }
128 :
129 17 : ret = ldb_search(ldb, tmp_ctx, &res, rid_set_dn, LDB_SCOPE_BASE, attrs, NULL);
130 17 : if (ret != LDB_SUCCESS) {
131 0 : DEBUG(0,(__location__ ": Failed to load RID Set attrs from %s - %s\n",
132 : ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)));
133 0 : talloc_free(tmp_ctx);
134 0 : return ret;
135 : }
136 :
137 17 : alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
138 17 : prev_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDPreviousAllocationPool", 0);
139 17 : prev_pool_lo = prev_pool & 0xFFFFFFFF;
140 17 : prev_pool_hi = prev_pool >> 32;
141 17 : next_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "rIDNextRid", 0);
142 :
143 17 : if (alloc_pool != prev_pool) {
144 12 : talloc_free(tmp_ctx);
145 12 : return LDB_SUCCESS;
146 : }
147 :
148 5 : if (next_rid < (prev_pool_hi + prev_pool_lo)/2) {
149 3 : talloc_free(tmp_ctx);
150 3 : return LDB_SUCCESS;
151 : }
152 :
153 2 : *exhausted = true;
154 2 : *_alloc_pool = alloc_pool;
155 2 : talloc_free(tmp_ctx);
156 2 : return LDB_SUCCESS;
157 : }
158 :
159 :
160 : /*
161 : see if we are low on RIDs in the RID Set rIDAllocationPool. If we
162 : are, then schedule a replication call with DRSUAPI_EXOP_FSMO_RID_ALLOC
163 : to the RID Manager
164 : */
165 212 : WERROR dreplsrv_ridalloc_check_rid_pool(struct dreplsrv_service *service)
166 : {
167 2 : struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
168 212 : TALLOC_CTX *tmp_ctx = talloc_new(service);
169 212 : struct ldb_context *ldb = service->samdb;
170 2 : bool exhausted;
171 2 : WERROR werr;
172 2 : int ret;
173 2 : uint64_t alloc_pool;
174 2 : bool is_us;
175 :
176 212 : if (service->am_rodc) {
177 6 : talloc_free(tmp_ctx);
178 6 : return WERR_OK;
179 : }
180 :
181 206 : if (service->rid_alloc_in_progress) {
182 4 : talloc_free(tmp_ctx);
183 4 : return WERR_OK;
184 : }
185 :
186 : /*
187 : steps:
188 : - find who the RID Manager is
189 : - if we are the RID Manager then nothing to do
190 : - find our RID Set object
191 : - load rIDAllocationPool and rIDPreviousAllocationPool
192 : - if rIDAllocationPool != rIDPreviousAllocationPool then
193 : nothing to do
194 : - schedule a getncchanges with DRSUAPI_EXOP_FSMO_RID_ALLOC
195 : to the RID Manager
196 : */
197 :
198 : /* work out who is the RID Manager */
199 202 : ret = samdb_rid_manager_dn(ldb, tmp_ctx, &rid_manager_dn);
200 202 : if (ret != LDB_SUCCESS) {
201 0 : DEBUG(0, (__location__ ": Failed to find RID Manager object - %s\n", ldb_errstring(ldb)));
202 0 : talloc_free(tmp_ctx);
203 0 : return WERR_DS_DRA_INTERNAL_ERROR;
204 : }
205 :
206 : /* find the DN of the RID Manager */
207 202 : ret = samdb_reference_dn(ldb, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn);
208 202 : if (ret != LDB_SUCCESS) {
209 0 : DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s\n",
210 : ldb_errstring(ldb)));
211 0 : talloc_free(tmp_ctx);
212 0 : return WERR_DS_DRA_INTERNAL_ERROR;
213 : }
214 :
215 202 : ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us);
216 202 : if (ret != LDB_SUCCESS) {
217 0 : DEBUG(0,(__location__ ": Failed to find determine if %s is our ntdsDsa object - %s\n",
218 : ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb)));
219 0 : talloc_free(tmp_ctx);
220 0 : return WERR_DS_DRA_INTERNAL_ERROR;
221 : }
222 :
223 202 : if (is_us) {
224 : /* we are the RID Manager - no need to do a
225 : DRSUAPI_EXOP_FSMO_RID_ALLOC */
226 185 : talloc_free(tmp_ctx);
227 185 : return WERR_OK;
228 : }
229 :
230 17 : ret = drepl_ridalloc_pool_exhausted(ldb, &exhausted, &alloc_pool);
231 17 : if (ret != LDB_SUCCESS) {
232 0 : talloc_free(tmp_ctx);
233 0 : return WERR_DS_DRA_INTERNAL_ERROR;
234 : }
235 :
236 17 : if (!exhausted) {
237 : /* don't need a new pool */
238 15 : talloc_free(tmp_ctx);
239 15 : return WERR_OK;
240 : }
241 :
242 2 : DEBUG(2,(__location__ ": Requesting more RIDs from RID Manager\n"));
243 :
244 2 : werr = drepl_request_new_rid_pool(service, rid_manager_dn, fsmo_role_dn, alloc_pool);
245 2 : talloc_free(tmp_ctx);
246 2 : return werr;
247 : }
248 :
249 : /* called by the samldb ldb module to tell us to ask for a new RID
250 : pool */
251 6 : void dreplsrv_allocate_rid(struct imessaging_context *msg,
252 : void *private_data,
253 : uint32_t msg_type,
254 : struct server_id server_id,
255 : size_t num_fds,
256 : int *fds,
257 : DATA_BLOB *data)
258 : {
259 6 : struct dreplsrv_service *service = talloc_get_type(private_data, struct dreplsrv_service);
260 6 : if (num_fds != 0) {
261 0 : DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
262 0 : return;
263 : }
264 6 : dreplsrv_ridalloc_check_rid_pool(service);
265 : }
|