2 Unix SMB/CIFS implementation.
4 DRS Replica Information
6 Copyright (C) Erick Nogueira do Nascimento 2009-2010
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.
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.
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/>.
24 #include "dsdb/samdb/samdb.h"
25 #include "dsdb/common/proto.h"
26 #include "auth/auth.h"
27 #include "smbd/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"
41 get the stamp values for the linked attribute 'linked_attr_name' of the object 'dn'
43 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
)
47 struct ldb_result
*res
;
50 struct ldb_dn
*attr_ext_dn
;
53 attrs
[0] = linked_attr_name
;
56 ret
= dsdb_search_dn(samdb
, mem_ctx
, &res
, dn
, attrs
,
57 DSDB_SEARCH_SHOW_EXTENDED_DN
| DSDB_SEARCH_REVEAL_INTERNALS
);
58 if (ret
!= LDB_SUCCESS
) {
59 DEBUG(0, (__location__
": Failed search for attribute %s on %s",
60 linked_attr_name
, ldb_dn_get_linearized(dn
)));
61 return WERR_INTERNAL_ERROR
;
64 attr_ext_dn
= ldb_msg_find_attr_as_dn(samdb
, mem_ctx
, res
->msgs
[0], linked_attr_name
);
66 DEBUG(0, (__location__
": Failed search for attribute %s on %s",
67 linked_attr_name
, ldb_dn_get_linearized(dn
)));
68 return WERR_INTERNAL_ERROR
;
71 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)));
74 ntstatus
= dsdb_get_extended_dn_uint32(attr_ext_dn
, attr_version
, "RMD_VERSION");
75 if (!NT_STATUS_IS_OK(ntstatus
)) {
76 DEBUG(0, (__location__
": Could not extract component %s from dn \"%s\"",
77 "RMD_VERSION", ldb_dn_get_extended_linearized(mem_ctx
, attr_ext_dn
, 1)));
78 return WERR_INTERNAL_ERROR
;
81 ntstatus
= dsdb_get_extended_dn_nttime(attr_ext_dn
, attr_change_time
, "RMD_CHANGETIME");
82 if (!NT_STATUS_IS_OK(ntstatus
)) {
83 DEBUG(0, (__location__
": Could not extract component %s from dn \"%s\"",
84 "RMD_CHANGETIME", ldb_dn_get_extended_linearized(mem_ctx
, attr_ext_dn
, 1)));
85 return WERR_INTERNAL_ERROR
;
88 ntstatus
= dsdb_get_extended_dn_uint32(attr_ext_dn
, attr_version
, "RMD_ORIGINATING_USN");
89 if (!NT_STATUS_IS_OK(ntstatus
)) {
90 DEBUG(0, (__location__
": Could not extract component %s from dn \"%s\"",
91 "RMD_ORIGINATING_USN", ldb_dn_get_extended_linearized(mem_ctx
, attr_ext_dn
, 1)));
92 return WERR_INTERNAL_ERROR
;
98 static WERROR
get_repl_prop_metadata_ctr(TALLOC_CTX
*mem_ctx
,
99 struct ldb_context
*samdb
,
101 struct replPropertyMetaDataBlob
*obj_metadata_ctr
)
104 struct ldb_result
*res
;
105 const char *attrs
[] = { "replPropertyMetaData", NULL
};
106 const struct ldb_val
*omd_value
;
107 enum ndr_err_code ndr_err
;
109 ret
= ldb_search(samdb
, mem_ctx
, &res
, dn
, LDB_SCOPE_BASE
, attrs
, NULL
);
110 if (ret
!= LDB_SUCCESS
|| res
->count
!= 1) {
111 DEBUG(0, (__location__
": Failed search for replPropertyMetaData attribute on %s",
112 ldb_dn_get_linearized(dn
)));
113 return WERR_INTERNAL_ERROR
;
116 omd_value
= ldb_msg_find_ldb_val(res
->msgs
[0], "replPropertyMetaData");
118 DEBUG(0,(__location__
": Object %s does not have a replPropertyMetaData attribute\n",
119 ldb_dn_get_linearized(dn
)));
121 return WERR_INTERNAL_ERROR
;
124 ndr_err
= ndr_pull_struct_blob(omd_value
, mem_ctx
,
126 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
127 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
128 DEBUG(0,(__location__
": Failed to parse replPropertyMetaData for %s\n",
129 ldb_dn_get_linearized(dn
)));
131 return WERR_INTERNAL_ERROR
;
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'
143 static WERROR
get_dn_from_invocation_id(TALLOC_CTX
*mem_ctx
,
144 struct ldb_context
*samdb
,
145 struct GUID
*invocation_id
,
148 char *invocation_id_str
;
149 const char *attrs_invocation
[] = { NULL
};
150 struct ldb_message
*msg
;
153 invocation_id_str
= GUID_string(mem_ctx
, invocation_id
);
154 W_ERROR_HAVE_NO_MEMORY(invocation_id_str
);
156 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 if (ret
!= LDB_SUCCESS
) {
159 DEBUG(0, (__location__
": Failed search for the object DN under %s whose invocationId is %s",
160 invocation_id_str
, ldb_dn_get_linearized(ldb_get_config_basedn(samdb
))));
161 talloc_free(invocation_id_str
);
162 return WERR_INTERNAL_ERROR
;
165 *dn_str
= ldb_dn_alloc_linearized(mem_ctx
, msg
->dn
);
166 talloc_free(invocation_id_str
);
171 get metadata version 2 info for a specified object DN
173 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
,
181 struct replPropertyMetaDataBlob omd_ctr
;
182 struct replPropertyMetaData1
*attr
;
183 struct drsuapi_DsReplicaObjMetaData2Ctr
*metadata2
;
184 const struct dsdb_schema
*schema
;
188 DEBUG(0, ("kccdrs_replica_get_info_obj_metadata2() called\n"));
191 return WERR_INVALID_PARAMETER
;
194 if (!ldb_dn_validate(dn
)) {
195 return WERR_DS_DRA_BAD_DN
;
198 status
= get_repl_prop_metadata_ctr(mem_ctx
, samdb
, dn
, &omd_ctr
);
199 W_ERROR_NOT_OK_RETURN(status
);
201 schema
= dsdb_get_schema(samdb
, reply
);
203 DEBUG(0,(__location__
": Failed to get the schema\n"));
204 return WERR_INTERNAL_ERROR
;
207 reply
->objmetadata2
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaObjMetaData2Ctr
);
208 W_ERROR_HAVE_NO_MEMORY(reply
->objmetadata2
);
209 metadata2
= reply
->objmetadata2
;
210 metadata2
->enumeration_context
= 0;
212 /* For each replicated attribute of the object */
213 for (i
= 0, j
= 0; i
< omd_ctr
.ctr
.ctr1
.count
; i
++) {
214 const struct dsdb_attribute
*schema_attr
;
215 uint32_t attr_version
;
216 NTTIME attr_change_time
;
217 uint32_t attr_originating_usn
;
221 s := AttrStamp(object, attr)
223 /* get a reference to the attribute on 'omd_ctr' */
224 attr
= &omd_ctr
.ctr
.ctr1
.array
[j
];
226 schema_attr
= dsdb_attribute_by_attributeID_id(schema
, attr
->attid
);
228 DEBUG(0, ("attribute_id = %d, attribute_name: %s\n", attr
->attid
, schema_attr
->lDAPDisplayName
));
231 if (attr in Link Attributes of object and
232 dwInVersion = 2 and DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS in msgIn.ulFlags)
235 schema_attr
->linkID
!= 0 && /* Checks if attribute is a linked attribute */
236 (schema_attr
->linkID
% 2) == 0 && /* is it a forward link? only forward links have the LinkValueStamp */
238 (r
->in
.req
->req2
.flags
& DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
)) /* on MS-DRSR it is DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS */
241 ls := LinkValueStamp of the most recent
242 value change in object!attr
244 status
= get_linked_attribute_value_stamp(mem_ctx
, samdb
, dn
, schema_attr
->lDAPDisplayName
,
245 &attr_version
, &attr_change_time
, &attr_originating_usn
);
246 W_ERROR_NOT_OK_RETURN(status
);
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
254 /* if (ls is more recent than s (based on order in which the change was applied on server)) then */
255 if (attr_change_time
> attr
->originating_change_time
) {
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
263 attr
->version
= attr_version
;
264 attr
->originating_change_time
= attr_change_time
;
265 attr
->originating_invocation_id
= GUID_zero();
266 attr
->originating_usn
= attr_originating_usn
;
270 if (i
< base_index
) {
274 metadata2
->array
= talloc_realloc(mem_ctx
, metadata2
->array
,
275 struct drsuapi_DsReplicaObjMetaData2
, j
+ 1);
276 W_ERROR_HAVE_NO_MEMORY(metadata2
->array
);
277 metadata2
->array
[j
].attribute_name
= schema_attr
->lDAPDisplayName
;
278 metadata2
->array
[j
].local_usn
= attr
->local_usn
;
279 metadata2
->array
[j
].originating_change_time
= attr
->originating_change_time
;
280 metadata2
->array
[j
].originating_invocation_id
= attr
->originating_invocation_id
;
281 metadata2
->array
[j
].originating_usn
= attr
->originating_usn
;
282 metadata2
->array
[j
].version
= attr
->version
;
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
289 status
= get_dn_from_invocation_id(mem_ctx
, samdb
,
290 &attr
->originating_invocation_id
,
291 &metadata2
->array
[j
].originating_dsa_dn
);
292 W_ERROR_NOT_OK_RETURN(status
);
294 metadata2
->count
= j
;
302 get cursors info for a specified DN
304 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
,
312 if (!ldb_dn_validate(dn
)) {
313 return WERR_INVALID_PARAMETER
;
315 reply
->cursors
= talloc(mem_ctx
, struct drsuapi_DsReplicaCursorCtr
);
316 W_ERROR_HAVE_NO_MEMORY(reply
->cursors
);
318 reply
->cursors
->reserved
= 0;
320 ret
= dsdb_load_udv_v1(samdb
, dn
, reply
->cursors
, &reply
->cursors
->array
, &reply
->cursors
->count
);
321 if (ret
!= LDB_SUCCESS
) {
322 return WERR_DS_DRA_BAD_NC
;
328 get cursors2 info for a specified DN
330 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
,
338 if (!ldb_dn_validate(dn
)) {
339 return WERR_INVALID_PARAMETER
;
341 reply
->cursors2
= talloc(mem_ctx
, struct drsuapi_DsReplicaCursor2Ctr
);
342 W_ERROR_HAVE_NO_MEMORY(reply
->cursors2
);
344 ret
= dsdb_load_udv_v2(samdb
, dn
, reply
->cursors2
, &reply
->cursors2
->array
, &reply
->cursors2
->count
);
345 if (ret
!= LDB_SUCCESS
) {
346 return WERR_DS_DRA_BAD_NC
;
349 reply
->cursors2
->enumeration_context
= reply
->cursors2
->count
;
354 get pending ops info for a specified DN
356 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
,
362 struct timeval now
= timeval_current();
364 if (!ldb_dn_validate(dn
)) {
365 return WERR_INVALID_PARAMETER
;
367 reply
->pendingops
= talloc(mem_ctx
, struct drsuapi_DsReplicaOpCtr
);
368 W_ERROR_HAVE_NO_MEMORY(reply
->pendingops
);
370 /* claim no pending ops for now */
371 reply
->pendingops
->time
= timeval_to_nttime(&now
);
372 reply
->pendingops
->count
= 0;
373 reply
->pendingops
->array
= NULL
;
380 struct ncList
*prev
, *next
;
384 Fill 'master_nc_list' with the master ncs hosted by this server
386 static WERROR
get_master_ncs(TALLOC_CTX
*mem_ctx
, struct ldb_context
*samdb
,
387 const char *ntds_guid_str
, struct ncList
**master_nc_list
)
389 const char *post_2003_attrs
[] = { "msDS-hasMasterNCs", "hasPartialReplicaNCs", NULL
};
390 const char *pre_2003_attrs
[] = { "hasMasterNCs", "hasPartialReplicaNCs", NULL
};
391 const char **attrs
= post_2003_attrs
;
392 struct ldb_result
*res
;
393 struct ncList
*nc_list
= NULL
;
394 struct ncList
*nc_list_elem
;
398 int is_level_post_2003
;
400 /* In W2003 and greater, msDS-hasMasterNCs attribute lists the writable NC replicas */
401 is_level_post_2003
= 1;
402 ret
= ldb_search(samdb
, mem_ctx
, &res
, ldb_get_config_basedn(samdb
),
403 LDB_SCOPE_DEFAULT
, post_2003_attrs
, "(objectguid=%s)", ntds_guid_str
);
405 if (ret
!= LDB_SUCCESS
) {
406 DEBUG(0,(__location__
": Failed objectguid search - %s\n", ldb_errstring(samdb
)));
408 is_level_post_2003
= 0;
409 attrs
= post_2003_attrs
;
410 ret
= ldb_search(samdb
, mem_ctx
, &res
, ldb_get_config_basedn(samdb
),
411 LDB_SCOPE_DEFAULT
, pre_2003_attrs
, "(objectguid=%s)", ntds_guid_str
);
414 if (ret
!= LDB_SUCCESS
) {
415 DEBUG(0,(__location__
": Failed objectguid search - %s\n", ldb_errstring(samdb
)));
416 return WERR_INTERNAL_ERROR
;
419 if (res
->count
== 0) {
420 DEBUG(0,(__location__
": Failed: objectguid=%s not found\n", ntds_guid_str
));
421 return WERR_INTERNAL_ERROR
;
424 for (i
= 0; i
< res
->count
; i
++) {
425 struct ldb_message_element
*msg_elem
;
428 for (a
=0; attrs
[a
]; a
++) {
429 msg_elem
= ldb_msg_find_element(res
->msgs
[i
], attrs
[a
]);
430 if (!msg_elem
|| msg_elem
->num_values
== 0) {
434 for (k
= 0; k
< msg_elem
->num_values
; k
++) {
435 /* copy the string on msg_elem->values[k]->data to nc_str */
436 nc_str
= talloc_strndup(mem_ctx
, (char *)msg_elem
->values
[k
].data
, msg_elem
->values
[k
].length
);
437 W_ERROR_HAVE_NO_MEMORY(nc_str
);
439 nc_list_elem
= talloc_zero(mem_ctx
, struct ncList
);
440 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
441 nc_list_elem
->dn
= ldb_dn_new(mem_ctx
, samdb
, nc_str
);
442 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
443 DLIST_ADD(nc_list
, nc_list_elem
);
448 *master_nc_list
= nc_list
;
453 Fill 'nc_list' with the ncs list. (MS-DRSR 4.1.13.3)
454 if the object dn is specified, fill 'nc_list' only with this dn
455 otherwise, fill 'nc_list' with all master ncs hosted by this server
457 static WERROR
get_ncs_list(TALLOC_CTX
*mem_ctx
,
458 struct ldb_context
*samdb
,
459 struct kccsrv_service
*service
,
460 const char *object_dn_str
,
461 struct ncList
**nc_list
)
464 struct ncList
*nc_list_elem
;
465 struct ldb_dn
*nc_dn
;
467 if (object_dn_str
!= NULL
) {
468 /* ncs := { object_dn } */
470 nc_dn
= ldb_dn_new(mem_ctx
, samdb
, object_dn_str
);
471 nc_list_elem
= talloc_zero(mem_ctx
, struct ncList
);
472 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
473 nc_list_elem
->dn
= nc_dn
;
474 DLIST_ADD_END(*nc_list
, nc_list_elem
, struct ncList
*);
476 /* ncs := getNCs() from ldb database.
477 * getNCs() must return an array containing
478 * the DSNames of all NCs hosted by this
481 char *ntds_guid_str
= GUID_string(mem_ctx
, &service
->ntds_guid
);
482 W_ERROR_HAVE_NO_MEMORY(ntds_guid_str
);
483 status
= get_master_ncs(mem_ctx
, samdb
, ntds_guid_str
, nc_list
);
484 W_ERROR_NOT_OK_RETURN(status
);
491 Copy the fields from 'reps1' to 'reps2', leaving zeroed the fields on
492 'reps2' that aren't available on 'reps1'.
494 static WERROR
copy_repsfrom_1_to_2(TALLOC_CTX
*mem_ctx
,
495 struct repsFromTo2
**reps2
,
496 struct repsFromTo1
*reps1
)
498 struct repsFromTo2
* reps
;
500 reps
= talloc_zero(mem_ctx
, struct repsFromTo2
);
501 W_ERROR_HAVE_NO_MEMORY(reps
);
503 reps
->blobsize
= reps1
->blobsize
;
504 reps
->consecutive_sync_failures
= reps1
->consecutive_sync_failures
;
505 reps
->last_attempt
= reps1
->last_attempt
;
506 reps
->last_success
= reps1
->last_success
;
507 reps
->result_last_attempt
= reps1
->result_last_attempt
;
508 reps
->other_info
= talloc_zero(mem_ctx
, struct repsFromTo2OtherInfo
);
509 W_ERROR_HAVE_NO_MEMORY(reps
->other_info
);
510 reps
->other_info
->dns_name1
= reps1
->other_info
->dns_name
;
511 reps
->replica_flags
= reps1
->replica_flags
;
512 memcpy(reps
->schedule
, reps1
->schedule
, sizeof(reps1
->schedule
));
513 reps
->reserved
= reps1
->reserved
;
514 reps
->highwatermark
= reps1
->highwatermark
;
515 reps
->source_dsa_obj_guid
= reps1
->source_dsa_obj_guid
;
516 reps
->source_dsa_invocation_id
= reps1
->source_dsa_invocation_id
;
517 reps
->transport_guid
= reps1
->transport_guid
;
523 static WERROR
fill_neighbor_from_repsFrom(TALLOC_CTX
*mem_ctx
,
524 struct ldb_context
*samdb
,
525 struct ldb_dn
*nc_dn
,
526 struct drsuapi_DsReplicaNeighbour
*neigh
,
527 struct repsFromTo2
*reps_from
)
529 struct ldb_dn
*source_dsa_dn
;
531 struct ldb_dn
*transport_obj_dn
= NULL
;
533 neigh
->source_dsa_address
= reps_from
->other_info
->dns_name1
;
534 neigh
->replica_flags
= reps_from
->replica_flags
;
535 neigh
->last_attempt
= reps_from
->last_attempt
;
536 neigh
->source_dsa_obj_guid
= reps_from
->source_dsa_obj_guid
;
538 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, &reps_from
->source_dsa_obj_guid
,
541 if (ret
!= LDB_SUCCESS
) {
542 DEBUG(0,(__location__
": Failed to find DN for neighbor GUID %s\n",
543 GUID_string(mem_ctx
, &reps_from
->source_dsa_obj_guid
)));
544 return WERR_DS_DRA_INTERNAL_ERROR
;
547 neigh
->source_dsa_obj_dn
= ldb_dn_get_linearized(source_dsa_dn
);
548 neigh
->naming_context_dn
= ldb_dn_get_linearized(nc_dn
);
550 if (dsdb_find_guid_by_dn(samdb
, nc_dn
, &neigh
->naming_context_obj_guid
)
552 return WERR_DS_DRA_INTERNAL_ERROR
;
555 if (!GUID_all_zero(&reps_from
->transport_guid
)) {
556 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, &reps_from
->transport_guid
,
558 if (ret
!= LDB_SUCCESS
) {
559 return WERR_DS_DRA_INTERNAL_ERROR
;
563 neigh
->transport_obj_dn
= ldb_dn_get_linearized(transport_obj_dn
);
564 neigh
->source_dsa_invocation_id
= reps_from
->source_dsa_invocation_id
;
565 neigh
->transport_obj_guid
= reps_from
->transport_guid
;
566 neigh
->highest_usn
= reps_from
->highwatermark
.highest_usn
;
567 neigh
->tmp_highest_usn
= reps_from
->highwatermark
.tmp_highest_usn
;
568 neigh
->last_success
= reps_from
->last_success
;
569 neigh
->result_last_attempt
= reps_from
->result_last_attempt
;
570 neigh
->consecutive_sync_failures
= reps_from
->consecutive_sync_failures
;
571 neigh
->reserved
= 0; /* Unused. MUST be 0. */
577 Get the inbound neighbours of this DC
578 See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
580 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
,
586 struct GUID req_src_dsa_guid
,
587 const char *object_dn_str
)
591 struct ldb_dn
*nc_dn
= NULL
;
592 struct ncList
*p_nc_list
= NULL
;
593 struct repsFromToBlob
*reps_from_blob
= NULL
;
594 struct repsFromTo2
*reps_from
= NULL
;
595 uint32_t c_reps_from
;
597 struct ncList
*nc_list
= NULL
;
599 status
= get_ncs_list(mem_ctx
, samdb
, service
, object_dn_str
, &nc_list
);
600 W_ERROR_NOT_OK_RETURN(status
);
604 reply
->neighbours
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaNeighbourCtr
);
605 W_ERROR_HAVE_NO_MEMORY(reply
->neighbours
);
606 reply
->neighbours
->reserved
= 0;
607 reply
->neighbours
->count
= 0;
609 /* foreach nc in ncs */
610 for (p_nc_list
= nc_list
; p_nc_list
!= NULL
; p_nc_list
= p_nc_list
->next
) {
612 nc_dn
= p_nc_list
->dn
;
614 /* load the nc's repsFromTo blob */
615 status
= dsdb_loadreps(samdb
, mem_ctx
, nc_dn
, "repsFrom",
616 &reps_from_blob
, &c_reps_from
);
617 W_ERROR_NOT_OK_RETURN(status
);
619 /* foreach r in nc!repsFrom */
620 for (i_rep
= 0; i_rep
< c_reps_from
; i_rep
++) {
622 /* put all info on reps_from */
623 if (reps_from_blob
[i_rep
].version
== 1) {
624 status
= copy_repsfrom_1_to_2(mem_ctx
, &reps_from
,
625 &reps_from_blob
[i_rep
].ctr
.ctr1
);
626 W_ERROR_NOT_OK_RETURN(status
);
627 } else { /* reps_from->version == 2 */
628 reps_from
= &reps_from_blob
[i_rep
].ctr
.ctr2
;
631 if (GUID_all_zero(&req_src_dsa_guid
) ||
632 GUID_compare(&req_src_dsa_guid
, &reps_from
->source_dsa_obj_guid
) == 0)
635 if (i
>= base_index
) {
636 struct drsuapi_DsReplicaNeighbour neigh
;
638 status
= fill_neighbor_from_repsFrom(mem_ctx
, samdb
,
641 W_ERROR_NOT_OK_RETURN(status
);
643 /* append the neighbour to the neighbours array */
644 reply
->neighbours
->array
= talloc_realloc(mem_ctx
,
645 reply
->neighbours
->array
,
646 struct drsuapi_DsReplicaNeighbour
,
647 reply
->neighbours
->count
+ 1);
648 reply
->neighbours
->array
[reply
->neighbours
->count
] = neigh
;
649 reply
->neighbours
->count
++;
661 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
)
667 struct ldb_dn
*source_dsa_dn
;
669 neigh
->source_dsa_address
= reps_to
->other_info
->dns_name1
;
670 neigh
->replica_flags
= reps_to
->replica_flags
;
671 neigh
->last_attempt
= reps_to
->last_attempt
;
672 neigh
->source_dsa_obj_guid
= reps_to
->source_dsa_obj_guid
;
674 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, &reps_to
->source_dsa_obj_guid
, &source_dsa_dn
);
675 if (ret
!= LDB_SUCCESS
) {
676 DEBUG(0,(__location__
": Failed to find DN for neighbor GUID %s\n",
677 GUID_string(mem_ctx
, &reps_to
->source_dsa_obj_guid
)));
678 return WERR_DS_DRA_INTERNAL_ERROR
;
681 neigh
->source_dsa_obj_dn
= ldb_dn_get_linearized(source_dsa_dn
);
682 neigh
->naming_context_dn
= ldb_dn_get_linearized(nc_dn
);
684 ret
= dsdb_find_guid_by_dn(samdb
, nc_dn
,
685 &neigh
->naming_context_obj_guid
);
686 if (ret
!= LDB_SUCCESS
) {
687 DEBUG(0,(__location__
": Failed to find GUID for DN %s\n",
688 ldb_dn_get_linearized(nc_dn
)));
689 return WERR_DS_DRA_INTERNAL_ERROR
;
692 neigh
->last_success
= reps_to
->last_success
;
693 neigh
->result_last_attempt
= reps_to
->result_last_attempt
;
694 neigh
->consecutive_sync_failures
= reps_to
->consecutive_sync_failures
;
699 Get the outbound neighbours of this DC
700 See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_REPSTO
702 static WERROR
kccdrs_replica_get_info_repsto(TALLOC_CTX
*mem_ctx
,
703 struct kccsrv_service
*service
,
704 struct ldb_context
*samdb
,
705 struct drsuapi_DsReplicaGetInfo
*r
,
706 union drsuapi_DsReplicaInfo
*reply
,
708 struct GUID req_src_dsa_guid
,
709 const char *object_dn_str
)
713 struct ncList
*p_nc_list
= NULL
;
714 struct ldb_dn
*nc_dn
= NULL
;
715 struct repsFromToBlob
*reps_to_blob
;
716 struct repsFromTo2
*reps_to
;
719 struct ncList
*nc_list
= NULL
;
721 status
= get_ncs_list(mem_ctx
, samdb
, service
, object_dn_str
, &nc_list
);
722 W_ERROR_NOT_OK_RETURN(status
);
726 reply
->repsto
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaNeighbourCtr
);
727 W_ERROR_HAVE_NO_MEMORY(reply
->repsto
);
728 reply
->repsto
->reserved
= 0;
729 reply
->repsto
->count
= 0;
731 /* foreach nc in ncs */
732 for (p_nc_list
= nc_list
; p_nc_list
!= NULL
; p_nc_list
= p_nc_list
->next
) {
734 nc_dn
= p_nc_list
->dn
;
736 status
= dsdb_loadreps(samdb
, mem_ctx
, nc_dn
, "repsTo",
737 &reps_to_blob
, &c_reps_to
);
738 W_ERROR_NOT_OK_RETURN(status
);
740 /* foreach r in nc!repsTo */
741 for (i_rep
= 0; i_rep
< c_reps_to
; i_rep
++) {
742 struct drsuapi_DsReplicaNeighbour neigh
;
745 /* put all info on reps_to */
746 if (reps_to_blob
[i_rep
].version
== 1) {
747 status
= copy_repsfrom_1_to_2(mem_ctx
,
749 &reps_to_blob
[i_rep
].ctr
.ctr1
);
750 W_ERROR_NOT_OK_RETURN(status
);
751 } else { /* reps_to->version == 2 */
752 reps_to
= &reps_to_blob
[i_rep
].ctr
.ctr2
;
755 if (i
>= base_index
) {
756 status
= fill_neighbor_from_repsTo(mem_ctx
,
759 W_ERROR_NOT_OK_RETURN(status
);
761 /* append the neighbour to the neighbours array */
762 reply
->repsto
->array
= talloc_realloc(mem_ctx
,
763 reply
->repsto
->array
,
764 struct drsuapi_DsReplicaNeighbour
,
765 reply
->repsto
->count
+ 1);
766 reply
->repsto
->array
[reply
->repsto
->count
++] = neigh
;
776 NTSTATUS
kccdrs_replica_get_info(struct irpc_message
*msg
,
777 struct drsuapi_DsReplicaGetInfo
*req
)
780 struct drsuapi_DsReplicaGetInfoRequest1
*req1
;
781 struct drsuapi_DsReplicaGetInfoRequest2
*req2
;
783 union drsuapi_DsReplicaInfo
*reply
;
784 struct GUID req_src_dsa_guid
;
785 const char *object_dn_str
= NULL
;
786 struct kccsrv_service
*service
;
787 struct ldb_context
*samdb
;
789 enum drsuapi_DsReplicaInfoType info_type
;
791 const char *attribute_name
, *value_dn
;
793 service
= talloc_get_type(msg
->private_data
, struct kccsrv_service
);
794 samdb
= service
->samdb
;
795 mem_ctx
= talloc_new(msg
);
796 NT_STATUS_HAVE_NO_MEMORY(mem_ctx
);
799 NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo
, req
);
802 /* check request version */
803 if (req
->in
.level
!= DRSUAPI_DS_REPLICA_GET_INFO
&&
804 req
->in
.level
!= DRSUAPI_DS_REPLICA_GET_INFO2
)
806 DEBUG(1,(__location__
": Unsupported DsReplicaGetInfo level %u\n",
808 status
= WERR_REVISION_MISMATCH
;
812 if (req
->in
.level
== DRSUAPI_DS_REPLICA_GET_INFO
) {
813 req1
= &req
->in
.req
->req1
;
815 info_type
= req1
->info_type
;
816 object_dn_str
= req1
->object_dn
;
817 req_src_dsa_guid
= req1
->source_dsa_guid
;
818 } else { /* r->in.level == DRSUAPI_DS_REPLICA_GET_INFO2 */
819 req2
= &req
->in
.req
->req2
;
820 if (req2
->enumeration_context
== 0xffffffff) {
821 /* no more data is available */
822 status
= WERR_NO_MORE_ITEMS
; /* on MS-DRSR it is ERROR_NO_MORE_ITEMS */
826 base_index
= req2
->enumeration_context
;
827 info_type
= req2
->info_type
;
828 object_dn_str
= req2
->object_dn
;
829 req_src_dsa_guid
= req2
->source_dsa_guid
;
831 attribute_name
= req2
->attribute_name
;
832 value_dn
= req2
->value_dn_str
;
835 reply
= req
->out
.info
;
836 *req
->out
.info_type
= info_type
;
838 /* Based on the infoType requested, retrieve the corresponding
839 * information and construct the response message */
842 case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS
:
843 status
= kccdrs_replica_get_info_neighbours(mem_ctx
, service
, samdb
, req
,
844 reply
, base_index
, req_src_dsa_guid
,
847 case DRSUAPI_DS_REPLICA_INFO_REPSTO
:
848 status
= kccdrs_replica_get_info_repsto(mem_ctx
, service
, samdb
, req
,
849 reply
, base_index
, req_src_dsa_guid
,
852 case DRSUAPI_DS_REPLICA_INFO_CURSORS
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_FOR_NC */
853 status
= kccdrs_replica_get_info_cursors(mem_ctx
, samdb
, req
, reply
,
854 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
856 case DRSUAPI_DS_REPLICA_INFO_CURSORS2
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_2_FOR_NC */
857 status
= kccdrs_replica_get_info_cursors2(mem_ctx
, samdb
, req
, reply
,
858 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
860 case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS
:
861 status
= kccdrs_replica_get_info_pending_ops(mem_ctx
, samdb
, req
, reply
,
862 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
864 case DRSUAPI_DS_REPLICA_INFO_CURSORS3
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
865 status
= WERR_NOT_SUPPORTED
;
867 case DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1
: /* On MS-DRSR it is DS_REPL_INFO_UPTODATE_VECTOR_V1 */
868 status
= WERR_NOT_SUPPORTED
;
870 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
872 * It should be too complicated to filter the metadata2 to remove the additional data
873 * as metadata2 is a superset of metadata
875 status
= WERR_NOT_SUPPORTED
;
877 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
878 status
= kccdrs_replica_get_info_obj_metadata2(mem_ctx
, samdb
, req
, reply
,
879 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
), base_index
);
881 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_ATTR_VALUE */
882 status
= WERR_NOT_SUPPORTED
;
884 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE */
885 status
= WERR_NOT_SUPPORTED
;
887 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES
: /* On MS-DRSR it is DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES */
888 status
= WERR_NOT_SUPPORTED
;
890 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES
: /* On MS-DRSR it is DS_REPL_INFO_KCC_LINK_FAILURES */
891 status
= WERR_NOT_SUPPORTED
;
893 case DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS
: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
894 status
= WERR_NOT_SUPPORTED
;
896 case DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS
: /* On MS-DRSR it is DS_REPL_INFO_SERVER_OUTGOING_CALLS */
897 status
= WERR_NOT_SUPPORTED
;
900 DEBUG(1,(__location__
": Unsupported DsReplicaGetInfo info_type %u\n",
902 status
= WERR_INVALID_LEVEL
;
907 /* put the status on the result field of the reply */
908 req
->out
.result
= status
;
910 NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo
, req
);