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 "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"
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\n",
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\n",
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\"\n",
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\"\n",
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\"\n",
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\n",
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\n",
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
= 0;
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 *attrs
[] = { "msDS-hasMasterNCs", "hasPartialReplicaNCs", NULL
};
390 struct ldb_result
*res
;
391 struct ncList
*nc_list
= NULL
;
392 struct ncList
*nc_list_elem
;
397 /* In W2003 and greater, msDS-hasMasterNCs attribute lists the writable NC replicas */
398 ret
= ldb_search(samdb
, mem_ctx
, &res
, ldb_get_config_basedn(samdb
),
399 LDB_SCOPE_DEFAULT
, attrs
, "(objectguid=%s)", ntds_guid_str
);
401 if (ret
!= LDB_SUCCESS
) {
402 DEBUG(0,(__location__
": Failed objectguid search - %s\n", ldb_errstring(samdb
)));
403 return WERR_INTERNAL_ERROR
;
406 if (res
->count
== 0) {
407 DEBUG(0,(__location__
": Failed: objectguid=%s not found\n", ntds_guid_str
));
408 return WERR_INTERNAL_ERROR
;
411 for (i
= 0; i
< res
->count
; i
++) {
412 struct ldb_message_element
*msg_elem
;
415 for (a
=0; attrs
[a
]; a
++) {
416 msg_elem
= ldb_msg_find_element(res
->msgs
[i
], attrs
[a
]);
417 if (!msg_elem
|| msg_elem
->num_values
== 0) {
421 for (k
= 0; k
< msg_elem
->num_values
; k
++) {
422 /* copy the string on msg_elem->values[k]->data to nc_str */
423 nc_str
= talloc_strndup(mem_ctx
, (char *)msg_elem
->values
[k
].data
, msg_elem
->values
[k
].length
);
424 W_ERROR_HAVE_NO_MEMORY(nc_str
);
426 nc_list_elem
= talloc_zero(mem_ctx
, struct ncList
);
427 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
428 nc_list_elem
->dn
= ldb_dn_new(mem_ctx
, samdb
, nc_str
);
429 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
430 DLIST_ADD(nc_list
, nc_list_elem
);
435 *master_nc_list
= nc_list
;
440 Fill 'nc_list' with the ncs list. (MS-DRSR 4.1.13.3)
441 if the object dn is specified, fill 'nc_list' only with this dn
442 otherwise, fill 'nc_list' with all master ncs hosted by this server
444 static WERROR
get_ncs_list(TALLOC_CTX
*mem_ctx
,
445 struct ldb_context
*samdb
,
446 struct kccsrv_service
*service
,
447 const char *object_dn_str
,
448 struct ncList
**nc_list
)
451 struct ncList
*nc_list_elem
;
452 struct ldb_dn
*nc_dn
;
454 if (object_dn_str
!= NULL
) {
455 /* ncs := { object_dn } */
457 nc_dn
= ldb_dn_new(mem_ctx
, samdb
, object_dn_str
);
458 nc_list_elem
= talloc_zero(mem_ctx
, struct ncList
);
459 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
460 nc_list_elem
->dn
= nc_dn
;
461 DLIST_ADD_END(*nc_list
, nc_list_elem
);
463 /* ncs := getNCs() from ldb database.
464 * getNCs() must return an array containing
465 * the DSNames of all NCs hosted by this
468 char *ntds_guid_str
= GUID_string(mem_ctx
, &service
->ntds_guid
);
469 W_ERROR_HAVE_NO_MEMORY(ntds_guid_str
);
470 status
= get_master_ncs(mem_ctx
, samdb
, ntds_guid_str
, nc_list
);
471 W_ERROR_NOT_OK_RETURN(status
);
478 Copy the fields from 'reps1' to 'reps2', leaving zeroed the fields on
479 'reps2' that aren't available on 'reps1'.
481 static WERROR
copy_repsfrom_1_to_2(TALLOC_CTX
*mem_ctx
,
482 struct repsFromTo2
**reps2
,
483 struct repsFromTo1
*reps1
)
485 struct repsFromTo2
* reps
;
487 reps
= talloc_zero(mem_ctx
, struct repsFromTo2
);
488 W_ERROR_HAVE_NO_MEMORY(reps
);
490 reps
->blobsize
= reps1
->blobsize
;
491 reps
->consecutive_sync_failures
= reps1
->consecutive_sync_failures
;
492 reps
->last_attempt
= reps1
->last_attempt
;
493 reps
->last_success
= reps1
->last_success
;
494 reps
->result_last_attempt
= reps1
->result_last_attempt
;
495 reps
->other_info
= talloc_zero(mem_ctx
, struct repsFromTo2OtherInfo
);
496 W_ERROR_HAVE_NO_MEMORY(reps
->other_info
);
497 reps
->other_info
->dns_name1
= reps1
->other_info
->dns_name
;
498 reps
->replica_flags
= reps1
->replica_flags
;
499 memcpy(reps
->schedule
, reps1
->schedule
, sizeof(reps1
->schedule
));
500 reps
->reserved
= reps1
->reserved
;
501 reps
->highwatermark
= reps1
->highwatermark
;
502 reps
->source_dsa_obj_guid
= reps1
->source_dsa_obj_guid
;
503 reps
->source_dsa_invocation_id
= reps1
->source_dsa_invocation_id
;
504 reps
->transport_guid
= reps1
->transport_guid
;
510 static WERROR
fill_neighbor_from_repsFrom(TALLOC_CTX
*mem_ctx
,
511 struct ldb_context
*samdb
,
512 struct ldb_dn
*nc_dn
,
513 struct drsuapi_DsReplicaNeighbour
*neigh
,
514 struct repsFromTo2
*reps_from
)
516 struct ldb_dn
*source_dsa_dn
;
518 struct ldb_dn
*transport_obj_dn
= NULL
;
520 neigh
->source_dsa_address
= reps_from
->other_info
->dns_name1
;
521 neigh
->replica_flags
= reps_from
->replica_flags
;
522 neigh
->last_attempt
= reps_from
->last_attempt
;
523 neigh
->source_dsa_obj_guid
= reps_from
->source_dsa_obj_guid
;
525 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, &reps_from
->source_dsa_obj_guid
,
526 DSDB_SEARCH_SHOW_RECYCLED
,
529 if (ret
!= LDB_SUCCESS
) {
530 DEBUG(0,(__location__
": Failed to find DN for neighbor GUID %s\n",
531 GUID_string(mem_ctx
, &reps_from
->source_dsa_obj_guid
)));
532 return WERR_DS_DRA_INTERNAL_ERROR
;
535 neigh
->source_dsa_obj_dn
= ldb_dn_get_linearized(source_dsa_dn
);
536 neigh
->naming_context_dn
= ldb_dn_get_linearized(nc_dn
);
538 if (dsdb_find_guid_by_dn(samdb
, nc_dn
,
539 &neigh
->naming_context_obj_guid
)
541 return WERR_DS_DRA_INTERNAL_ERROR
;
544 if (!GUID_all_zero(&reps_from
->transport_guid
)) {
545 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, &reps_from
->transport_guid
,
546 DSDB_SEARCH_SHOW_RECYCLED
,
548 if (ret
!= LDB_SUCCESS
) {
549 return WERR_DS_DRA_INTERNAL_ERROR
;
553 neigh
->transport_obj_dn
= ldb_dn_get_linearized(transport_obj_dn
);
554 neigh
->source_dsa_invocation_id
= reps_from
->source_dsa_invocation_id
;
555 neigh
->transport_obj_guid
= reps_from
->transport_guid
;
556 neigh
->highest_usn
= reps_from
->highwatermark
.highest_usn
;
557 neigh
->tmp_highest_usn
= reps_from
->highwatermark
.tmp_highest_usn
;
558 neigh
->last_success
= reps_from
->last_success
;
559 neigh
->result_last_attempt
= reps_from
->result_last_attempt
;
560 neigh
->consecutive_sync_failures
= reps_from
->consecutive_sync_failures
;
561 neigh
->reserved
= 0; /* Unused. MUST be 0. */
567 Get the inbound neighbours of this DC
568 See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
570 static WERROR
kccdrs_replica_get_info_neighbours(TALLOC_CTX
*mem_ctx
,
571 struct kccsrv_service
*service
,
572 struct ldb_context
*samdb
,
573 struct drsuapi_DsReplicaGetInfo
*r
,
574 union drsuapi_DsReplicaInfo
*reply
,
576 struct GUID req_src_dsa_guid
,
577 const char *object_dn_str
)
581 struct ldb_dn
*nc_dn
= NULL
;
582 struct ncList
*p_nc_list
= NULL
;
583 struct repsFromToBlob
*reps_from_blob
= NULL
;
584 struct repsFromTo2
*reps_from
= NULL
;
585 uint32_t c_reps_from
;
587 struct ncList
*nc_list
= NULL
;
589 status
= get_ncs_list(mem_ctx
, samdb
, service
, object_dn_str
, &nc_list
);
590 W_ERROR_NOT_OK_RETURN(status
);
594 reply
->neighbours
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaNeighbourCtr
);
595 W_ERROR_HAVE_NO_MEMORY(reply
->neighbours
);
596 reply
->neighbours
->reserved
= 0;
597 reply
->neighbours
->count
= 0;
599 /* foreach nc in ncs */
600 for (p_nc_list
= nc_list
; p_nc_list
!= NULL
; p_nc_list
= p_nc_list
->next
) {
602 nc_dn
= p_nc_list
->dn
;
604 /* load the nc's repsFromTo blob */
605 status
= dsdb_loadreps(samdb
, mem_ctx
, nc_dn
, "repsFrom",
606 &reps_from_blob
, &c_reps_from
);
607 W_ERROR_NOT_OK_RETURN(status
);
609 /* foreach r in nc!repsFrom */
610 for (i_rep
= 0; i_rep
< c_reps_from
; i_rep
++) {
612 /* put all info on reps_from */
613 if (reps_from_blob
[i_rep
].version
== 1) {
614 status
= copy_repsfrom_1_to_2(mem_ctx
, &reps_from
,
615 &reps_from_blob
[i_rep
].ctr
.ctr1
);
616 W_ERROR_NOT_OK_RETURN(status
);
617 } else { /* reps_from->version == 2 */
618 reps_from
= &reps_from_blob
[i_rep
].ctr
.ctr2
;
621 if (GUID_all_zero(&req_src_dsa_guid
) ||
622 GUID_equal(&req_src_dsa_guid
,
623 &reps_from
->source_dsa_obj_guid
)) {
625 if (i
>= base_index
) {
626 struct drsuapi_DsReplicaNeighbour neigh
;
628 status
= fill_neighbor_from_repsFrom(mem_ctx
, samdb
,
631 W_ERROR_NOT_OK_RETURN(status
);
633 /* append the neighbour to the neighbours array */
634 reply
->neighbours
->array
= talloc_realloc(mem_ctx
,
635 reply
->neighbours
->array
,
636 struct drsuapi_DsReplicaNeighbour
,
637 reply
->neighbours
->count
+ 1);
638 reply
->neighbours
->array
[reply
->neighbours
->count
] = neigh
;
639 reply
->neighbours
->count
++;
651 static WERROR
fill_neighbor_from_repsTo(TALLOC_CTX
*mem_ctx
,
652 struct ldb_context
*samdb
, struct ldb_dn
*nc_dn
,
653 struct drsuapi_DsReplicaNeighbour
*neigh
,
654 struct repsFromTo2
*reps_to
)
657 struct ldb_dn
*source_dsa_dn
;
659 neigh
->source_dsa_address
= reps_to
->other_info
->dns_name1
;
660 neigh
->replica_flags
= reps_to
->replica_flags
;
661 neigh
->last_attempt
= reps_to
->last_attempt
;
662 neigh
->source_dsa_obj_guid
= reps_to
->source_dsa_obj_guid
;
664 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
,
665 &reps_to
->source_dsa_obj_guid
,
666 DSDB_SEARCH_SHOW_RECYCLED
,
668 if (ret
!= LDB_SUCCESS
) {
669 DEBUG(0,(__location__
": Failed to find DN for neighbor GUID %s\n",
670 GUID_string(mem_ctx
, &reps_to
->source_dsa_obj_guid
)));
671 return WERR_DS_DRA_INTERNAL_ERROR
;
674 neigh
->source_dsa_obj_dn
= ldb_dn_get_linearized(source_dsa_dn
);
675 neigh
->naming_context_dn
= ldb_dn_get_linearized(nc_dn
);
677 ret
= dsdb_find_guid_by_dn(samdb
, nc_dn
,
678 &neigh
->naming_context_obj_guid
);
679 if (ret
!= LDB_SUCCESS
) {
680 DEBUG(0,(__location__
": Failed to find GUID for DN %s\n",
681 ldb_dn_get_linearized(nc_dn
)));
682 return WERR_DS_DRA_INTERNAL_ERROR
;
685 neigh
->last_success
= reps_to
->last_success
;
686 neigh
->result_last_attempt
= reps_to
->result_last_attempt
;
687 neigh
->consecutive_sync_failures
= reps_to
->consecutive_sync_failures
;
692 Get the outbound neighbours of this DC
693 See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_REPSTO
695 static WERROR
kccdrs_replica_get_info_repsto(TALLOC_CTX
*mem_ctx
,
696 struct kccsrv_service
*service
,
697 struct ldb_context
*samdb
,
698 struct drsuapi_DsReplicaGetInfo
*r
,
699 union drsuapi_DsReplicaInfo
*reply
,
701 struct GUID req_src_dsa_guid
,
702 const char *object_dn_str
)
706 struct ncList
*p_nc_list
= NULL
;
707 struct ldb_dn
*nc_dn
= NULL
;
708 struct repsFromToBlob
*reps_to_blob
;
709 struct repsFromTo2
*reps_to
;
712 struct ncList
*nc_list
= NULL
;
714 status
= get_ncs_list(mem_ctx
, samdb
, service
, object_dn_str
, &nc_list
);
715 W_ERROR_NOT_OK_RETURN(status
);
719 reply
->repsto
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaNeighbourCtr
);
720 W_ERROR_HAVE_NO_MEMORY(reply
->repsto
);
721 reply
->repsto
->reserved
= 0;
722 reply
->repsto
->count
= 0;
724 /* foreach nc in ncs */
725 for (p_nc_list
= nc_list
; p_nc_list
!= NULL
; p_nc_list
= p_nc_list
->next
) {
727 nc_dn
= p_nc_list
->dn
;
729 status
= dsdb_loadreps(samdb
, mem_ctx
, nc_dn
, "repsTo",
730 &reps_to_blob
, &c_reps_to
);
731 W_ERROR_NOT_OK_RETURN(status
);
733 /* foreach r in nc!repsTo */
734 for (i_rep
= 0; i_rep
< c_reps_to
; i_rep
++) {
735 struct drsuapi_DsReplicaNeighbour neigh
;
738 /* put all info on reps_to */
739 if (reps_to_blob
[i_rep
].version
== 1) {
740 status
= copy_repsfrom_1_to_2(mem_ctx
,
742 &reps_to_blob
[i_rep
].ctr
.ctr1
);
743 W_ERROR_NOT_OK_RETURN(status
);
744 } else { /* reps_to->version == 2 */
745 reps_to
= &reps_to_blob
[i_rep
].ctr
.ctr2
;
748 if (i
>= base_index
) {
749 status
= fill_neighbor_from_repsTo(mem_ctx
,
752 W_ERROR_NOT_OK_RETURN(status
);
754 /* append the neighbour to the neighbours array */
755 reply
->repsto
->array
= talloc_realloc(mem_ctx
,
756 reply
->repsto
->array
,
757 struct drsuapi_DsReplicaNeighbour
,
758 reply
->repsto
->count
+ 1);
759 reply
->repsto
->array
[reply
->repsto
->count
++] = neigh
;
769 NTSTATUS
kccdrs_replica_get_info(struct irpc_message
*msg
,
770 struct drsuapi_DsReplicaGetInfo
*req
)
773 struct drsuapi_DsReplicaGetInfoRequest1
*req1
;
774 struct drsuapi_DsReplicaGetInfoRequest2
*req2
;
776 union drsuapi_DsReplicaInfo
*reply
;
777 struct GUID req_src_dsa_guid
;
778 const char *object_dn_str
= NULL
;
779 struct kccsrv_service
*service
;
780 struct ldb_context
*samdb
;
782 enum drsuapi_DsReplicaInfoType info_type
;
784 service
= talloc_get_type(msg
->private_data
, struct kccsrv_service
);
785 samdb
= service
->samdb
;
786 mem_ctx
= talloc_new(msg
);
787 NT_STATUS_HAVE_NO_MEMORY(mem_ctx
);
790 NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo
, req
);
793 /* check request version */
794 if (req
->in
.level
!= DRSUAPI_DS_REPLICA_GET_INFO
&&
795 req
->in
.level
!= DRSUAPI_DS_REPLICA_GET_INFO2
)
797 DEBUG(1,(__location__
": Unsupported DsReplicaGetInfo level %u\n",
799 status
= WERR_REVISION_MISMATCH
;
803 if (req
->in
.level
== DRSUAPI_DS_REPLICA_GET_INFO
) {
804 req1
= &req
->in
.req
->req1
;
806 info_type
= req1
->info_type
;
807 object_dn_str
= req1
->object_dn
;
808 req_src_dsa_guid
= req1
->source_dsa_guid
;
809 } else { /* r->in.level == DRSUAPI_DS_REPLICA_GET_INFO2 */
810 req2
= &req
->in
.req
->req2
;
811 if (req2
->enumeration_context
== 0xffffffff) {
812 /* no more data is available */
813 status
= WERR_NO_MORE_ITEMS
; /* on MS-DRSR it is ERROR_NO_MORE_ITEMS */
817 base_index
= req2
->enumeration_context
;
818 info_type
= req2
->info_type
;
819 object_dn_str
= req2
->object_dn
;
820 req_src_dsa_guid
= req2
->source_dsa_guid
;
823 reply
= req
->out
.info
;
824 *req
->out
.info_type
= info_type
;
826 /* Based on the infoType requested, retrieve the corresponding
827 * information and construct the response message */
830 case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS
:
831 status
= kccdrs_replica_get_info_neighbours(mem_ctx
, service
, samdb
, req
,
832 reply
, base_index
, req_src_dsa_guid
,
835 case DRSUAPI_DS_REPLICA_INFO_REPSTO
:
836 status
= kccdrs_replica_get_info_repsto(mem_ctx
, service
, samdb
, req
,
837 reply
, base_index
, req_src_dsa_guid
,
840 case DRSUAPI_DS_REPLICA_INFO_CURSORS
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_FOR_NC */
841 status
= kccdrs_replica_get_info_cursors(mem_ctx
, samdb
, req
, reply
,
842 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
844 case DRSUAPI_DS_REPLICA_INFO_CURSORS2
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_2_FOR_NC */
845 status
= kccdrs_replica_get_info_cursors2(mem_ctx
, samdb
, req
, reply
,
846 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
848 case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS
:
849 status
= kccdrs_replica_get_info_pending_ops(mem_ctx
, samdb
, req
, reply
,
850 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
852 case DRSUAPI_DS_REPLICA_INFO_CURSORS3
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
853 status
= WERR_NOT_SUPPORTED
;
855 case DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1
: /* On MS-DRSR it is DS_REPL_INFO_UPTODATE_VECTOR_V1 */
856 status
= WERR_NOT_SUPPORTED
;
858 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
860 * It should be too complicated to filter the metadata2 to remove the additional data
861 * as metadata2 is a superset of metadata
863 status
= WERR_NOT_SUPPORTED
;
865 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
866 status
= kccdrs_replica_get_info_obj_metadata2(mem_ctx
, samdb
, req
, reply
,
867 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
), base_index
);
869 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_ATTR_VALUE */
870 status
= WERR_NOT_SUPPORTED
;
872 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE */
873 status
= WERR_NOT_SUPPORTED
;
875 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES
: /* On MS-DRSR it is DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES */
876 status
= WERR_NOT_SUPPORTED
;
878 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES
: /* On MS-DRSR it is DS_REPL_INFO_KCC_LINK_FAILURES */
879 status
= WERR_NOT_SUPPORTED
;
881 case DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS
: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
882 status
= WERR_NOT_SUPPORTED
;
884 case DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS
: /* On MS-DRSR it is DS_REPL_INFO_SERVER_OUTGOING_CALLS */
885 status
= WERR_NOT_SUPPORTED
;
888 DEBUG(1,(__location__
": Unsupported DsReplicaGetInfo info_type %u\n",
890 status
= WERR_INVALID_LEVEL
;
895 /* put the status on the result field of the reply */
896 req
->out
.result
= status
;
898 NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo
, req
);