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 *attrs
[] = { "hasMasterNCs", NULL
};
390 struct ldb_result
*res
;
391 struct ncList
*nc_list
= NULL
;
392 struct ncList
*nc_list_elem
;
397 ret
= ldb_search(samdb
, mem_ctx
, &res
, ldb_get_config_basedn(samdb
),
398 LDB_SCOPE_DEFAULT
, attrs
, "(objectguid=%s)", ntds_guid_str
);
400 if (ret
!= LDB_SUCCESS
) {
401 DEBUG(0,(__location__
": Failed objectguid search - %s\n", ldb_errstring(samdb
)));
402 return WERR_INTERNAL_ERROR
;
405 if (res
->count
== 0) {
406 DEBUG(0,(__location__
": Failed: objectguid=%s not found\n", ntds_guid_str
));
407 return WERR_INTERNAL_ERROR
;
410 for (i
= 0; i
< res
->count
; i
++) {
411 struct ldb_message_element
*msg_elem
= ldb_msg_find_element(res
->msgs
[i
], "hasMasterNCs");
414 if (!msg_elem
|| msg_elem
->num_values
== 0) {
415 DEBUG(0,(__location__
": Failed: Attribute hasMasterNCs not found - %s\n",
416 ldb_errstring(samdb
)));
417 return WERR_INTERNAL_ERROR
;
420 for (k
= 0; k
< msg_elem
->num_values
; k
++) {
421 /* copy the string on msg_elem->values[k]->data to nc_str */
422 nc_str
= talloc_strndup(mem_ctx
, (char *)msg_elem
->values
[k
].data
, msg_elem
->values
[k
].length
);
423 W_ERROR_HAVE_NO_MEMORY(nc_str
);
425 nc_list_elem
= talloc_zero(mem_ctx
, struct ncList
);
426 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
427 nc_list_elem
->dn
= ldb_dn_new(mem_ctx
, samdb
, nc_str
);
428 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
429 DLIST_ADD(nc_list
, nc_list_elem
);
434 *master_nc_list
= nc_list
;
439 Fill 'nc_list' with the ncs list. (MS-DRSR 4.1.13.3)
440 if the object dn is specified, fill 'nc_list' only with this dn
441 otherwise, fill 'nc_list' with all master ncs hosted by this server
443 static WERROR
get_ncs_list(TALLOC_CTX
*mem_ctx
,
444 struct ldb_context
*samdb
,
445 struct kccsrv_service
*service
,
446 const char *object_dn_str
,
447 struct ncList
**nc_list
)
450 struct ncList
*nc_list_elem
;
451 struct ldb_dn
*nc_dn
;
453 if (object_dn_str
!= NULL
) {
454 /* ncs := { object_dn } */
456 nc_dn
= ldb_dn_new(mem_ctx
, samdb
, object_dn_str
);
457 nc_list_elem
= talloc_zero(mem_ctx
, struct ncList
);
458 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
459 nc_list_elem
->dn
= nc_dn
;
460 DLIST_ADD_END(*nc_list
, nc_list_elem
, struct ncList
*);
462 /* ncs := getNCs() from ldb database.
463 * getNCs() must return an array containing
464 * the DSNames of all NCs hosted by this
467 char *ntds_guid_str
= GUID_string(mem_ctx
, &service
->ntds_guid
);
468 W_ERROR_HAVE_NO_MEMORY(ntds_guid_str
);
469 status
= get_master_ncs(mem_ctx
, samdb
, ntds_guid_str
, nc_list
);
470 W_ERROR_NOT_OK_RETURN(status
);
477 Copy the fields from 'reps1' to 'reps2', leaving zeroed the fields on
478 'reps2' that aren't available on 'reps1'.
480 static WERROR
copy_repsfrom_1_to_2(TALLOC_CTX
*mem_ctx
,
481 struct repsFromTo2
**reps2
,
482 struct repsFromTo1
*reps1
)
484 struct repsFromTo2
* reps
;
486 reps
= talloc_zero(mem_ctx
, struct repsFromTo2
);
487 W_ERROR_HAVE_NO_MEMORY(reps
);
489 reps
->blobsize
= reps1
->blobsize
;
490 reps
->consecutive_sync_failures
= reps1
->consecutive_sync_failures
;
491 reps
->last_attempt
= reps1
->last_attempt
;
492 reps
->last_success
= reps1
->last_success
;
493 reps
->result_last_attempt
= reps1
->result_last_attempt
;
494 reps
->other_info
= talloc_zero(mem_ctx
, struct repsFromTo2OtherInfo
);
495 W_ERROR_HAVE_NO_MEMORY(reps
->other_info
);
496 reps
->other_info
->dns_name1
= reps1
->other_info
->dns_name
;
497 reps
->replica_flags
= reps1
->replica_flags
;
498 memcpy(reps
->schedule
, reps1
->schedule
, sizeof(reps1
->schedule
));
499 reps
->reserved
= reps1
->reserved
;
500 reps
->highwatermark
= reps1
->highwatermark
;
501 reps
->source_dsa_obj_guid
= reps1
->source_dsa_obj_guid
;
502 reps
->source_dsa_invocation_id
= reps1
->source_dsa_invocation_id
;
503 reps
->transport_guid
= reps1
->transport_guid
;
509 static WERROR
fill_neighbor_from_repsFrom(TALLOC_CTX
*mem_ctx
,
510 struct ldb_context
*samdb
,
511 struct ldb_dn
*nc_dn
,
512 struct drsuapi_DsReplicaNeighbour
*neigh
,
513 struct repsFromTo2
*reps_from
)
515 struct ldb_dn
*source_dsa_dn
;
517 struct ldb_dn
*transport_obj_dn
= NULL
;
519 neigh
->source_dsa_address
= reps_from
->other_info
->dns_name1
;
520 neigh
->replica_flags
= reps_from
->replica_flags
;
521 neigh
->last_attempt
= reps_from
->last_attempt
;
522 neigh
->source_dsa_obj_guid
= reps_from
->source_dsa_obj_guid
;
524 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, &reps_from
->source_dsa_obj_guid
,
527 if (ret
!= LDB_SUCCESS
) {
528 DEBUG(0,(__location__
": Failed to find DN for neighbor GUID %s\n",
529 GUID_string(mem_ctx
, &reps_from
->source_dsa_obj_guid
)));
530 return WERR_DS_DRA_INTERNAL_ERROR
;
533 neigh
->source_dsa_obj_dn
= ldb_dn_get_linearized(source_dsa_dn
);
534 neigh
->naming_context_dn
= ldb_dn_get_linearized(nc_dn
);
536 if (dsdb_find_guid_by_dn(samdb
, nc_dn
, &neigh
->naming_context_obj_guid
)
538 return WERR_DS_DRA_INTERNAL_ERROR
;
541 if (!GUID_all_zero(&reps_from
->transport_guid
)) {
542 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, &reps_from
->transport_guid
,
544 if (ret
!= LDB_SUCCESS
) {
545 return WERR_DS_DRA_INTERNAL_ERROR
;
549 neigh
->transport_obj_dn
= ldb_dn_get_linearized(transport_obj_dn
);
550 neigh
->source_dsa_invocation_id
= reps_from
->source_dsa_invocation_id
;
551 neigh
->transport_obj_guid
= reps_from
->transport_guid
;
552 neigh
->highest_usn
= reps_from
->highwatermark
.highest_usn
;
553 neigh
->tmp_highest_usn
= reps_from
->highwatermark
.tmp_highest_usn
;
554 neigh
->last_success
= reps_from
->last_success
;
555 neigh
->result_last_attempt
= reps_from
->result_last_attempt
;
556 neigh
->consecutive_sync_failures
= reps_from
->consecutive_sync_failures
;
557 neigh
->reserved
= 0; /* Unused. MUST be 0. */
563 Get the inbound neighbours of this DC
564 See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
566 static WERROR
kccdrs_replica_get_info_neighbours(TALLOC_CTX
*mem_ctx
,
567 struct kccsrv_service
*service
,
568 struct ldb_context
*samdb
,
569 struct drsuapi_DsReplicaGetInfo
*r
,
570 union drsuapi_DsReplicaInfo
*reply
,
572 struct GUID req_src_dsa_guid
,
573 const char *object_dn_str
)
577 struct ldb_dn
*nc_dn
= NULL
;
578 struct ncList
*p_nc_list
= NULL
;
579 struct repsFromToBlob
*reps_from_blob
= NULL
;
580 struct repsFromTo2
*reps_from
= NULL
;
581 uint32_t c_reps_from
;
583 struct ncList
*nc_list
= NULL
;
585 status
= get_ncs_list(mem_ctx
, samdb
, service
, object_dn_str
, &nc_list
);
586 W_ERROR_NOT_OK_RETURN(status
);
590 reply
->neighbours
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaNeighbourCtr
);
591 W_ERROR_HAVE_NO_MEMORY(reply
->neighbours
);
592 reply
->neighbours
->reserved
= 0;
593 reply
->neighbours
->count
= 0;
595 /* foreach nc in ncs */
596 for (p_nc_list
= nc_list
; p_nc_list
!= NULL
; p_nc_list
= p_nc_list
->next
) {
598 nc_dn
= p_nc_list
->dn
;
600 /* load the nc's repsFromTo blob */
601 status
= dsdb_loadreps(samdb
, mem_ctx
, nc_dn
, "repsFrom",
602 &reps_from_blob
, &c_reps_from
);
603 W_ERROR_NOT_OK_RETURN(status
);
605 /* foreach r in nc!repsFrom */
606 for (i_rep
= 0; i_rep
< c_reps_from
; i_rep
++) {
608 /* put all info on reps_from */
609 if (reps_from_blob
[i_rep
].version
== 1) {
610 status
= copy_repsfrom_1_to_2(mem_ctx
, &reps_from
,
611 &reps_from_blob
[i_rep
].ctr
.ctr1
);
612 W_ERROR_NOT_OK_RETURN(status
);
613 } else { /* reps_from->version == 2 */
614 reps_from
= &reps_from_blob
[i_rep
].ctr
.ctr2
;
617 if (GUID_all_zero(&req_src_dsa_guid
) ||
618 GUID_compare(&req_src_dsa_guid
, &reps_from
->source_dsa_obj_guid
) == 0)
621 if (i
>= base_index
) {
622 struct drsuapi_DsReplicaNeighbour neigh
;
624 status
= fill_neighbor_from_repsFrom(mem_ctx
, samdb
,
627 W_ERROR_NOT_OK_RETURN(status
);
629 /* append the neighbour to the neighbours array */
630 reply
->neighbours
->array
= talloc_realloc(mem_ctx
,
631 reply
->neighbours
->array
,
632 struct drsuapi_DsReplicaNeighbour
,
633 reply
->neighbours
->count
+ 1);
634 reply
->neighbours
->array
[reply
->neighbours
->count
] = neigh
;
635 reply
->neighbours
->count
++;
647 static WERROR
fill_neighbor_from_repsTo(TALLOC_CTX
*mem_ctx
,
648 struct ldb_context
*samdb
, struct ldb_dn
*nc_dn
,
649 struct drsuapi_DsReplicaNeighbour
*neigh
,
650 struct repsFromTo2
*reps_to
)
653 struct ldb_dn
*source_dsa_dn
;
655 neigh
->source_dsa_address
= reps_to
->other_info
->dns_name1
;
656 neigh
->replica_flags
= reps_to
->replica_flags
;
657 neigh
->last_attempt
= reps_to
->last_attempt
;
658 neigh
->source_dsa_obj_guid
= reps_to
->source_dsa_obj_guid
;
660 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, &reps_to
->source_dsa_obj_guid
, &source_dsa_dn
);
661 if (ret
!= LDB_SUCCESS
) {
662 DEBUG(0,(__location__
": Failed to find DN for neighbor GUID %s\n",
663 GUID_string(mem_ctx
, &reps_to
->source_dsa_obj_guid
)));
664 return WERR_DS_DRA_INTERNAL_ERROR
;
667 neigh
->source_dsa_obj_dn
= ldb_dn_get_linearized(source_dsa_dn
);
668 neigh
->naming_context_dn
= ldb_dn_get_linearized(nc_dn
);
670 ret
= dsdb_find_guid_by_dn(samdb
, nc_dn
,
671 &neigh
->naming_context_obj_guid
);
672 if (ret
!= LDB_SUCCESS
) {
673 DEBUG(0,(__location__
": Failed to find GUID for DN %s\n",
674 ldb_dn_get_linearized(nc_dn
)));
675 return WERR_DS_DRA_INTERNAL_ERROR
;
682 Get the outbound neighbours of this DC
683 See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_REPSTO
685 static WERROR
kccdrs_replica_get_info_repsto(TALLOC_CTX
*mem_ctx
,
686 struct kccsrv_service
*service
,
687 struct ldb_context
*samdb
,
688 struct drsuapi_DsReplicaGetInfo
*r
,
689 union drsuapi_DsReplicaInfo
*reply
,
691 struct GUID req_src_dsa_guid
,
692 const char *object_dn_str
)
696 struct ncList
*p_nc_list
= NULL
;
697 struct ldb_dn
*nc_dn
= NULL
;
698 struct repsFromToBlob
*reps_to_blob
;
699 struct repsFromTo2
*reps_to
;
702 struct ncList
*nc_list
= NULL
;
704 status
= get_ncs_list(mem_ctx
, samdb
, service
, object_dn_str
, &nc_list
);
705 W_ERROR_NOT_OK_RETURN(status
);
709 reply
->repsto
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaNeighbourCtr
);
710 W_ERROR_HAVE_NO_MEMORY(reply
->repsto
);
711 reply
->repsto
->reserved
= 0;
712 reply
->repsto
->count
= 0;
714 /* foreach nc in ncs */
715 for (p_nc_list
= nc_list
; p_nc_list
!= NULL
; p_nc_list
= p_nc_list
->next
) {
717 nc_dn
= p_nc_list
->dn
;
719 status
= dsdb_loadreps(samdb
, mem_ctx
, nc_dn
, "repsTo",
720 &reps_to_blob
, &c_reps_to
);
721 W_ERROR_NOT_OK_RETURN(status
);
723 /* foreach r in nc!repsTo */
724 for (i_rep
= 0; i_rep
< c_reps_to
; i_rep
++) {
725 struct drsuapi_DsReplicaNeighbour neigh
;
728 /* put all info on reps_to */
729 if (reps_to_blob
[i_rep
].version
== 1) {
730 status
= copy_repsfrom_1_to_2(mem_ctx
,
732 &reps_to_blob
[i_rep
].ctr
.ctr1
);
733 W_ERROR_NOT_OK_RETURN(status
);
734 } else { /* reps_to->version == 2 */
735 reps_to
= &reps_to_blob
[i_rep
].ctr
.ctr2
;
738 if (i
>= base_index
) {
739 status
= fill_neighbor_from_repsTo(mem_ctx
,
742 W_ERROR_NOT_OK_RETURN(status
);
744 /* append the neighbour to the neighbours array */
745 reply
->repsto
->array
= talloc_realloc(mem_ctx
,
746 reply
->repsto
->array
,
747 struct drsuapi_DsReplicaNeighbour
,
748 reply
->repsto
->count
+ 1);
749 reply
->repsto
->array
[reply
->repsto
->count
++] = neigh
;
759 NTSTATUS
kccdrs_replica_get_info(struct irpc_message
*msg
,
760 struct drsuapi_DsReplicaGetInfo
*req
)
763 struct drsuapi_DsReplicaGetInfoRequest1
*req1
;
764 struct drsuapi_DsReplicaGetInfoRequest2
*req2
;
766 union drsuapi_DsReplicaInfo
*reply
;
767 struct GUID req_src_dsa_guid
;
768 const char *object_dn_str
= NULL
;
769 struct kccsrv_service
*service
;
770 struct ldb_context
*samdb
;
772 enum drsuapi_DsReplicaInfoType info_type
;
774 const char *attribute_name
, *value_dn
;
776 service
= talloc_get_type(msg
->private_data
, struct kccsrv_service
);
777 samdb
= service
->samdb
;
778 mem_ctx
= talloc_new(msg
);
779 NT_STATUS_HAVE_NO_MEMORY(mem_ctx
);
782 NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo
, req
);
785 /* check request version */
786 if (req
->in
.level
!= DRSUAPI_DS_REPLICA_GET_INFO
&&
787 req
->in
.level
!= DRSUAPI_DS_REPLICA_GET_INFO2
)
789 DEBUG(1,(__location__
": Unsupported DsReplicaGetInfo level %u\n",
791 status
= WERR_REVISION_MISMATCH
;
795 if (req
->in
.level
== DRSUAPI_DS_REPLICA_GET_INFO
) {
796 req1
= &req
->in
.req
->req1
;
798 info_type
= req1
->info_type
;
799 object_dn_str
= req1
->object_dn
;
800 req_src_dsa_guid
= req1
->source_dsa_guid
;
801 } else { /* r->in.level == DRSUAPI_DS_REPLICA_GET_INFO2 */
802 req2
= &req
->in
.req
->req2
;
803 if (req2
->enumeration_context
== 0xffffffff) {
804 /* no more data is available */
805 status
= WERR_NO_MORE_ITEMS
; /* on MS-DRSR it is ERROR_NO_MORE_ITEMS */
809 base_index
= req2
->enumeration_context
;
810 info_type
= req2
->info_type
;
811 object_dn_str
= req2
->object_dn
;
812 req_src_dsa_guid
= req2
->source_dsa_guid
;
814 attribute_name
= req2
->attribute_name
;
815 value_dn
= req2
->value_dn_str
;
818 reply
= req
->out
.info
;
819 *req
->out
.info_type
= info_type
;
821 /* Based on the infoType requested, retrieve the corresponding
822 * information and construct the response message */
825 case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS
:
826 status
= kccdrs_replica_get_info_neighbours(mem_ctx
, service
, samdb
, req
,
827 reply
, base_index
, req_src_dsa_guid
,
830 case DRSUAPI_DS_REPLICA_INFO_REPSTO
:
831 status
= kccdrs_replica_get_info_repsto(mem_ctx
, service
, samdb
, req
,
832 reply
, base_index
, req_src_dsa_guid
,
835 case DRSUAPI_DS_REPLICA_INFO_CURSORS
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_FOR_NC */
836 status
= kccdrs_replica_get_info_cursors(mem_ctx
, samdb
, req
, reply
,
837 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
839 case DRSUAPI_DS_REPLICA_INFO_CURSORS2
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_2_FOR_NC */
840 status
= kccdrs_replica_get_info_cursors2(mem_ctx
, samdb
, req
, reply
,
841 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
843 case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS
:
844 status
= kccdrs_replica_get_info_pending_ops(mem_ctx
, samdb
, req
, reply
,
845 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
));
847 case DRSUAPI_DS_REPLICA_INFO_CURSORS3
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
848 status
= WERR_INVALID_LEVEL
;
850 case DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1
: /* On MS-DRSR it is DS_REPL_INFO_UPTODATE_VECTOR_V1 */
851 status
= WERR_INVALID_LEVEL
;
853 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
854 status
= WERR_INVALID_LEVEL
;
856 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
857 status
= kccdrs_replica_get_info_obj_metadata2(mem_ctx
, samdb
, req
, reply
,
858 ldb_dn_new(mem_ctx
, samdb
, object_dn_str
), base_index
);
860 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_ATTR_VALUE */
861 status
= WERR_INVALID_LEVEL
;
863 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE */
864 status
= WERR_INVALID_LEVEL
;
866 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES
: /* On MS-DRSR it is DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES */
867 status
= WERR_INVALID_LEVEL
;
869 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES
: /* On MS-DRSR it is DS_REPL_INFO_KCC_LINK_FAILURES */
870 status
= WERR_INVALID_LEVEL
;
872 case DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS
: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
873 status
= WERR_INVALID_LEVEL
;
875 case DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS
: /* On MS-DRSR it is DS_REPL_INFO_SERVER_OUTGOING_CALLS */
876 status
= WERR_INVALID_LEVEL
;
879 DEBUG(1,(__location__
": Unsupported DsReplicaGetInfo info_type %u\n",
881 status
= WERR_INVALID_LEVEL
;
886 /* put the status on the result field of the reply */
887 req
->out
.result
= status
;
889 NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo
, req
);