s4-drs: DsReplGetInfo() for DS_REPL_INFO_REPSTO infoType
[ira/wip.git] / source4 / dsdb / kcc / kcc_drs_replica_info.c
1 /*
2  Unix SMB/CIFS implementation.
3
4  DRS Replica Information
5
6  Copyright (C) Erick Nogueira do Nascimento 2009
7
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.
12
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.
17
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/>.
20
21  */
22
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"
36
37
38 /*
39   get cursors info for a specified DN
40 */
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)
46 {
47         int ret;
48
49         if (!ldb_dn_validate(dn)) {
50                 return WERR_INVALID_PARAMETER;
51         }
52         reply->cursors = talloc(mem_ctx, struct drsuapi_DsReplicaCursorCtr);
53         W_ERROR_HAVE_NO_MEMORY(reply->cursors);
54
55         reply->cursors->reserved = 0;
56
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;
60         }
61         return WERR_OK;
62 }
63
64 /*
65   get cursors2 info for a specified DN
66 */
67 static WERROR kccdrs_replica_get_info_cursors2(TALLOC_CTX *mem_ctx,
68                                                struct ldb_context *samdb,
69                                                struct drsuapi_DsReplicaGetInfo *r,
70                                                union drsuapi_DsReplicaInfo *reply,
71                                                struct ldb_dn *dn)
72 {
73         int ret;
74
75         if (!ldb_dn_validate(dn)) {
76                 return WERR_INVALID_PARAMETER;
77         }
78         reply->cursors2 = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2Ctr);
79         W_ERROR_HAVE_NO_MEMORY(reply->cursors2);
80
81         ret = dsdb_load_udv_v2(samdb, dn, reply->cursors2, &reply->cursors2->array, &reply->cursors2->count);
82         if (ret != LDB_SUCCESS) {
83                 return WERR_DS_DRA_BAD_NC;
84         }
85
86         reply->cursors2->enumeration_context = reply->cursors2->count;
87         return WERR_OK;
88 }
89
90 /*
91   get pending ops info for a specified DN
92 */
93 static WERROR kccdrs_replica_get_info_pending_ops(TALLOC_CTX *mem_ctx,
94                                                   struct ldb_context *samdb,
95                                                   struct drsuapi_DsReplicaGetInfo *r,
96                                                   union drsuapi_DsReplicaInfo *reply,
97                                                   struct ldb_dn *dn)
98 {
99         struct timeval now = timeval_current();
100
101         if (!ldb_dn_validate(dn)) {
102                 return WERR_INVALID_PARAMETER;
103         }
104         reply->pendingops = talloc(mem_ctx, struct drsuapi_DsReplicaOpCtr);
105         W_ERROR_HAVE_NO_MEMORY(reply->pendingops);
106
107         /* claim no pending ops for now */
108         reply->pendingops->time = timeval_to_nttime(&now);
109         reply->pendingops->count = 0;
110         reply->pendingops->array = NULL;
111
112         return WERR_OK;
113 }
114
115
116 struct ncList {
117         struct ldb_dn *dn;
118         struct ncList *prev, *next;
119 };
120
121 struct neighList {
122         struct drsuapi_DsReplicaNeighbour *neigh;
123         struct neighList *prev, *next;
124 };
125
126 static WERROR copy_repsfrom_1_to_2(TALLOC_CTX *mem_ctx,
127                                  struct repsFromTo2 **reps2,
128                                  struct repsFromTo1 *reps1)
129 {
130         struct repsFromTo2* reps;
131
132         reps = talloc_zero(mem_ctx, struct repsFromTo2);
133         W_ERROR_HAVE_NO_MEMORY(reps);
134
135         reps->blobsize = reps1->blobsize;
136         reps->consecutive_sync_failures = reps1->consecutive_sync_failures;
137         reps->last_attempt = reps1->last_attempt;
138         reps->last_success = reps1->last_success;
139         reps->other_info = talloc_zero(mem_ctx, struct repsFromTo2OtherInfo);
140         W_ERROR_HAVE_NO_MEMORY(reps->other_info);
141         reps->other_info->dns_name1 = reps1->other_info->dns_name;
142         reps->replica_flags = reps1->replica_flags;
143         memcpy(reps->schedule, reps1->schedule, sizeof(reps1->schedule));
144         reps->reserved = reps1->reserved;
145         reps->highwatermark = reps1->highwatermark;
146         reps->source_dsa_obj_guid = reps1->source_dsa_obj_guid;
147         reps->source_dsa_invocation_id = reps1->source_dsa_invocation_id;
148         reps->transport_guid = reps1->transport_guid;
149
150         *reps2 = reps;
151         return WERR_OK;
152 }
153
154 static WERROR fill_neighbor_from_repsFrom(TALLOC_CTX *mem_ctx,
155                                           struct ldb_context *samdb,
156                                           struct ldb_dn *nc_dn,
157                                           struct drsuapi_DsReplicaNeighbour *neigh,
158                                           struct repsFromTo2 *reps_from)
159 {
160         WERROR status;
161         struct ldb_dn *source_dsa_dn;
162         int ret;
163         char *dsa_guid_str;
164         struct ldb_dn *transport_obj_dn = NULL;
165
166         neigh->source_dsa_address = reps_from->other_info->dns_name1;
167         neigh->replica_flags = reps_from->replica_flags;
168         neigh->last_attempt = reps_from->last_attempt;
169         neigh->source_dsa_obj_guid = reps_from->source_dsa_obj_guid;
170
171         dsa_guid_str = GUID_string(mem_ctx, &reps_from->source_dsa_obj_guid);
172         W_ERROR_HAVE_NO_MEMORY(dsa_guid_str);
173         ret = dsdb_find_dn_by_guid(samdb, mem_ctx, dsa_guid_str, &source_dsa_dn);
174
175         if (ret != LDB_SUCCESS) {
176                 DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
177                       dsa_guid_str));
178                 status = WERR_DS_DRA_INTERNAL_ERROR;
179                 goto DONE;
180         }
181
182         neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
183         neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
184
185         if (dsdb_find_guid_by_dn(samdb, nc_dn, &neigh->naming_context_obj_guid)
186                         != LDB_SUCCESS) {
187                 status = WERR_DS_DRA_INTERNAL_ERROR;
188                 goto DONE;
189         }
190
191         if (!GUID_all_zero(&reps_from->transport_guid)) {
192                 char *transp_guid_str = GUID_string(mem_ctx, &reps_from->transport_guid);
193                 W_ERROR_HAVE_NO_MEMORY(transp_guid_str);
194                 if (dsdb_find_dn_by_guid(samdb, mem_ctx, transp_guid_str,
195                                          &transport_obj_dn) != LDB_SUCCESS)
196                 {
197                         status = WERR_DS_DRA_INTERNAL_ERROR;
198                         goto DONE;
199                 }
200         }
201
202         neigh->transport_obj_dn = ldb_dn_get_linearized(transport_obj_dn);
203         neigh->source_dsa_invocation_id = reps_from->source_dsa_invocation_id;
204         neigh->transport_obj_guid = reps_from->transport_guid;
205         neigh->highest_usn = reps_from->highwatermark.highest_usn;
206         neigh->tmp_highest_usn = reps_from->highwatermark.tmp_highest_usn;
207         neigh->last_success = reps_from->last_success;
208         neigh->result_last_attempt = reps_from->result_last_attempt;
209         neigh->consecutive_sync_failures = reps_from->consecutive_sync_failures;
210         neigh->reserved = 0; /* Unused. MUST be 0. */
211
212         /* If everything went fine so far, set the status to OK */
213         status = WERR_OK;
214 DONE:
215         return status;
216 }
217
218 /*
219  * See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
220  * */
221 static WERROR kccdrs_replica_get_info_neighbours(TALLOC_CTX *mem_ctx,
222                                                  struct ldb_context *samdb,
223                                                  struct drsuapi_DsReplicaGetInfo *r,
224                                                  union drsuapi_DsReplicaInfo *reply,
225                                                  int base_index,
226                                                  struct GUID req_src_dsa_guid,
227                                                  struct ncList *nc_list)
228 {
229         WERROR status;
230
231         int i, j, k;
232         struct ldb_dn *nc_dn = NULL;
233         struct ncList *p_nc_list = NULL;
234
235         struct repsFromToBlob *reps_from_blob = NULL;
236         struct repsFromTo2 *reps_from = NULL;
237         uint32_t c_reps_from;
238
239         int i_rep;
240
241         struct neighList *neigh_list = NULL;
242         struct neighList *neigh_elem = NULL;
243
244         struct drsuapi_DsReplicaNeighbour *neigh = NULL;
245
246         i = j = 0;
247         neigh_list = NULL;
248
249         /* foreach nc in ncs */
250         for (p_nc_list = nc_list; p_nc_list != NULL; p_nc_list = p_nc_list->next) {
251
252                 nc_dn = p_nc_list->dn;
253
254                 /* load the nc's repsFromTo blob */
255                 status = dsdb_loadreps(samdb, mem_ctx, nc_dn, "repsFrom",
256                                 &reps_from_blob, &c_reps_from);
257                 if (!W_ERROR_IS_OK(status)) {
258                         status = WERR_DS_DRA_INTERNAL_ERROR;
259                         goto DONE;
260                 }
261
262                 /* foreach r in nc!repsFrom */
263                 for (i_rep = 0; i_rep < c_reps_from; i_rep++) {
264
265                         /* put all info on reps_from */
266                         if (reps_from_blob[i_rep].version == 1) {
267                                 status = copy_repsfrom_1_to_2(mem_ctx, &reps_from,
268                                                               &reps_from_blob[i_rep].ctr.ctr1);
269                                 if (!W_ERROR_IS_OK(status)) {
270                                         goto DONE;
271                                 }
272                         } else { /* reps_from->version == 2 */
273                                 reps_from = &reps_from_blob[i_rep].ctr.ctr2;
274                         }
275
276                         if (GUID_all_zero(&req_src_dsa_guid) ||
277                             GUID_compare(&req_src_dsa_guid, &reps_from->source_dsa_obj_guid) == 0)
278                         {
279
280                                 if (i >= base_index) {
281                                         neigh = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbour);
282                                         W_ERROR_HAVE_NO_MEMORY(neigh);
283
284                                         status = fill_neighbor_from_repsFrom(mem_ctx, samdb,
285                                                                              nc_dn, neigh,
286                                                                              reps_from);
287                                         if (!W_ERROR_IS_OK(status)) {
288                                                 goto DONE;
289                                         }
290
291                                         /* append the neighbor to neigh_list */
292                                         neigh_elem = talloc_zero(mem_ctx, struct neighList);
293                                         W_ERROR_HAVE_NO_MEMORY(neigh_elem);
294                                         neigh_elem->neigh = neigh;
295                                         DLIST_ADD_END(neigh_list, neigh_elem, struct neighList*);
296
297                                         j++;
298                                 }
299
300                                 i++;
301                         }
302                 }
303         }
304
305         /* put all neighbours on neigh_list on reply->neighbours->array */
306         reply->neighbours = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbourCtr);
307         W_ERROR_HAVE_NO_MEMORY(reply->neighbours);
308
309         reply->neighbours->count = j;
310         reply->neighbours->reserved = 0;
311         reply->neighbours->array = talloc_array(mem_ctx, struct drsuapi_DsReplicaNeighbour, j);
312         W_ERROR_HAVE_NO_MEMORY(reply->neighbours->array);
313
314         for (k = 0; neigh_list != NULL; neigh_list = neigh_list->next, k++) {
315                 reply->neighbours->array[k] = *neigh_list->neigh;
316         }
317
318         /* If everything went fine so far, set the status to OK */
319         status = WERR_OK;
320 DONE:
321         return status;
322 }
323
324 static WERROR fill_neighbor_from_repsTo(TALLOC_CTX *mem_ctx,
325                                         struct ldb_context *samdb, struct ldb_dn *nc_dn,
326                                         struct drsuapi_DsReplicaNeighbour *neigh,
327                                         struct repsFromTo2 *reps_to)
328 {
329         WERROR status;
330         char *dsa_guid_str;
331         int ret;
332         struct ldb_dn *source_dsa_dn;
333
334         neigh->source_dsa_address = reps_to->other_info->dns_name1;
335         neigh->replica_flags = reps_to->replica_flags;
336         neigh->last_attempt = reps_to->last_attempt;
337         neigh->source_dsa_obj_guid = reps_to->source_dsa_obj_guid;
338
339         dsa_guid_str = GUID_string(mem_ctx, &reps_to->source_dsa_obj_guid);
340         W_ERROR_HAVE_NO_MEMORY(dsa_guid_str);
341
342         ret = dsdb_find_dn_by_guid(samdb, mem_ctx, dsa_guid_str, &source_dsa_dn);
343         if (ret != LDB_SUCCESS) {
344                 DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
345                          dsa_guid_str));
346                 status = WERR_DS_DRA_INTERNAL_ERROR;
347                 goto DONE;
348         }
349
350         neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
351         neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
352
353         ret = dsdb_find_guid_by_dn(samdb, nc_dn,
354                         &neigh->naming_context_obj_guid);
355         if (ret != LDB_SUCCESS) {
356                 DEBUG(0,(__location__ ": Failed to find GUID for DN %s\n",
357                          ldb_dn_get_linearized(nc_dn)));
358                 status = WERR_DS_DRA_INTERNAL_ERROR;
359                 goto DONE;
360         }
361
362         /* If everything went fine so far, set the status to OK */
363         status = WERR_OK;
364         DONE: return status;
365 }
366
367 static WERROR kccdrs_replica_get_info_repsto(TALLOC_CTX *mem_ctx,
368                 struct ldb_context *samdb, struct drsuapi_DsReplicaGetInfo *r,
369                 union drsuapi_DsReplicaInfo *reply, int base_index,
370                 struct GUID req_src_dsa_guid, struct ncList *nc_list)
371 {
372         WERROR status;
373         int i, j, k;
374         struct ncList *p_nc_list = NULL;
375         struct ldb_dn *nc_dn = NULL;
376         struct repsFromToBlob *reps_to_blob;
377         struct repsFromTo2 *reps_to;
378         uint32_t c_reps_to;
379         int i_rep;
380         struct drsuapi_DsReplicaNeighbour *neigh;
381         struct neighList *neigh_list = NULL;
382         struct neighList *neigh_elem = NULL;
383
384         i = j = 0;
385
386         /* foreach nc in ncs */
387         for (p_nc_list = nc_list; p_nc_list != NULL; p_nc_list = p_nc_list->next) {
388
389                 nc_dn = p_nc_list->dn;
390
391                 status = dsdb_loadreps(samdb, mem_ctx, nc_dn, "repsTo",
392                                 &reps_to_blob, &c_reps_to);
393                 if (!W_ERROR_IS_OK(status)) {
394                         status = WERR_DS_DRA_INTERNAL_ERROR;
395                         goto DONE;
396                 }
397
398                 /* foreach r in nc!repsTo */
399                 for (i_rep = 0; i_rep < c_reps_to; i_rep++) {
400
401                         /* put all info on reps_from */
402                         if (reps_to_blob[i_rep].version == 1) {
403                                 status = copy_repsfrom_1_to_2(mem_ctx,
404                                                               &reps_to,
405                                                               &reps_to_blob[i_rep].ctr.ctr1);
406                                 if (!W_ERROR_IS_OK(status)) {
407                                         goto DONE;
408                                 }
409                         } else { /* reps_from->version == 2 */
410                                 reps_to = &reps_to_blob[i_rep].ctr.ctr2;
411                         }
412
413                         if (i >= base_index) {
414                                 neigh = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbour);
415                                 W_ERROR_HAVE_NO_MEMORY(neigh);
416
417                                 status = fill_neighbor_from_repsTo(mem_ctx,
418                                                                    samdb, nc_dn,
419                                                                    neigh, reps_to);
420                                 if (!W_ERROR_IS_OK(status)) {
421                                         goto DONE;
422                                 }
423
424                                 /* append the neighbor to neigh_list */
425                                 neigh_elem = talloc_zero(mem_ctx, struct neighList);
426                                 W_ERROR_HAVE_NO_MEMORY(neigh_elem);
427                                 neigh_elem->neigh = neigh;
428                                 DLIST_ADD_END(neigh_list, neigh_elem, struct neighList*);
429
430                                 j++;
431                         }
432
433                         i++;
434                 }
435         }
436
437         /* put all neighbours on neigh_list on reply->neighbours->array */
438         reply->neighbours = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbourCtr);
439         W_ERROR_HAVE_NO_MEMORY(reply->neighbours);
440
441         reply->neighbours->count = j;
442         reply->neighbours->reserved = 0;
443         reply->neighbours->array = talloc_array(mem_ctx, struct drsuapi_DsReplicaNeighbour, j);
444         W_ERROR_HAVE_NO_MEMORY(reply->neighbours->array);
445
446         for (k = 0; neigh_list != NULL; neigh_list = neigh_list->next, k++) {
447                 reply->neighbours->array[k] = *neigh_list->neigh;
448         }
449
450         /* If everything went fine so far, set the status to OK */
451         status = WERR_OK;
452         DONE: return status;
453 }
454
455 static WERROR get_master_ncs(TALLOC_CTX *mem_ctx, struct ldb_context *samdb,
456                              const char *ntds_guid_str, struct ncList **master_nc_list)
457 {
458         WERROR status;
459         const char *attrs[] = { "hasMasterNCs", NULL };
460         struct ldb_result *res;
461         struct ncList *nc_list = NULL;
462         struct ncList *nc_list_elem;
463         int ret;
464         int i;
465         char *nc_str;
466
467         ret = ldb_search(samdb, mem_ctx, &res, ldb_get_config_basedn(samdb),
468                         LDB_SCOPE_DEFAULT, attrs, "(objectguid=%s)", ntds_guid_str);
469
470         if (ret != LDB_SUCCESS) {
471                 DEBUG(0,(__location__ ": Failed objectguid search - %s\n", ldb_errstring(samdb)));
472                 status = WERR_INTERNAL_ERROR;
473                 goto DONE;
474         }
475
476         if (res->count == 0) {
477                 DEBUG(0,(__location__ ": Failed: objectguid=%s not found\n", ntds_guid_str));
478                 status = WERR_INTERNAL_ERROR;
479                 goto DONE;
480         }
481
482         for (i = 0; i < res->count; i++) {
483
484                 struct ldb_message_element *msg_elem = ldb_msg_find_element(
485                                 res->msgs[i], "hasMasterNCs");
486                 int k;
487
488                 if (!msg_elem || msg_elem->num_values == 0) {
489                         DEBUG(0,(__location__ ": Failed: Attribute hasMasterNCs not found - %s\n",
490                               ldb_errstring(samdb)));
491                         status = WERR_INTERNAL_ERROR;
492                         goto DONE;
493                 }
494
495                 for (k = 0; k < msg_elem->num_values; k++) {
496                         int len = msg_elem->values[k].length;
497
498                         /* copy the string on msg_elem->values[k]->data to nc_str */
499                         nc_str = talloc_array(mem_ctx, char, len);
500                         W_ERROR_HAVE_NO_MEMORY(nc_str);
501                         memcpy(nc_str, msg_elem->values[k].data, len);
502                         nc_str[len] = '\0';
503
504                         nc_list_elem = talloc_zero(mem_ctx, struct ncList);
505                         W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
506                         nc_list_elem->dn = ldb_dn_new(mem_ctx, samdb, nc_str);
507                         W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
508                         DLIST_ADD(nc_list, nc_list_elem);
509                 }
510
511         }
512
513         *master_nc_list = nc_list;
514         /* If everything went fine so far, set the status to OK */
515         status = WERR_OK;
516 DONE:
517         return status;
518 }
519
520 NTSTATUS kccdrs_replica_get_info(struct irpc_message *msg,
521                                  struct drsuapi_DsReplicaGetInfo *req)
522 {
523         WERROR status;
524
525         struct drsuapi_DsReplicaGetInfoRequest1 *req1;
526         struct drsuapi_DsReplicaGetInfoRequest2 *req2;
527         enum drsuapi_DsReplicaInfoType info_type, *tmp_p_info_type;
528
529         int base_index;
530         union drsuapi_DsReplicaInfo *reply;
531
532         struct GUID req_src_dsa_guid;
533         const char *object_dn = NULL;
534         struct ldb_dn *nc_dn = NULL;
535         struct ncList *nc_list = NULL, *nc_list_elem = NULL;
536
537         struct kccsrv_service *service;
538         struct ldb_context *samdb;
539         TALLOC_CTX *mem_ctx;
540
541         service = talloc_get_type(msg->private_data, struct kccsrv_service);
542         samdb = service->samdb;
543         mem_ctx = talloc_new(msg);
544         NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
545
546         NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo, req);
547
548         /* check request version */
549         if (req->in.level != DRSUAPI_DS_REPLICA_GET_INFO &&
550             req->in.level != DRSUAPI_DS_REPLICA_GET_INFO2)
551         {
552                 DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo level %u\n",
553                          req->in.level));
554                 status = WERR_REVISION_MISMATCH;
555                 goto DONE;
556         }
557
558         if (req->in.level == DRSUAPI_DS_REPLICA_GET_INFO) {
559                 req1 = &req->in.req->req1;
560                 base_index = 0;
561                 info_type = req1->info_type;
562                 object_dn = req1->object_dn;
563                 req_src_dsa_guid = req1->guid1;
564
565         } else { /* r->in.level == DRSUAPI_DS_REPLICA_GET_INFO2 */
566                 req2 = &req->in.req->req2;
567                 if (req2->enumeration_context == 0xffffffff) {
568                         /* no more data is available */
569                         status = WERR_NO_MORE_ITEMS; /* on MS-DRSR it is ERROR_NO_MORE_ITEMS */
570                         goto DONE;
571                 }
572
573                 base_index = req2->enumeration_context;
574                 info_type = req2->info_type;
575                 object_dn = req2->object_dn;
576                 req_src_dsa_guid = req2->guid1;
577         }
578
579         /* TODO: Perform the necessary access permission checking here according to the infoType requested */
580         switch (info_type) {
581         case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
582         case DRSUAPI_DS_REPLICA_INFO_CURSORS:
583         case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA:
584         case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES:
585         case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES:
586         case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS:
587         case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA:
588         case DRSUAPI_DS_REPLICA_INFO_CURSORS2:
589         case DRSUAPI_DS_REPLICA_INFO_CURSORS3:
590         case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2:
591         case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2:
592         case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02:
593         case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04:
594         case DRSUAPI_DS_REPLICA_INFO_CURSORS05:
595         case DRSUAPI_DS_REPLICA_INFO_06:
596                 break;
597         default:
598                 DEBUG(0,(__location__ ": infoType %u requested is invalid.", (unsigned)info_type));
599                 status = WERR_INVALID_PARAMETER; /* infoType is invalid */
600                 goto DONE;
601         }
602
603         /* allocate the reply and fill in some fields */
604         reply = talloc_zero(mem_ctx, union drsuapi_DsReplicaInfo);
605         NT_STATUS_HAVE_NO_MEMORY(reply);
606         req->out.info = reply;
607         tmp_p_info_type = talloc(mem_ctx, enum drsuapi_DsReplicaInfoType);
608         NT_STATUS_HAVE_NO_MEMORY(tmp_p_info_type);
609         *tmp_p_info_type = info_type;
610         req->out.info_type = tmp_p_info_type;
611
612         /* Based on the infoType requested, retrieve the corresponding
613          * information and construct the response message */
614         switch (info_type) {
615
616         case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
617         case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02: /* On MS-DRSR it is DS_REPL_INFO_REPSTO */
618                 if (object_dn != NULL) { /* ncs := { object_dn } */
619                         nc_list = NULL;
620                         nc_dn = ldb_dn_new(mem_ctx, samdb, object_dn);
621                         nc_list_elem = talloc_zero(mem_ctx, struct ncList);
622                         NT_STATUS_HAVE_NO_MEMORY(nc_list_elem);
623                         nc_list_elem->dn = nc_dn;
624                         DLIST_ADD_END(nc_list, nc_list_elem, struct ncList*);
625
626                 } else {
627                         /* ncs := getNCs() from ldb database.
628                          * getNCs() must return an array containing
629                          * the DSNames of all NCs hosted by this
630                          * server.
631                          */
632                         char *ntds_guid_str = GUID_string(mem_ctx, &service->ntds_guid);
633                         NT_STATUS_HAVE_NO_MEMORY(ntds_guid_str);
634                         status = get_master_ncs(mem_ctx, samdb, ntds_guid_str, &nc_list);
635                         if (!W_ERROR_IS_OK(status)) {
636                                 goto DONE;
637                         }
638                 }
639
640                 if (info_type == DRSUAPI_DS_REPLICA_INFO_NEIGHBORS) {
641                         status = kccdrs_replica_get_info_neighbours(mem_ctx, samdb, req,
642                                                                     reply, base_index,
643                                                                     req_src_dsa_guid, nc_list);
644                 } else { /* info_type == DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02 */
645                         status = kccdrs_replica_get_info_repsto(mem_ctx, samdb, req,
646                                                                 reply, base_index,
647                                                                 req_src_dsa_guid, nc_list);
648                 }
649
650                 break;
651
652         case DRSUAPI_DS_REPLICA_INFO_CURSORS: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_FOR_NC */
653                 status = kccdrs_replica_get_info_cursors(mem_ctx, samdb, req, reply,
654                                                          ldb_dn_new(mem_ctx, samdb, object_dn));
655                 break;
656         case DRSUAPI_DS_REPLICA_INFO_CURSORS2: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_2_FOR_NC */
657                 status = kccdrs_replica_get_info_cursors2(mem_ctx, samdb, req, reply,
658                                                           ldb_dn_new(mem_ctx, samdb, object_dn));
659                 break;
660         case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS: /* On MS-DRSR it is DS_REPL_INFO_PENDING_OPS */
661                 status = kccdrs_replica_get_info_pending_ops(mem_ctx, samdb, req, reply,
662                                                              ldb_dn_new(mem_ctx, samdb, object_dn));
663                 break;
664
665         case DRSUAPI_DS_REPLICA_INFO_CURSORS3: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
666         case DRSUAPI_DS_REPLICA_INFO_CURSORS05: /* On MS-DRSR it is DS_REPL_INFO_UPTODATE_VECTOR_V1 */
667         case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
668         case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
669         case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_ATTR_VALUE */
670         case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2: /* On MS-DRSR it is DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE */
671         case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES: /* On MS-DRSR it is DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES */
672         case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES: /* On MS-DRSR it is DS_REPL_INFO_KCC_LINK_FAILURES */
673         case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
674         case DRSUAPI_DS_REPLICA_INFO_06: /* On MS-DRSR it is DS_REPL_INFO_SERVER_OUTGOING_CALLS */
675         default:
676                 DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo info_type %u\n",
677                          info_type));
678                 status = WERR_INVALID_LEVEL;
679                 break;
680         }
681
682 DONE:
683         /* put the status on the result field of the reply */
684         req->out.result = status;
685         NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo, req);
686         return NT_STATUS_OK;
687 }