s4-kcc: added support for CURSORS info level in DsReplicaGetInfo
[Samba/gebeck_regimport.git] / source4 / dsdb / kcc / kcc_drs_replica_info.c
blob6d42ec62529146c737ed142f1de8537e81778514
1 /*
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/>.
23 #include "includes.h"
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,
45 struct ldb_dn *dn)
47 int ret;
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;
61 return WERR_OK;
65 struct ncList {
66 struct ldb_dn *dn;
67 struct ncList *prev, *next;
70 struct neighList {
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;
99 *reps2 = reps;
100 return WERR_OK;
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)
109 WERROR status;
110 struct ldb_dn *source_dsa_dn;
111 int ret;
112 char *dsa_guid_str;
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",
126 dsa_guid_str));
127 status = WERR_DS_DRA_INTERNAL_ERROR;
128 goto DONE;
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)
135 != LDB_SUCCESS) {
136 status = WERR_DS_DRA_INTERNAL_ERROR;
137 goto DONE;
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;
147 goto DONE;
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 */
162 status = WERR_OK;
163 DONE:
164 return status;
168 * See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
169 * */
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,
174 int base_index,
175 struct GUID req_src_dsa_guid,
176 struct ncList *nc_list)
178 WERROR status;
180 int i, j, k;
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;
188 int i_rep;
190 struct neighList *neigh_list = NULL;
191 struct neighList *neigh_elem = NULL;
193 struct drsuapi_DsReplicaNeighbour *neigh = NULL;
195 i = j = 0;
196 neigh_list = 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;
208 goto DONE;
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)) {
219 goto DONE;
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,
234 nc_dn, neigh,
235 reps_from);
236 if (!W_ERROR_IS_OK(status)) {
237 goto DONE;
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*);
246 j++;
249 i++;
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 */
268 status = WERR_OK;
269 DONE:
270 return status;
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)
276 WERROR status;
277 const char *attrs[] = { "hasMasterNCs", NULL };
278 struct ldb_result *res;
279 struct ncList *nc_list = NULL;
280 struct ncList *nc_list_elem;
281 int ret;
282 int i;
283 char *nc_str;
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;
291 goto DONE;
294 if (res->count == 0) {
295 DEBUG(0,(__location__ ": Failed: objectguid=%s not found\n", ntds_guid_str));
296 status = WERR_INTERNAL_ERROR;
297 goto DONE;
300 for (i = 0; i < res->count; i++) {
302 struct ldb_message_element *msg_elem = ldb_msg_find_element(
303 res->msgs[i], "hasMasterNCs");
304 int k;
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;
310 goto DONE;
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);
320 nc_str[len] = '\0';
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 */
333 status = WERR_OK;
334 DONE:
335 return status;
338 NTSTATUS kccdrs_replica_get_info(struct irpc_message *msg,
339 struct drsuapi_DsReplicaGetInfo *req)
341 WERROR status;
343 struct drsuapi_DsReplicaGetInfoRequest1 *req1;
344 struct drsuapi_DsReplicaGetInfoRequest2 *req2;
345 enum drsuapi_DsReplicaInfoType info_type, *tmp_p_info_type;
347 int base_index;
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;
357 TALLOC_CTX *mem_ctx;
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",
371 req->in.level));
372 status = WERR_REVISION_MISMATCH;
373 goto DONE;
376 if (req->in.level == DRSUAPI_DS_REPLICA_GET_INFO) {
377 req1 = &req->in.req->req1;
378 base_index = 0;
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 */
388 goto DONE;
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 */
398 switch (info_type) {
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:
414 break;
415 default:
416 DEBUG(0,(__location__ ": infoType %u requested is invalid.", (unsigned)info_type));
417 status = WERR_INVALID_PARAMETER; /* infoType is invalid */
418 goto DONE;
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 */
432 switch (info_type) {
434 case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
435 if (object_dn != NULL) { /* ncs := { object_dn } */
436 nc_list = NULL;
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*);
443 } else {
444 /* ncs := getNCs() from ldb database.
445 * getNCs() must return an array containing
446 * the DSNames of all NCs hosted by this
447 * server.
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)) {
453 goto DONE;
457 status = kccdrs_replica_get_info_neighbours(mem_ctx, samdb, req,
458 reply, base_index,
459 req_src_dsa_guid, nc_list);
460 break;
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));
465 break;
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 */
479 default:
480 DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo info_type %u\n",
481 info_type));
482 status = WERR_INVALID_LEVEL;
483 break;
486 DONE:
487 /* put the status on the result field of the reply */
488 req->out.result = status;
489 NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo, req);
490 return NT_STATUS_OK;