lib: Make create_synthetic_smb_fname_split use synthetic_smb_fname_split
[Samba/gebeck_regimport.git] / source4 / dsdb / kcc / kcc_drs_replica_info.c
blob0b6b82ad5633fd0c73f3b21b3ab8dd51d2707fbc
1 /*
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/>.
23 #include "includes.h"
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;
48 int ret;
49 const char *attrs[2];
50 struct ldb_dn *attr_ext_dn;
51 NTSTATUS ntstatus;
53 attrs[0] = linked_attr_name;
54 attrs[1] = NULL;
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);
65 if (!attr_ext_dn) {
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;
95 return WERR_OK;
98 static WERROR get_repl_prop_metadata_ctr(TALLOC_CTX *mem_ctx,
99 struct ldb_context *samdb,
100 struct ldb_dn *dn,
101 struct replPropertyMetaDataBlob *obj_metadata_ctr)
103 int ret;
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");
117 if (!omd_value) {
118 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
119 ldb_dn_get_linearized(dn)));
120 talloc_free(res);
121 return WERR_INTERNAL_ERROR;
124 ndr_err = ndr_pull_struct_blob(omd_value, mem_ctx,
125 obj_metadata_ctr,
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)));
130 talloc_free(res);
131 return WERR_INTERNAL_ERROR;
134 talloc_free(res);
135 return WERR_OK;
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,
146 const char **dn_str)
148 char *invocation_id_str;
149 const char *attrs_invocation[] = { NULL };
150 struct ldb_message *msg;
151 int ret;
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);
167 return WERR_OK;
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,
177 struct ldb_dn *dn,
178 uint32_t base_index)
180 WERROR status;
181 struct replPropertyMetaDataBlob omd_ctr;
182 struct replPropertyMetaData1 *attr;
183 struct drsuapi_DsReplicaObjMetaData2Ctr *metadata2;
184 const struct dsdb_schema *schema;
186 uint32_t i, j;
188 DEBUG(0, ("kccdrs_replica_get_info_obj_metadata2() called\n"));
190 if (!dn) {
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);
202 if (!schema) {
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;
220 attr := attrsSeq[i]
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)
234 if (schema_attr &&
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 */
237 r->in.level == 2 &&
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) {
271 continue;
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);
293 j++;
294 metadata2->count = j;
298 return WERR_OK;
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,
308 struct ldb_dn *dn)
310 int ret;
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;
324 return WERR_OK;
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,
334 struct ldb_dn *dn)
336 int ret;
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;
350 return WERR_OK;
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,
360 struct ldb_dn *dn)
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;
375 return WERR_OK;
378 struct ncList {
379 struct ldb_dn *dn;
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;
395 int ret;
396 unsigned int i;
397 char *nc_str;
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;
426 unsigned int k, a;
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) {
431 continue;
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;
449 return WERR_OK;
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)
463 WERROR status;
464 struct ncList *nc_list_elem;
465 struct ldb_dn *nc_dn;
467 if (object_dn_str != NULL) {
468 /* ncs := { object_dn } */
469 *nc_list = NULL;
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*);
475 } else {
476 /* ncs := getNCs() from ldb database.
477 * getNCs() must return an array containing
478 * the DSNames of all NCs hosted by this
479 * server.
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);
487 return WERR_OK;
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;
519 *reps2 = reps;
520 return WERR_OK;
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;
530 int ret;
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,
539 &source_dsa_dn);
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)
551 != LDB_SUCCESS) {
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,
557 &transport_obj_dn);
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. */
573 return WERR_OK;
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,
585 uint32_t base_index,
586 struct GUID req_src_dsa_guid,
587 const char *object_dn_str)
589 WERROR status;
590 uint32_t i, j;
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;
596 uint32_t i_rep;
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);
602 i = j = 0;
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;
637 ZERO_STRUCT(neigh);
638 status = fill_neighbor_from_repsFrom(mem_ctx, samdb,
639 nc_dn, &neigh,
640 reps_from);
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++;
650 j++;
653 i++;
658 return WERR_OK;
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)
666 int ret;
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;
695 return WERR_OK;
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,
707 uint32_t base_index,
708 struct GUID req_src_dsa_guid,
709 const char *object_dn_str)
711 WERROR status;
712 uint32_t i, j;
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;
717 uint32_t c_reps_to;
718 uint32_t i_rep;
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);
724 i = j = 0;
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;
743 ZERO_STRUCT(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,
748 &reps_to,
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,
757 samdb, nc_dn,
758 &neigh, reps_to);
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;
767 j++;
769 i++;
773 return WERR_OK;
776 NTSTATUS kccdrs_replica_get_info(struct irpc_message *msg,
777 struct drsuapi_DsReplicaGetInfo *req)
779 WERROR status;
780 struct drsuapi_DsReplicaGetInfoRequest1 *req1;
781 struct drsuapi_DsReplicaGetInfoRequest2 *req2;
782 uint32_t base_index;
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;
788 TALLOC_CTX *mem_ctx;
789 enum drsuapi_DsReplicaInfoType info_type;
790 uint32_t flags;
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);
798 #if 0
799 NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo, req);
800 #endif
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",
807 req->in.level));
808 status = WERR_REVISION_MISMATCH;
809 goto done;
812 if (req->in.level == DRSUAPI_DS_REPLICA_GET_INFO) {
813 req1 = &req->in.req->req1;
814 base_index = 0;
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 */
823 goto done;
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;
830 flags = req2->flags;
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 */
840 switch (info_type) {
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,
845 object_dn_str);
846 break;
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,
850 object_dn_str);
851 break;
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));
855 break;
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));
859 break;
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));
863 break;
864 case DRSUAPI_DS_REPLICA_INFO_CURSORS3: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
865 status = WERR_NOT_SUPPORTED;
866 break;
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;
869 break;
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;
876 break;
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);
880 break;
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;
883 break;
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;
886 break;
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;
889 break;
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;
892 break;
893 case DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
894 status = WERR_NOT_SUPPORTED;
895 break;
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;
898 break;
899 default:
900 DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo info_type %u\n",
901 info_type));
902 status = WERR_INVALID_LEVEL;
903 break;
906 done:
907 /* put the status on the result field of the reply */
908 req->out.result = status;
909 #if 0
910 NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo, req);
911 #endif
912 return NT_STATUS_OK;