2 Unix SMB/CIFS implementation.
4 DRS Replica Information
6 Copyright (C) Erick Nogueira do Nascimento 2009
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 "auth/auth.h"
26 #include "smbd/service.h"
27 #include "lib/events/events.h"
28 #include "lib/messaging/irpc.h"
29 #include "dsdb/kcc/kcc_service.h"
30 #include "lib/ldb/include/ldb_errors.h"
31 #include "../lib/util/dlinklist.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "librpc/gen_ndr/ndr_drsuapi.h"
34 #include "librpc/gen_ndr/ndr_drsblobs.h"
35 #include "param/param.h"
39 get cursors info for a specified DN
41 static WERROR
kccdrs_replica_get_info_cursors(TALLOC_CTX
*mem_ctx
,
42 struct ldb_context
*samdb
,
43 struct drsuapi_DsReplicaGetInfo
*r
,
44 union drsuapi_DsReplicaInfo
*reply
,
49 if (!ldb_dn_validate(dn
)) {
50 return WERR_INVALID_PARAMETER
;
52 reply
->cursors
= talloc(mem_ctx
, struct drsuapi_DsReplicaCursorCtr
);
53 W_ERROR_HAVE_NO_MEMORY(reply
->cursors
);
55 reply
->cursors
->reserved
= 0;
57 ret
= dsdb_load_udv_v1(samdb
, dn
, reply
->cursors
, &reply
->cursors
->array
, &reply
->cursors
->count
);
58 if (ret
!= LDB_SUCCESS
) {
59 return WERR_DS_DRA_BAD_NC
;
67 struct ncList
*prev
, *next
;
71 struct drsuapi_DsReplicaNeighbour
*neigh
;
72 struct neighList
*prev
, *next
;
75 static WERROR
copy_repsfrom_1_to_2(TALLOC_CTX
*mem_ctx
,
76 struct repsFromTo2
**reps2
,
77 struct repsFromTo1
*reps1
)
79 struct repsFromTo2
* reps
;
81 reps
= talloc_zero(mem_ctx
, struct repsFromTo2
);
82 W_ERROR_HAVE_NO_MEMORY(reps
);
84 reps
->blobsize
= reps1
->blobsize
;
85 reps
->consecutive_sync_failures
= reps1
->consecutive_sync_failures
;
86 reps
->last_attempt
= reps1
->last_attempt
;
87 reps
->last_success
= reps1
->last_success
;
88 reps
->other_info
= talloc_zero(mem_ctx
, struct repsFromTo2OtherInfo
);
89 W_ERROR_HAVE_NO_MEMORY(reps
->other_info
);
90 reps
->other_info
->dns_name1
= reps1
->other_info
->dns_name
;
91 reps
->replica_flags
= reps1
->replica_flags
;
92 memcpy(reps
->schedule
, reps1
->schedule
, sizeof(reps1
->schedule
));
93 reps
->reserved
= reps1
->reserved
;
94 reps
->highwatermark
= reps1
->highwatermark
;
95 reps
->source_dsa_obj_guid
= reps1
->source_dsa_obj_guid
;
96 reps
->source_dsa_invocation_id
= reps1
->source_dsa_invocation_id
;
97 reps
->transport_guid
= reps1
->transport_guid
;
103 static WERROR
fill_neighbor_from_repsFrom(TALLOC_CTX
*mem_ctx
,
104 struct ldb_context
*samdb
,
105 struct ldb_dn
*nc_dn
,
106 struct drsuapi_DsReplicaNeighbour
*neigh
,
107 struct repsFromTo2
*reps_from
)
110 struct ldb_dn
*source_dsa_dn
;
113 struct ldb_dn
*transport_obj_dn
= NULL
;
115 neigh
->source_dsa_address
= reps_from
->other_info
->dns_name1
;
116 neigh
->replica_flags
= reps_from
->replica_flags
;
117 neigh
->last_attempt
= reps_from
->last_attempt
;
118 neigh
->source_dsa_obj_guid
= reps_from
->source_dsa_obj_guid
;
120 dsa_guid_str
= GUID_string(mem_ctx
, &reps_from
->source_dsa_obj_guid
);
121 W_ERROR_HAVE_NO_MEMORY(dsa_guid_str
);
122 ret
= dsdb_find_dn_by_guid(samdb
, mem_ctx
, dsa_guid_str
, &source_dsa_dn
);
124 if (ret
!= LDB_SUCCESS
) {
125 DEBUG(0,(__location__
": Failed to find DN for neighbor GUID %s\n",
127 status
= WERR_DS_DRA_INTERNAL_ERROR
;
131 neigh
->source_dsa_obj_dn
= ldb_dn_get_linearized(source_dsa_dn
);
132 neigh
->naming_context_dn
= ldb_dn_get_linearized(nc_dn
);
134 if (dsdb_find_guid_by_dn(samdb
, nc_dn
, &neigh
->naming_context_obj_guid
)
136 status
= WERR_DS_DRA_INTERNAL_ERROR
;
140 if (!GUID_all_zero(&reps_from
->transport_guid
)) {
141 char *transp_guid_str
= GUID_string(mem_ctx
, &reps_from
->transport_guid
);
142 W_ERROR_HAVE_NO_MEMORY(transp_guid_str
);
143 if (dsdb_find_dn_by_guid(samdb
, mem_ctx
, transp_guid_str
,
144 &transport_obj_dn
) != LDB_SUCCESS
)
146 status
= WERR_DS_DRA_INTERNAL_ERROR
;
151 neigh
->transport_obj_dn
= ldb_dn_get_linearized(transport_obj_dn
);
152 neigh
->source_dsa_invocation_id
= reps_from
->source_dsa_invocation_id
;
153 neigh
->transport_obj_guid
= reps_from
->transport_guid
;
154 neigh
->highest_usn
= reps_from
->highwatermark
.highest_usn
;
155 neigh
->tmp_highest_usn
= reps_from
->highwatermark
.tmp_highest_usn
;
156 neigh
->last_success
= reps_from
->last_success
;
157 neigh
->result_last_attempt
= reps_from
->result_last_attempt
;
158 neigh
->consecutive_sync_failures
= reps_from
->consecutive_sync_failures
;
159 neigh
->reserved
= 0; /* Unused. MUST be 0. */
161 /* If everything went fine so far, set the status to OK */
168 * See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
170 static WERROR
kccdrs_replica_get_info_neighbours(TALLOC_CTX
*mem_ctx
,
171 struct ldb_context
*samdb
,
172 struct drsuapi_DsReplicaGetInfo
*r
,
173 union drsuapi_DsReplicaInfo
*reply
,
175 struct GUID req_src_dsa_guid
,
176 struct ncList
*nc_list
)
181 struct ldb_dn
*nc_dn
= NULL
;
182 struct ncList
*p_nc_list
= NULL
;
184 struct repsFromToBlob
*reps_from_blob
= NULL
;
185 struct repsFromTo2
*reps_from
= NULL
;
186 uint32_t c_reps_from
;
190 struct neighList
*neigh_list
= NULL
;
191 struct neighList
*neigh_elem
= NULL
;
193 struct drsuapi_DsReplicaNeighbour
*neigh
= NULL
;
198 /* foreach nc in ncs */
199 for (p_nc_list
= nc_list
; p_nc_list
!= NULL
; p_nc_list
= p_nc_list
->next
) {
201 nc_dn
= p_nc_list
->dn
;
203 /* load the nc's repsFromTo blob */
204 status
= dsdb_loadreps(samdb
, mem_ctx
, nc_dn
, "repsFrom",
205 &reps_from_blob
, &c_reps_from
);
206 if (!W_ERROR_IS_OK(status
)) {
207 status
= WERR_DS_DRA_INTERNAL_ERROR
;
211 /* foreach r in nc!repsFrom */
212 for (i_rep
= 0; i_rep
< c_reps_from
; i_rep
++) {
214 /* put all info on reps_from */
215 if (reps_from_blob
[i_rep
].version
== 1) {
216 status
= copy_repsfrom_1_to_2(mem_ctx
, &reps_from
,
217 &reps_from_blob
[i_rep
].ctr
.ctr1
);
218 if (!W_ERROR_IS_OK(status
)) {
221 } else { /* reps_from->version == 2 */
222 reps_from
= &reps_from_blob
[i_rep
].ctr
.ctr2
;
225 if (GUID_all_zero(&req_src_dsa_guid
) ||
226 GUID_compare(&req_src_dsa_guid
, &reps_from
->source_dsa_obj_guid
) == 0)
229 if (i
>= base_index
) {
230 neigh
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaNeighbour
);
231 W_ERROR_HAVE_NO_MEMORY(neigh
);
233 status
= fill_neighbor_from_repsFrom(mem_ctx
, samdb
,
236 if (!W_ERROR_IS_OK(status
)) {
240 /* append the neighbor to neigh_list */
241 neigh_elem
= talloc_zero(mem_ctx
, struct neighList
);
242 W_ERROR_HAVE_NO_MEMORY(neigh_elem
);
243 neigh_elem
->neigh
= neigh
;
244 DLIST_ADD_END(neigh_list
, neigh_elem
, struct neighList
*);
254 /* put all neighbours on neigh_list on reply->neighbours->array */
255 reply
->neighbours
= talloc_zero(mem_ctx
, struct drsuapi_DsReplicaNeighbourCtr
);
256 W_ERROR_HAVE_NO_MEMORY(reply
->neighbours
);
258 reply
->neighbours
->count
= j
;
259 reply
->neighbours
->reserved
= 0;
260 reply
->neighbours
->array
= talloc_array(mem_ctx
, struct drsuapi_DsReplicaNeighbour
, j
);
261 W_ERROR_HAVE_NO_MEMORY(reply
->neighbours
->array
);
263 for (k
= 0; neigh_list
!= NULL
; neigh_list
= neigh_list
->next
, k
++) {
264 reply
->neighbours
->array
[k
] = *neigh_list
->neigh
;
267 /* If everything went fine so far, set the status to OK */
273 static WERROR
get_master_ncs(TALLOC_CTX
*mem_ctx
, struct ldb_context
*samdb
,
274 const char *ntds_guid_str
, struct ncList
**master_nc_list
)
277 const char *attrs
[] = { "hasMasterNCs", NULL
};
278 struct ldb_result
*res
;
279 struct ncList
*nc_list
= NULL
;
280 struct ncList
*nc_list_elem
;
285 ret
= ldb_search(samdb
, mem_ctx
, &res
, ldb_get_config_basedn(samdb
),
286 LDB_SCOPE_DEFAULT
, attrs
, "(objectguid=%s)", ntds_guid_str
);
288 if (ret
!= LDB_SUCCESS
) {
289 DEBUG(0,(__location__
": Failed objectguid search - %s\n", ldb_errstring(samdb
)));
290 status
= WERR_INTERNAL_ERROR
;
294 if (res
->count
== 0) {
295 DEBUG(0,(__location__
": Failed: objectguid=%s not found\n", ntds_guid_str
));
296 status
= WERR_INTERNAL_ERROR
;
300 for (i
= 0; i
< res
->count
; i
++) {
302 struct ldb_message_element
*msg_elem
= ldb_msg_find_element(
303 res
->msgs
[i
], "hasMasterNCs");
306 if (!msg_elem
|| msg_elem
->num_values
== 0) {
307 DEBUG(0,(__location__
": Failed: Attribute hasMasterNCs not found - %s\n",
308 ldb_errstring(samdb
)));
309 status
= WERR_INTERNAL_ERROR
;
313 for (k
= 0; k
< msg_elem
->num_values
; k
++) {
314 int len
= msg_elem
->values
[k
].length
;
316 /* copy the string on msg_elem->values[k]->data to nc_str */
317 nc_str
= talloc_array(mem_ctx
, char, len
);
318 W_ERROR_HAVE_NO_MEMORY(nc_str
);
319 memcpy(nc_str
, msg_elem
->values
[k
].data
, len
);
322 nc_list_elem
= talloc_zero(mem_ctx
, struct ncList
);
323 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
324 nc_list_elem
->dn
= ldb_dn_new(mem_ctx
, samdb
, nc_str
);
325 W_ERROR_HAVE_NO_MEMORY(nc_list_elem
);
326 DLIST_ADD(nc_list
, nc_list_elem
);
331 *master_nc_list
= nc_list
;
332 /* If everything went fine so far, set the status to OK */
338 NTSTATUS
kccdrs_replica_get_info(struct irpc_message
*msg
,
339 struct drsuapi_DsReplicaGetInfo
*req
)
343 struct drsuapi_DsReplicaGetInfoRequest1
*req1
;
344 struct drsuapi_DsReplicaGetInfoRequest2
*req2
;
345 enum drsuapi_DsReplicaInfoType info_type
, *tmp_p_info_type
;
348 union drsuapi_DsReplicaInfo
*reply
;
350 struct GUID req_src_dsa_guid
;
351 const char *object_dn
= NULL
;
352 struct ldb_dn
*nc_dn
= NULL
;
353 struct ncList
*nc_list
= NULL
, *nc_list_elem
= NULL
;
355 struct kccsrv_service
*service
;
356 struct ldb_context
*samdb
;
359 service
= talloc_get_type(msg
->private_data
, struct kccsrv_service
);
360 samdb
= service
->samdb
;
361 mem_ctx
= talloc_new(msg
);
362 NT_STATUS_HAVE_NO_MEMORY(mem_ctx
);
364 NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo
, req
);
366 /* check request version */
367 if (req
->in
.level
!= DRSUAPI_DS_REPLICA_GET_INFO
&&
368 req
->in
.level
!= DRSUAPI_DS_REPLICA_GET_INFO2
)
370 DEBUG(1,(__location__
": Unsupported DsReplicaGetInfo level %u\n",
372 status
= WERR_REVISION_MISMATCH
;
376 if (req
->in
.level
== DRSUAPI_DS_REPLICA_GET_INFO
) {
377 req1
= &req
->in
.req
->req1
;
379 info_type
= req1
->info_type
;
380 object_dn
= req1
->object_dn
;
381 req_src_dsa_guid
= req1
->guid1
;
383 } else { /* r->in.level == DRSUAPI_DS_REPLICA_GET_INFO2 */
384 req2
= &req
->in
.req
->req2
;
385 if (req2
->unknown2
== 0xffffffff) {
386 /* no more data is available */
387 status
= WERR_NO_MORE_ITEMS
; /* on MS-DRSR it is ERROR_NO_MORE_ITEMS */
391 base_index
= req2
->unknown2
; /* Note: This is dwEnumerationContext on MS-DRSR 4.1.13.1.3 */
392 info_type
= req2
->info_type
;
393 object_dn
= req2
->object_dn
;
394 req_src_dsa_guid
= req2
->guid1
;
397 /* TODO: Perform the necessary access permission checking here according to the infoType requested */
399 case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS
:
400 case DRSUAPI_DS_REPLICA_INFO_CURSORS
:
401 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA
:
402 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES
:
403 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES
:
404 case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS
:
405 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA
:
406 case DRSUAPI_DS_REPLICA_INFO_CURSORS2
:
407 case DRSUAPI_DS_REPLICA_INFO_CURSORS3
:
408 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2
:
409 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2
:
410 case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02
:
411 case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04
:
412 case DRSUAPI_DS_REPLICA_INFO_CURSORS05
:
413 case DRSUAPI_DS_REPLICA_INFO_06
:
416 DEBUG(0,(__location__
": infoType %u requested is invalid.", (unsigned)info_type
));
417 status
= WERR_INVALID_PARAMETER
; /* infoType is invalid */
421 /* allocate the reply and fill in some fields */
422 reply
= talloc_zero(mem_ctx
, union drsuapi_DsReplicaInfo
);
423 NT_STATUS_HAVE_NO_MEMORY(reply
);
424 req
->out
.info
= reply
;
425 tmp_p_info_type
= talloc(mem_ctx
, enum drsuapi_DsReplicaInfoType
);
426 NT_STATUS_HAVE_NO_MEMORY(tmp_p_info_type
);
427 *tmp_p_info_type
= info_type
;
428 req
->out
.info_type
= tmp_p_info_type
;
430 /* Based on the infoType requested, retrieve the corresponding
431 * information and construct the response message */
434 case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS
:
435 if (object_dn
!= NULL
) { /* ncs := { object_dn } */
437 nc_dn
= ldb_dn_new(mem_ctx
, samdb
, object_dn
);
438 nc_list_elem
= talloc_zero(mem_ctx
, struct ncList
);
439 NT_STATUS_HAVE_NO_MEMORY(nc_list_elem
);
440 nc_list_elem
->dn
= nc_dn
;
441 DLIST_ADD_END(nc_list
, nc_list_elem
, struct ncList
*);
444 /* ncs := getNCs() from ldb database.
445 * getNCs() must return an array containing
446 * the DSNames of all NCs hosted by this
449 char *ntds_guid_str
= GUID_string(mem_ctx
, &service
->ntds_guid
);
450 NT_STATUS_HAVE_NO_MEMORY(ntds_guid_str
);
451 status
= get_master_ncs(mem_ctx
, samdb
, ntds_guid_str
, &nc_list
);
452 if (!W_ERROR_IS_OK(status
)) {
457 status
= kccdrs_replica_get_info_neighbours(mem_ctx
, samdb
, req
,
459 req_src_dsa_guid
, nc_list
);
462 case DRSUAPI_DS_REPLICA_INFO_CURSORS
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_FOR_NC */
463 status
= kccdrs_replica_get_info_cursors(mem_ctx
, samdb
, req
, reply
,
464 ldb_dn_new(mem_ctx
, samdb
, object_dn
));
466 case DRSUAPI_DS_REPLICA_INFO_CURSORS2
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_2_FOR_NC */
467 case DRSUAPI_DS_REPLICA_INFO_CURSORS3
: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
468 case DRSUAPI_DS_REPLICA_INFO_CURSORS05
: /* On MS-DRSR it is DS_REPL_INFO_UPTODATE_VECTOR_V1 */
469 case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02
: /* DS_REPL_INFO_REPSTO */
470 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
471 case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
472 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_ATTR_VALUE */
473 case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2
: /* On MS-DRSR it is DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE */
474 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES
: /* On MS-DRSR it is DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES */
475 case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES
: /* On MS-DRSR it is DS_REPL_INFO_KCC_LINK_FAILURES */
476 case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS
: /* On MS-DRSR it is DS_REPL_INFO_PENDING_OPS */
477 case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04
: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
478 case DRSUAPI_DS_REPLICA_INFO_06
: /* On MS-DRSR it is DS_REPL_INFO_SERVER_OUTGOING_CALLS */
480 DEBUG(1,(__location__
": Unsupported DsReplicaGetInfo info_type %u\n",
482 status
= WERR_INVALID_LEVEL
;
487 /* put the status on the result field of the reply */
488 req
->out
.result
= status
;
489 NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo
, req
);