Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : DRS Replica Information
5 :
6 : Copyright (C) Erick Nogueira do Nascimento 2009-2010
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 :
21 : */
22 :
23 : #include "includes.h"
24 : #include "dsdb/samdb/samdb.h"
25 : #include "dsdb/common/proto.h"
26 : #include "auth/auth.h"
27 : #include "samba/service.h"
28 : #include "lib/events/events.h"
29 : #include "lib/messaging/irpc.h"
30 : #include "dsdb/kcc/kcc_service.h"
31 : #include <ldb_errors.h>
32 : #include "../lib/util/dlinklist.h"
33 : #include "librpc/gen_ndr/ndr_misc.h"
34 : #include "librpc/gen_ndr/ndr_drsuapi.h"
35 : #include "librpc/gen_ndr/ndr_drsblobs.h"
36 : #include "param/param.h"
37 : #include "dsdb/common/util.h"
38 :
39 :
40 : /*
41 : get the stamp values for the linked attribute 'linked_attr_name' of the object 'dn'
42 : */
43 0 : static WERROR get_linked_attribute_value_stamp(TALLOC_CTX *mem_ctx, struct ldb_context *samdb,
44 : struct ldb_dn *dn, const char *linked_attr_name,
45 : uint32_t *attr_version, NTTIME *attr_change_time, uint32_t *attr_orig_usn)
46 : {
47 0 : struct ldb_result *res;
48 0 : int ret;
49 0 : const char *attrs[2];
50 0 : struct ldb_dn *attr_ext_dn;
51 0 : NTSTATUS ntstatus;
52 :
53 0 : attrs[0] = linked_attr_name;
54 0 : attrs[1] = NULL;
55 :
56 0 : ret = dsdb_search_dn(samdb, mem_ctx, &res, dn, attrs,
57 : DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_REVEAL_INTERNALS);
58 0 : if (ret != LDB_SUCCESS) {
59 0 : DEBUG(0, (__location__ ": Failed search for attribute %s on %s\n",
60 : linked_attr_name, ldb_dn_get_linearized(dn)));
61 0 : return WERR_INTERNAL_ERROR;
62 : }
63 :
64 0 : attr_ext_dn = ldb_msg_find_attr_as_dn(samdb, mem_ctx, res->msgs[0], linked_attr_name);
65 0 : if (!attr_ext_dn) {
66 0 : DEBUG(0, (__location__ ": Failed search for attribute %s on %s\n",
67 : linked_attr_name, ldb_dn_get_linearized(dn)));
68 0 : return WERR_INTERNAL_ERROR;
69 : }
70 :
71 0 : DEBUG(0, ("linked_attr_name = %s, attr_ext_dn = %s", linked_attr_name,
72 : ldb_dn_get_extended_linearized(mem_ctx, attr_ext_dn, 1)));
73 :
74 0 : ntstatus = dsdb_get_extended_dn_uint32(attr_ext_dn, attr_version, "RMD_VERSION");
75 0 : if (!NT_STATUS_IS_OK(ntstatus)) {
76 0 : DEBUG(0, (__location__ ": Could not extract component %s from dn \"%s\"\n",
77 : "RMD_VERSION", ldb_dn_get_extended_linearized(mem_ctx, attr_ext_dn, 1)));
78 0 : return WERR_INTERNAL_ERROR;
79 : }
80 :
81 0 : ntstatus = dsdb_get_extended_dn_nttime(attr_ext_dn, attr_change_time, "RMD_CHANGETIME");
82 0 : if (!NT_STATUS_IS_OK(ntstatus)) {
83 0 : DEBUG(0, (__location__ ": Could not extract component %s from dn \"%s\"\n",
84 : "RMD_CHANGETIME", ldb_dn_get_extended_linearized(mem_ctx, attr_ext_dn, 1)));
85 0 : return WERR_INTERNAL_ERROR;
86 : }
87 :
88 0 : ntstatus = dsdb_get_extended_dn_uint32(attr_ext_dn, attr_version, "RMD_ORIGINATING_USN");
89 0 : if (!NT_STATUS_IS_OK(ntstatus)) {
90 0 : DEBUG(0, (__location__ ": Could not extract component %s from dn \"%s\"\n",
91 : "RMD_ORIGINATING_USN", ldb_dn_get_extended_linearized(mem_ctx, attr_ext_dn, 1)));
92 0 : return WERR_INTERNAL_ERROR;
93 : }
94 :
95 0 : return WERR_OK;
96 : }
97 :
98 0 : static WERROR get_repl_prop_metadata_ctr(TALLOC_CTX *mem_ctx,
99 : struct ldb_context *samdb,
100 : struct ldb_dn *dn,
101 : struct replPropertyMetaDataBlob *obj_metadata_ctr)
102 : {
103 0 : int ret;
104 0 : struct ldb_result *res;
105 0 : const char *attrs[] = { "replPropertyMetaData", NULL };
106 0 : const struct ldb_val *omd_value;
107 0 : enum ndr_err_code ndr_err;
108 :
109 0 : ret = ldb_search(samdb, mem_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
110 0 : if (ret != LDB_SUCCESS || res->count != 1) {
111 0 : DEBUG(0, (__location__ ": Failed search for replPropertyMetaData attribute on %s\n",
112 : ldb_dn_get_linearized(dn)));
113 0 : return WERR_INTERNAL_ERROR;
114 : }
115 :
116 0 : omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
117 0 : if (!omd_value) {
118 0 : DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
119 : ldb_dn_get_linearized(dn)));
120 0 : talloc_free(res);
121 0 : return WERR_INTERNAL_ERROR;
122 : }
123 :
124 0 : ndr_err = ndr_pull_struct_blob(omd_value, mem_ctx,
125 : obj_metadata_ctr,
126 : (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
127 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
128 0 : DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
129 : ldb_dn_get_linearized(dn)));
130 0 : talloc_free(res);
131 0 : return WERR_INTERNAL_ERROR;
132 : }
133 :
134 0 : talloc_free(res);
135 0 : return WERR_OK;
136 : }
137 :
138 : /*
139 : get the DN of the nTDSDSA object from the configuration partition
140 : whose invocationId is 'invocation_id'
141 : put the value on 'dn_str'
142 : */
143 0 : static WERROR get_dn_from_invocation_id(TALLOC_CTX *mem_ctx,
144 : struct ldb_context *samdb,
145 : struct GUID *invocation_id,
146 : const char **dn_str)
147 : {
148 0 : char *invocation_id_str;
149 0 : const char *attrs_invocation[] = { NULL };
150 0 : struct ldb_message *msg;
151 0 : int ret;
152 :
153 0 : invocation_id_str = GUID_string(mem_ctx, invocation_id);
154 0 : W_ERROR_HAVE_NO_MEMORY(invocation_id_str);
155 :
156 0 : ret = dsdb_search_one(samdb, invocation_id_str, &msg, ldb_get_config_basedn(samdb), LDB_SCOPE_SUBTREE,
157 : attrs_invocation, 0, "(&(objectClass=nTDSDSA)(invocationId=%s))", invocation_id_str);
158 0 : if (ret != LDB_SUCCESS) {
159 0 : DEBUG(0, (__location__ ": Failed search for the object DN under %s whose invocationId is %s\n",
160 : invocation_id_str, ldb_dn_get_linearized(ldb_get_config_basedn(samdb))));
161 0 : talloc_free(invocation_id_str);
162 0 : return WERR_INTERNAL_ERROR;
163 : }
164 :
165 0 : *dn_str = ldb_dn_alloc_linearized(mem_ctx, msg->dn);
166 0 : talloc_free(invocation_id_str);
167 0 : return WERR_OK;
168 : }
169 :
170 : /*
171 : get metadata version 2 info for a specified object DN
172 : */
173 0 : static WERROR kccdrs_replica_get_info_obj_metadata2(TALLOC_CTX *mem_ctx,
174 : struct ldb_context *samdb,
175 : struct drsuapi_DsReplicaGetInfo *r,
176 : union drsuapi_DsReplicaInfo *reply,
177 : struct ldb_dn *dn,
178 : uint32_t base_index)
179 : {
180 0 : WERROR status;
181 0 : struct replPropertyMetaDataBlob omd_ctr;
182 0 : struct replPropertyMetaData1 *attr;
183 0 : struct drsuapi_DsReplicaObjMetaData2Ctr *metadata2;
184 0 : const struct dsdb_schema *schema;
185 :
186 0 : uint32_t i, j;
187 :
188 0 : DEBUG(0, ("kccdrs_replica_get_info_obj_metadata2() called\n"));
189 :
190 0 : if (!dn) {
191 0 : return WERR_INVALID_PARAMETER;
192 : }
193 :
194 0 : if (!ldb_dn_validate(dn)) {
195 0 : return WERR_DS_DRA_BAD_DN;
196 : }
197 :
198 0 : status = get_repl_prop_metadata_ctr(mem_ctx, samdb, dn, &omd_ctr);
199 0 : W_ERROR_NOT_OK_RETURN(status);
200 :
201 0 : schema = dsdb_get_schema(samdb, reply);
202 0 : if (!schema) {
203 0 : DEBUG(0,(__location__": Failed to get the schema\n"));
204 0 : return WERR_INTERNAL_ERROR;
205 : }
206 :
207 0 : reply->objmetadata2 = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjMetaData2Ctr);
208 0 : W_ERROR_HAVE_NO_MEMORY(reply->objmetadata2);
209 0 : metadata2 = reply->objmetadata2;
210 0 : metadata2->enumeration_context = 0;
211 :
212 : /* For each replicated attribute of the object */
213 0 : for (i = 0, j = 0; i < omd_ctr.ctr.ctr1.count; i++) {
214 0 : const struct dsdb_attribute *schema_attr;
215 0 : uint32_t attr_version;
216 0 : NTTIME attr_change_time;
217 0 : uint32_t attr_originating_usn = 0;
218 :
219 : /*
220 : attr := attrsSeq[i]
221 : s := AttrStamp(object, attr)
222 : */
223 : /* get a reference to the attribute on 'omd_ctr' */
224 0 : attr = &omd_ctr.ctr.ctr1.array[j];
225 :
226 0 : schema_attr = dsdb_attribute_by_attributeID_id(schema, attr->attid);
227 :
228 0 : DEBUG(0, ("attribute_id = %d, attribute_name: %s\n", attr->attid, schema_attr->lDAPDisplayName));
229 :
230 : /*
231 : if (attr in Link Attributes of object and
232 : dwInVersion = 2 and DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS in msgIn.ulFlags)
233 : */
234 0 : if (schema_attr &&
235 0 : schema_attr->linkID != 0 && /* Checks if attribute is a linked attribute */
236 0 : (schema_attr->linkID % 2) == 0 && /* is it a forward link? only forward links have the LinkValueStamp */
237 0 : r->in.level == 2 &&
238 0 : (r->in.req->req2.flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) /* on MS-DRSR it is DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS */
239 : {
240 : /*
241 : ls := LinkValueStamp of the most recent
242 : value change in object!attr
243 : */
244 0 : status = get_linked_attribute_value_stamp(mem_ctx, samdb, dn, schema_attr->lDAPDisplayName,
245 : &attr_version, &attr_change_time, &attr_originating_usn);
246 0 : W_ERROR_NOT_OK_RETURN(status);
247 :
248 : /*
249 : Aligning to MS-DRSR 4.1.13.3:
250 : 's' on the doc is 'attr->originating_change_time' here
251 : 'ls' on the doc is 'attr_change_time' here
252 : */
253 :
254 : /* if (ls is more recent than s (based on order in which the change was applied on server)) then */
255 0 : if (attr_change_time > attr->originating_change_time) {
256 : /*
257 : Improve the stamp with the link value stamp.
258 : s.dwVersion := ls.dwVersion
259 : s.timeChanged := ls.timeChanged
260 : s.uuidOriginating := NULLGUID
261 : s.usnOriginating := ls.usnOriginating
262 : */
263 0 : attr->version = attr_version;
264 0 : attr->originating_change_time = attr_change_time;
265 0 : attr->originating_invocation_id = GUID_zero();
266 0 : attr->originating_usn = attr_originating_usn;
267 : }
268 : }
269 :
270 0 : if (i < base_index) {
271 0 : continue;
272 : }
273 :
274 0 : metadata2->array = talloc_realloc(mem_ctx, metadata2->array,
275 : struct drsuapi_DsReplicaObjMetaData2, j + 1);
276 0 : W_ERROR_HAVE_NO_MEMORY(metadata2->array);
277 0 : metadata2->array[j].attribute_name = schema_attr->lDAPDisplayName;
278 0 : metadata2->array[j].local_usn = attr->local_usn;
279 0 : metadata2->array[j].originating_change_time = attr->originating_change_time;
280 0 : metadata2->array[j].originating_invocation_id = attr->originating_invocation_id;
281 0 : metadata2->array[j].originating_usn = attr->originating_usn;
282 0 : metadata2->array[j].version = attr->version;
283 :
284 : /*
285 : originating_dsa_dn := GetDNFromInvocationID(originating_invocation_id)
286 : GetDNFromInvocationID() should return the DN of the nTDSDSAobject that has the specified invocation ID
287 : See MS-DRSR 4.1.13.3 and 4.1.13.2.1
288 : */
289 0 : status = get_dn_from_invocation_id(mem_ctx, samdb,
290 : &attr->originating_invocation_id,
291 0 : &metadata2->array[j].originating_dsa_dn);
292 0 : W_ERROR_NOT_OK_RETURN(status);
293 0 : j++;
294 0 : metadata2->count = j;
295 :
296 : }
297 :
298 0 : return WERR_OK;
299 : }
300 :
301 : /*
302 : get cursors info for a specified DN
303 : */
304 0 : static WERROR kccdrs_replica_get_info_cursors(TALLOC_CTX *mem_ctx,
305 : struct ldb_context *samdb,
306 : struct drsuapi_DsReplicaGetInfo *r,
307 : union drsuapi_DsReplicaInfo *reply,
308 : struct ldb_dn *dn)
309 : {
310 0 : int ret;
311 :
312 0 : if (!ldb_dn_validate(dn)) {
313 0 : return WERR_INVALID_PARAMETER;
314 : }
315 0 : reply->cursors = talloc(mem_ctx, struct drsuapi_DsReplicaCursorCtr);
316 0 : W_ERROR_HAVE_NO_MEMORY(reply->cursors);
317 :
318 0 : reply->cursors->reserved = 0;
319 :
320 0 : ret = dsdb_load_udv_v1(samdb, dn, reply->cursors, &reply->cursors->array, &reply->cursors->count);
321 0 : if (ret != LDB_SUCCESS) {
322 0 : return WERR_DS_DRA_BAD_NC;
323 : }
324 0 : return WERR_OK;
325 : }
326 :
327 : /*
328 : get cursors2 info for a specified DN
329 : */
330 0 : static WERROR kccdrs_replica_get_info_cursors2(TALLOC_CTX *mem_ctx,
331 : struct ldb_context *samdb,
332 : struct drsuapi_DsReplicaGetInfo *r,
333 : union drsuapi_DsReplicaInfo *reply,
334 : struct ldb_dn *dn)
335 : {
336 0 : int ret;
337 :
338 0 : if (!ldb_dn_validate(dn)) {
339 0 : return WERR_INVALID_PARAMETER;
340 : }
341 0 : reply->cursors2 = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2Ctr);
342 0 : W_ERROR_HAVE_NO_MEMORY(reply->cursors2);
343 :
344 0 : ret = dsdb_load_udv_v2(samdb, dn, reply->cursors2, &reply->cursors2->array, &reply->cursors2->count);
345 0 : if (ret != LDB_SUCCESS) {
346 0 : return WERR_DS_DRA_BAD_NC;
347 : }
348 :
349 0 : reply->cursors2->enumeration_context = reply->cursors2->count;
350 0 : return WERR_OK;
351 : }
352 :
353 : /*
354 : get pending ops info for a specified DN
355 : */
356 0 : static WERROR kccdrs_replica_get_info_pending_ops(TALLOC_CTX *mem_ctx,
357 : struct ldb_context *samdb,
358 : struct drsuapi_DsReplicaGetInfo *r,
359 : union drsuapi_DsReplicaInfo *reply,
360 : struct ldb_dn *dn)
361 : {
362 0 : struct timeval now = timeval_current();
363 :
364 0 : if (!ldb_dn_validate(dn)) {
365 0 : return WERR_INVALID_PARAMETER;
366 : }
367 0 : reply->pendingops = talloc(mem_ctx, struct drsuapi_DsReplicaOpCtr);
368 0 : W_ERROR_HAVE_NO_MEMORY(reply->pendingops);
369 :
370 : /* claim no pending ops for now */
371 0 : reply->pendingops->time = timeval_to_nttime(&now);
372 0 : reply->pendingops->count = 0;
373 0 : reply->pendingops->array = NULL;
374 :
375 0 : return WERR_OK;
376 : }
377 :
378 : struct ncList {
379 : struct ldb_dn *dn;
380 : struct ncList *prev, *next;
381 : };
382 :
383 : /*
384 : Fill 'master_nc_list' with the master ncs hosted by this server
385 : */
386 10 : static WERROR get_master_ncs(TALLOC_CTX *mem_ctx, struct ldb_context *samdb,
387 : const char *ntds_guid_str, struct ncList **master_nc_list)
388 : {
389 10 : const char *post_2003_attrs[] = { "msDS-hasMasterNCs", "hasPartialReplicaNCs", NULL };
390 10 : const char *pre_2003_attrs[] = { "hasMasterNCs", "hasPartialReplicaNCs", NULL };
391 10 : const char **attrs = post_2003_attrs;
392 0 : struct ldb_result *res;
393 10 : struct ncList *nc_list = NULL;
394 0 : struct ncList *nc_list_elem;
395 0 : int ret;
396 0 : unsigned int i;
397 0 : char *nc_str;
398 :
399 : /* In W2003 and greater, msDS-hasMasterNCs attribute lists the writable NC replicas */
400 10 : ret = ldb_search(samdb, mem_ctx, &res, ldb_get_config_basedn(samdb),
401 : LDB_SCOPE_DEFAULT, post_2003_attrs, "(objectguid=%s)", ntds_guid_str);
402 :
403 10 : if (ret != LDB_SUCCESS) {
404 0 : DEBUG(0,(__location__ ": Failed objectguid search - %s\n", ldb_errstring(samdb)));
405 :
406 0 : attrs = post_2003_attrs;
407 0 : ret = ldb_search(samdb, mem_ctx, &res, ldb_get_config_basedn(samdb),
408 : LDB_SCOPE_DEFAULT, pre_2003_attrs, "(objectguid=%s)", ntds_guid_str);
409 : }
410 :
411 10 : if (ret != LDB_SUCCESS) {
412 0 : DEBUG(0,(__location__ ": Failed objectguid search - %s\n", ldb_errstring(samdb)));
413 0 : return WERR_INTERNAL_ERROR;
414 : }
415 :
416 10 : if (res->count == 0) {
417 0 : DEBUG(0,(__location__ ": Failed: objectguid=%s not found\n", ntds_guid_str));
418 0 : return WERR_INTERNAL_ERROR;
419 : }
420 :
421 20 : for (i = 0; i < res->count; i++) {
422 : struct ldb_message_element *msg_elem;
423 : unsigned int k, a;
424 :
425 30 : for (a=0; attrs[a]; a++) {
426 20 : msg_elem = ldb_msg_find_element(res->msgs[i], attrs[a]);
427 20 : if (!msg_elem || msg_elem->num_values == 0) {
428 10 : continue;
429 : }
430 :
431 60 : for (k = 0; k < msg_elem->num_values; k++) {
432 : /* copy the string on msg_elem->values[k]->data to nc_str */
433 50 : nc_str = talloc_strndup(mem_ctx, (char *)msg_elem->values[k].data, msg_elem->values[k].length);
434 50 : W_ERROR_HAVE_NO_MEMORY(nc_str);
435 :
436 50 : nc_list_elem = talloc_zero(mem_ctx, struct ncList);
437 50 : W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
438 50 : nc_list_elem->dn = ldb_dn_new(mem_ctx, samdb, nc_str);
439 50 : W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
440 50 : DLIST_ADD(nc_list, nc_list_elem);
441 : }
442 : }
443 : }
444 :
445 10 : *master_nc_list = nc_list;
446 10 : return WERR_OK;
447 : }
448 :
449 : /*
450 : Fill 'nc_list' with the ncs list. (MS-DRSR 4.1.13.3)
451 : if the object dn is specified, fill 'nc_list' only with this dn
452 : otherwise, fill 'nc_list' with all master ncs hosted by this server
453 : */
454 10 : static WERROR get_ncs_list(TALLOC_CTX *mem_ctx,
455 : struct ldb_context *samdb,
456 : struct kccsrv_service *service,
457 : const char *object_dn_str,
458 : struct ncList **nc_list)
459 : {
460 0 : WERROR status;
461 0 : struct ncList *nc_list_elem;
462 0 : struct ldb_dn *nc_dn;
463 :
464 10 : if (object_dn_str != NULL) {
465 : /* ncs := { object_dn } */
466 0 : *nc_list = NULL;
467 0 : nc_dn = ldb_dn_new(mem_ctx, samdb, object_dn_str);
468 0 : nc_list_elem = talloc_zero(mem_ctx, struct ncList);
469 0 : W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
470 0 : nc_list_elem->dn = nc_dn;
471 0 : DLIST_ADD_END(*nc_list, nc_list_elem);
472 : } else {
473 : /* ncs := getNCs() from ldb database.
474 : * getNCs() must return an array containing
475 : * the DSNames of all NCs hosted by this
476 : * server.
477 : */
478 10 : char *ntds_guid_str = GUID_string(mem_ctx, &service->ntds_guid);
479 10 : W_ERROR_HAVE_NO_MEMORY(ntds_guid_str);
480 10 : status = get_master_ncs(mem_ctx, samdb, ntds_guid_str, nc_list);
481 10 : W_ERROR_NOT_OK_RETURN(status);
482 : }
483 :
484 10 : return WERR_OK;
485 : }
486 :
487 : /*
488 : Copy the fields from 'reps1' to 'reps2', leaving zeroed the fields on
489 : 'reps2' that aren't available on 'reps1'.
490 : */
491 40 : static WERROR copy_repsfrom_1_to_2(TALLOC_CTX *mem_ctx,
492 : struct repsFromTo2 **reps2,
493 : struct repsFromTo1 *reps1)
494 : {
495 0 : struct repsFromTo2* reps;
496 :
497 40 : reps = talloc_zero(mem_ctx, struct repsFromTo2);
498 40 : W_ERROR_HAVE_NO_MEMORY(reps);
499 :
500 40 : reps->blobsize = reps1->blobsize;
501 40 : reps->consecutive_sync_failures = reps1->consecutive_sync_failures;
502 40 : reps->last_attempt = reps1->last_attempt;
503 40 : reps->last_success = reps1->last_success;
504 40 : reps->result_last_attempt = reps1->result_last_attempt;
505 40 : reps->other_info = talloc_zero(mem_ctx, struct repsFromTo2OtherInfo);
506 40 : W_ERROR_HAVE_NO_MEMORY(reps->other_info);
507 40 : reps->other_info->dns_name1 = reps1->other_info->dns_name;
508 40 : reps->replica_flags = reps1->replica_flags;
509 40 : memcpy(reps->schedule, reps1->schedule, sizeof(reps1->schedule));
510 40 : reps->reserved = reps1->reserved;
511 40 : reps->highwatermark = reps1->highwatermark;
512 40 : reps->source_dsa_obj_guid = reps1->source_dsa_obj_guid;
513 40 : reps->source_dsa_invocation_id = reps1->source_dsa_invocation_id;
514 40 : reps->transport_guid = reps1->transport_guid;
515 :
516 40 : *reps2 = reps;
517 40 : return WERR_OK;
518 : }
519 :
520 25 : static WERROR fill_neighbor_from_repsFrom(TALLOC_CTX *mem_ctx,
521 : struct ldb_context *samdb,
522 : struct ldb_dn *nc_dn,
523 : struct drsuapi_DsReplicaNeighbour *neigh,
524 : struct repsFromTo2 *reps_from)
525 : {
526 0 : struct ldb_dn *source_dsa_dn;
527 0 : int ret;
528 25 : struct ldb_dn *transport_obj_dn = NULL;
529 :
530 25 : neigh->source_dsa_address = reps_from->other_info->dns_name1;
531 25 : neigh->replica_flags = reps_from->replica_flags;
532 25 : neigh->last_attempt = reps_from->last_attempt;
533 25 : neigh->source_dsa_obj_guid = reps_from->source_dsa_obj_guid;
534 :
535 25 : ret = dsdb_find_dn_by_guid(samdb, mem_ctx, &reps_from->source_dsa_obj_guid,
536 : DSDB_SEARCH_SHOW_RECYCLED,
537 : &source_dsa_dn);
538 :
539 25 : if (ret != LDB_SUCCESS) {
540 0 : DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
541 : GUID_string(mem_ctx, &reps_from->source_dsa_obj_guid)));
542 0 : return WERR_DS_DRA_INTERNAL_ERROR;
543 : }
544 :
545 25 : neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
546 25 : neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
547 :
548 25 : if (dsdb_find_guid_by_dn(samdb, nc_dn,
549 : &neigh->naming_context_obj_guid)
550 : != LDB_SUCCESS) {
551 0 : return WERR_DS_DRA_INTERNAL_ERROR;
552 : }
553 :
554 25 : if (!GUID_all_zero(&reps_from->transport_guid)) {
555 0 : ret = dsdb_find_dn_by_guid(samdb, mem_ctx, &reps_from->transport_guid,
556 : DSDB_SEARCH_SHOW_RECYCLED,
557 : &transport_obj_dn);
558 0 : if (ret != LDB_SUCCESS) {
559 0 : return WERR_DS_DRA_INTERNAL_ERROR;
560 : }
561 : }
562 :
563 25 : neigh->transport_obj_dn = ldb_dn_get_linearized(transport_obj_dn);
564 25 : neigh->source_dsa_invocation_id = reps_from->source_dsa_invocation_id;
565 25 : neigh->transport_obj_guid = reps_from->transport_guid;
566 25 : neigh->highest_usn = reps_from->highwatermark.highest_usn;
567 25 : neigh->tmp_highest_usn = reps_from->highwatermark.tmp_highest_usn;
568 25 : neigh->last_success = reps_from->last_success;
569 25 : neigh->result_last_attempt = reps_from->result_last_attempt;
570 25 : neigh->consecutive_sync_failures = reps_from->consecutive_sync_failures;
571 25 : neigh->reserved = 0; /* Unused. MUST be 0. */
572 :
573 25 : return WERR_OK;
574 : }
575 :
576 : /*
577 : Get the inbound neighbours of this DC
578 : See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
579 : */
580 5 : static WERROR kccdrs_replica_get_info_neighbours(TALLOC_CTX *mem_ctx,
581 : struct kccsrv_service *service,
582 : struct ldb_context *samdb,
583 : struct drsuapi_DsReplicaGetInfo *r,
584 : union drsuapi_DsReplicaInfo *reply,
585 : uint32_t base_index,
586 : struct GUID req_src_dsa_guid,
587 : const char *object_dn_str)
588 : {
589 0 : WERROR status;
590 0 : uint32_t i, j;
591 5 : struct ldb_dn *nc_dn = NULL;
592 5 : struct ncList *p_nc_list = NULL;
593 5 : struct repsFromToBlob *reps_from_blob = NULL;
594 5 : struct repsFromTo2 *reps_from = NULL;
595 0 : uint32_t c_reps_from;
596 0 : uint32_t i_rep;
597 5 : struct ncList *nc_list = NULL;
598 :
599 5 : status = get_ncs_list(mem_ctx, samdb, service, object_dn_str, &nc_list);
600 5 : W_ERROR_NOT_OK_RETURN(status);
601 :
602 5 : i = j = 0;
603 :
604 5 : reply->neighbours = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbourCtr);
605 5 : W_ERROR_HAVE_NO_MEMORY(reply->neighbours);
606 5 : reply->neighbours->reserved = 0;
607 5 : reply->neighbours->count = 0;
608 :
609 : /* foreach nc in ncs */
610 30 : for (p_nc_list = nc_list; p_nc_list != NULL; p_nc_list = p_nc_list->next) {
611 :
612 25 : nc_dn = p_nc_list->dn;
613 :
614 : /* load the nc's repsFromTo blob */
615 25 : status = dsdb_loadreps(samdb, mem_ctx, nc_dn, "repsFrom",
616 : &reps_from_blob, &c_reps_from);
617 25 : W_ERROR_NOT_OK_RETURN(status);
618 :
619 : /* foreach r in nc!repsFrom */
620 50 : for (i_rep = 0; i_rep < c_reps_from; i_rep++) {
621 :
622 : /* put all info on reps_from */
623 25 : if (reps_from_blob[i_rep].version == 1) {
624 25 : status = copy_repsfrom_1_to_2(mem_ctx, &reps_from,
625 25 : &reps_from_blob[i_rep].ctr.ctr1);
626 25 : W_ERROR_NOT_OK_RETURN(status);
627 : } else { /* reps_from->version == 2 */
628 0 : reps_from = &reps_from_blob[i_rep].ctr.ctr2;
629 : }
630 :
631 25 : if (GUID_all_zero(&req_src_dsa_guid) ||
632 0 : GUID_equal(&req_src_dsa_guid,
633 0 : &reps_from->source_dsa_obj_guid)) {
634 :
635 25 : if (i >= base_index) {
636 0 : struct drsuapi_DsReplicaNeighbour neigh;
637 25 : ZERO_STRUCT(neigh);
638 25 : status = fill_neighbor_from_repsFrom(mem_ctx, samdb,
639 : nc_dn, &neigh,
640 : reps_from);
641 25 : W_ERROR_NOT_OK_RETURN(status);
642 :
643 : /* append the neighbour to the neighbours array */
644 25 : reply->neighbours->array = talloc_realloc(mem_ctx,
645 : reply->neighbours->array,
646 : struct drsuapi_DsReplicaNeighbour,
647 : reply->neighbours->count + 1);
648 25 : reply->neighbours->array[reply->neighbours->count] = neigh;
649 25 : reply->neighbours->count++;
650 25 : j++;
651 : }
652 :
653 25 : i++;
654 : }
655 : }
656 : }
657 :
658 5 : return WERR_OK;
659 : }
660 :
661 15 : static WERROR fill_neighbor_from_repsTo(TALLOC_CTX *mem_ctx,
662 : struct ldb_context *samdb, struct ldb_dn *nc_dn,
663 : struct drsuapi_DsReplicaNeighbour *neigh,
664 : struct repsFromTo2 *reps_to)
665 : {
666 0 : int ret;
667 0 : struct ldb_dn *source_dsa_dn;
668 :
669 15 : neigh->source_dsa_address = reps_to->other_info->dns_name1;
670 15 : neigh->replica_flags = reps_to->replica_flags;
671 15 : neigh->last_attempt = reps_to->last_attempt;
672 15 : neigh->source_dsa_obj_guid = reps_to->source_dsa_obj_guid;
673 :
674 15 : ret = dsdb_find_dn_by_guid(samdb, mem_ctx,
675 15 : &reps_to->source_dsa_obj_guid,
676 : DSDB_SEARCH_SHOW_RECYCLED,
677 : &source_dsa_dn);
678 15 : if (ret != LDB_SUCCESS) {
679 0 : DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
680 : GUID_string(mem_ctx, &reps_to->source_dsa_obj_guid)));
681 0 : return WERR_DS_DRA_INTERNAL_ERROR;
682 : }
683 :
684 15 : neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
685 15 : neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
686 :
687 15 : ret = dsdb_find_guid_by_dn(samdb, nc_dn,
688 : &neigh->naming_context_obj_guid);
689 15 : if (ret != LDB_SUCCESS) {
690 0 : DEBUG(0,(__location__ ": Failed to find GUID for DN %s\n",
691 : ldb_dn_get_linearized(nc_dn)));
692 0 : return WERR_DS_DRA_INTERNAL_ERROR;
693 : }
694 :
695 15 : neigh->last_success = reps_to->last_success;
696 15 : neigh->result_last_attempt = reps_to->result_last_attempt;
697 15 : neigh->consecutive_sync_failures = reps_to->consecutive_sync_failures;
698 15 : return WERR_OK;
699 : }
700 :
701 : /*
702 : Get the outbound neighbours of this DC
703 : See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_REPSTO
704 : */
705 5 : static WERROR kccdrs_replica_get_info_repsto(TALLOC_CTX *mem_ctx,
706 : struct kccsrv_service *service,
707 : struct ldb_context *samdb,
708 : struct drsuapi_DsReplicaGetInfo *r,
709 : union drsuapi_DsReplicaInfo *reply,
710 : uint32_t base_index,
711 : struct GUID req_src_dsa_guid,
712 : const char *object_dn_str)
713 : {
714 0 : WERROR status;
715 0 : uint32_t i, j;
716 5 : struct ncList *p_nc_list = NULL;
717 5 : struct ldb_dn *nc_dn = NULL;
718 0 : struct repsFromToBlob *reps_to_blob;
719 0 : struct repsFromTo2 *reps_to;
720 0 : uint32_t c_reps_to;
721 0 : uint32_t i_rep;
722 5 : struct ncList *nc_list = NULL;
723 :
724 5 : status = get_ncs_list(mem_ctx, samdb, service, object_dn_str, &nc_list);
725 5 : W_ERROR_NOT_OK_RETURN(status);
726 :
727 5 : i = j = 0;
728 :
729 5 : reply->repsto = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbourCtr);
730 5 : W_ERROR_HAVE_NO_MEMORY(reply->repsto);
731 5 : reply->repsto->reserved = 0;
732 5 : reply->repsto->count = 0;
733 :
734 : /* foreach nc in ncs */
735 30 : for (p_nc_list = nc_list; p_nc_list != NULL; p_nc_list = p_nc_list->next) {
736 :
737 25 : nc_dn = p_nc_list->dn;
738 :
739 25 : status = dsdb_loadreps(samdb, mem_ctx, nc_dn, "repsTo",
740 : &reps_to_blob, &c_reps_to);
741 25 : W_ERROR_NOT_OK_RETURN(status);
742 :
743 : /* foreach r in nc!repsTo */
744 40 : for (i_rep = 0; i_rep < c_reps_to; i_rep++) {
745 0 : struct drsuapi_DsReplicaNeighbour neigh;
746 15 : ZERO_STRUCT(neigh);
747 :
748 : /* put all info on reps_to */
749 15 : if (reps_to_blob[i_rep].version == 1) {
750 15 : status = copy_repsfrom_1_to_2(mem_ctx,
751 : &reps_to,
752 15 : &reps_to_blob[i_rep].ctr.ctr1);
753 15 : W_ERROR_NOT_OK_RETURN(status);
754 : } else { /* reps_to->version == 2 */
755 0 : reps_to = &reps_to_blob[i_rep].ctr.ctr2;
756 : }
757 :
758 15 : if (i >= base_index) {
759 15 : status = fill_neighbor_from_repsTo(mem_ctx,
760 : samdb, nc_dn,
761 : &neigh, reps_to);
762 15 : W_ERROR_NOT_OK_RETURN(status);
763 :
764 : /* append the neighbour to the neighbours array */
765 15 : reply->repsto->array = talloc_realloc(mem_ctx,
766 : reply->repsto->array,
767 : struct drsuapi_DsReplicaNeighbour,
768 : reply->repsto->count + 1);
769 15 : reply->repsto->array[reply->repsto->count++] = neigh;
770 15 : j++;
771 : }
772 15 : i++;
773 : }
774 : }
775 :
776 5 : return WERR_OK;
777 : }
778 :
779 10 : NTSTATUS kccdrs_replica_get_info(struct irpc_message *msg,
780 : struct drsuapi_DsReplicaGetInfo *req)
781 : {
782 0 : WERROR status;
783 0 : struct drsuapi_DsReplicaGetInfoRequest1 *req1;
784 0 : struct drsuapi_DsReplicaGetInfoRequest2 *req2;
785 0 : uint32_t base_index;
786 0 : union drsuapi_DsReplicaInfo *reply;
787 0 : struct GUID req_src_dsa_guid;
788 10 : const char *object_dn_str = NULL;
789 0 : struct kccsrv_service *service;
790 0 : struct ldb_context *samdb;
791 0 : TALLOC_CTX *mem_ctx;
792 0 : enum drsuapi_DsReplicaInfoType info_type;
793 :
794 10 : service = talloc_get_type(msg->private_data, struct kccsrv_service);
795 10 : samdb = service->samdb;
796 10 : mem_ctx = talloc_new(msg);
797 10 : NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
798 :
799 : #if 0
800 : NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo, req);
801 : #endif
802 :
803 : /* check request version */
804 10 : if (req->in.level != DRSUAPI_DS_REPLICA_GET_INFO &&
805 0 : req->in.level != DRSUAPI_DS_REPLICA_GET_INFO2)
806 : {
807 0 : DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo level %u\n",
808 : req->in.level));
809 0 : status = WERR_REVISION_MISMATCH;
810 0 : goto done;
811 : }
812 :
813 10 : if (req->in.level == DRSUAPI_DS_REPLICA_GET_INFO) {
814 10 : req1 = &req->in.req->req1;
815 10 : base_index = 0;
816 10 : info_type = req1->info_type;
817 10 : object_dn_str = req1->object_dn;
818 10 : req_src_dsa_guid = req1->source_dsa_guid;
819 : } else { /* r->in.level == DRSUAPI_DS_REPLICA_GET_INFO2 */
820 0 : req2 = &req->in.req->req2;
821 0 : if (req2->enumeration_context == 0xffffffff) {
822 : /* no more data is available */
823 0 : status = WERR_NO_MORE_ITEMS; /* on MS-DRSR it is ERROR_NO_MORE_ITEMS */
824 0 : goto done;
825 : }
826 :
827 0 : base_index = req2->enumeration_context;
828 0 : info_type = req2->info_type;
829 0 : object_dn_str = req2->object_dn;
830 0 : req_src_dsa_guid = req2->source_dsa_guid;
831 : }
832 :
833 10 : reply = req->out.info;
834 10 : *req->out.info_type = info_type;
835 :
836 : /* Based on the infoType requested, retrieve the corresponding
837 : * information and construct the response message */
838 10 : switch (info_type) {
839 :
840 5 : case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
841 5 : status = kccdrs_replica_get_info_neighbours(mem_ctx, service, samdb, req,
842 : reply, base_index, req_src_dsa_guid,
843 : object_dn_str);
844 5 : break;
845 5 : case DRSUAPI_DS_REPLICA_INFO_REPSTO:
846 5 : status = kccdrs_replica_get_info_repsto(mem_ctx, service, samdb, req,
847 : reply, base_index, req_src_dsa_guid,
848 : object_dn_str);
849 5 : break;
850 0 : case DRSUAPI_DS_REPLICA_INFO_CURSORS: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_FOR_NC */
851 0 : status = kccdrs_replica_get_info_cursors(mem_ctx, samdb, req, reply,
852 : ldb_dn_new(mem_ctx, samdb, object_dn_str));
853 0 : break;
854 0 : case DRSUAPI_DS_REPLICA_INFO_CURSORS2: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_2_FOR_NC */
855 0 : status = kccdrs_replica_get_info_cursors2(mem_ctx, samdb, req, reply,
856 : ldb_dn_new(mem_ctx, samdb, object_dn_str));
857 0 : break;
858 0 : case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS:
859 0 : status = kccdrs_replica_get_info_pending_ops(mem_ctx, samdb, req, reply,
860 : ldb_dn_new(mem_ctx, samdb, object_dn_str));
861 0 : break;
862 0 : case DRSUAPI_DS_REPLICA_INFO_CURSORS3: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
863 0 : status = WERR_NOT_SUPPORTED;
864 0 : break;
865 0 : case DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1: /* On MS-DRSR it is DS_REPL_INFO_UPTODATE_VECTOR_V1 */
866 0 : status = WERR_NOT_SUPPORTED;
867 0 : break;
868 0 : case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
869 : /*
870 : * It should be too complicated to filter the metadata2 to remove the additional data
871 : * as metadata2 is a superset of metadata
872 : */
873 0 : status = WERR_NOT_SUPPORTED;
874 0 : break;
875 0 : case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
876 0 : status = kccdrs_replica_get_info_obj_metadata2(mem_ctx, samdb, req, reply,
877 : ldb_dn_new(mem_ctx, samdb, object_dn_str), base_index);
878 0 : break;
879 0 : case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_ATTR_VALUE */
880 0 : status = WERR_NOT_SUPPORTED;
881 0 : break;
882 0 : case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2: /* On MS-DRSR it is DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE */
883 0 : status = WERR_NOT_SUPPORTED;
884 0 : break;
885 0 : case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES: /* On MS-DRSR it is DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES */
886 0 : status = WERR_NOT_SUPPORTED;
887 0 : break;
888 0 : case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES: /* On MS-DRSR it is DS_REPL_INFO_KCC_LINK_FAILURES */
889 0 : status = WERR_NOT_SUPPORTED;
890 0 : break;
891 0 : case DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
892 0 : status = WERR_NOT_SUPPORTED;
893 0 : break;
894 0 : case DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS: /* On MS-DRSR it is DS_REPL_INFO_SERVER_OUTGOING_CALLS */
895 0 : status = WERR_NOT_SUPPORTED;
896 0 : break;
897 0 : default:
898 0 : DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo info_type %u\n",
899 : info_type));
900 0 : status = WERR_INVALID_LEVEL;
901 0 : break;
902 : }
903 :
904 10 : done:
905 : /* put the status on the result field of the reply */
906 10 : req->out.result = status;
907 : #if 0
908 : NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo, req);
909 : #endif
910 10 : return NT_STATUS_OK;
911 : }
|