s4-drs: DsGetReplInfo() refactoring
[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 struct ncList {
116         struct ldb_dn *dn;
117         struct ncList *prev, *next;
118 };
119
120 /*
121   Fill 'master_nc_list' with the master ncs hosted by this server
122 */
123 static WERROR get_master_ncs(TALLOC_CTX *mem_ctx, struct ldb_context *samdb,
124                              const char *ntds_guid_str, struct ncList **master_nc_list)
125 {
126         const char *attrs[] = { "hasMasterNCs", NULL };
127         struct ldb_result *res;
128         struct ncList *nc_list = NULL;
129         struct ncList *nc_list_elem;
130         int ret;
131         int i;
132         char *nc_str;
133
134         ret = ldb_search(samdb, mem_ctx, &res, ldb_get_config_basedn(samdb),
135                         LDB_SCOPE_DEFAULT, attrs, "(objectguid=%s)", ntds_guid_str);
136
137         if (ret != LDB_SUCCESS) {
138                 DEBUG(0,(__location__ ": Failed objectguid search - %s\n", ldb_errstring(samdb)));
139                 return WERR_INTERNAL_ERROR;
140         }
141
142         if (res->count == 0) {
143                 DEBUG(0,(__location__ ": Failed: objectguid=%s not found\n", ntds_guid_str));
144                 return WERR_INTERNAL_ERROR;
145         }
146
147         for (i = 0; i < res->count; i++) {
148                 struct ldb_message_element *msg_elem = ldb_msg_find_element(res->msgs[i], "hasMasterNCs");
149                 int k;
150
151                 if (!msg_elem || msg_elem->num_values == 0) {
152                         DEBUG(0,(__location__ ": Failed: Attribute hasMasterNCs not found - %s\n",
153                               ldb_errstring(samdb)));
154                         return WERR_INTERNAL_ERROR;
155                 }
156
157                 for (k = 0; k < msg_elem->num_values; k++) {
158                         int len = msg_elem->values[k].length;
159
160                         /* copy the string on msg_elem->values[k]->data to nc_str */
161                         nc_str = talloc_array(mem_ctx, char, len);
162                         W_ERROR_HAVE_NO_MEMORY(nc_str);
163                         memcpy(nc_str, msg_elem->values[k].data, len);
164                         nc_str[len] = '\0';
165
166                         nc_list_elem = talloc_zero(mem_ctx, struct ncList);
167                         W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
168                         nc_list_elem->dn = ldb_dn_new(mem_ctx, samdb, nc_str);
169                         W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
170                         DLIST_ADD(nc_list, nc_list_elem);
171                 }
172
173         }
174
175         *master_nc_list = nc_list;
176         return WERR_OK;
177 }
178
179 /*
180   Fill 'nc_list' with the ncs list. (MS-DRSR 4.1.13.3)
181   if the object dn is specified, fill 'nc_list' only with this dn
182   otherwise, fill 'nc_list' with all master ncs hosted by this server
183 */
184 static WERROR get_ncs_list(TALLOC_CTX *mem_ctx,
185                 struct ldb_context *samdb,
186                 struct kccsrv_service *service,
187                 const char *object_dn_str,
188                 struct ncList **nc_list)
189 {
190         WERROR status;
191         struct ncList *nc_list_elem;
192         struct ldb_dn *nc_dn;
193
194         if (object_dn_str != NULL) {
195                 /* ncs := { object_dn } */
196                 *nc_list = NULL;
197                 nc_dn = ldb_dn_new(mem_ctx, samdb, object_dn_str);
198                 nc_list_elem = talloc_zero(mem_ctx, struct ncList);
199                 W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
200                 nc_list_elem->dn = nc_dn;
201                 DLIST_ADD_END(*nc_list, nc_list_elem, struct ncList*);
202         } else {
203                 /* ncs := getNCs() from ldb database.
204                  * getNCs() must return an array containing
205                  * the DSNames of all NCs hosted by this
206                  * server.
207                  */
208                 char *ntds_guid_str = GUID_string(mem_ctx, &service->ntds_guid);
209                 W_ERROR_HAVE_NO_MEMORY(ntds_guid_str);
210                 status = get_master_ncs(mem_ctx, samdb, ntds_guid_str, nc_list);
211                 W_ERROR_NOT_OK_RETURN(status);
212         }
213
214         return WERR_OK;
215 }
216
217 /*
218   Copy the fields from 'reps1' to 'reps2', leaving zeroed the fields on
219   'reps2' that aren't available on 'reps1'.
220 */
221 static WERROR copy_repsfrom_1_to_2(TALLOC_CTX *mem_ctx,
222                                  struct repsFromTo2 **reps2,
223                                  struct repsFromTo1 *reps1)
224 {
225         struct repsFromTo2* reps;
226
227         reps = talloc_zero(mem_ctx, struct repsFromTo2);
228         W_ERROR_HAVE_NO_MEMORY(reps);
229
230         reps->blobsize = reps1->blobsize;
231         reps->consecutive_sync_failures = reps1->consecutive_sync_failures;
232         reps->last_attempt = reps1->last_attempt;
233         reps->last_success = reps1->last_success;
234         reps->other_info = talloc_zero(mem_ctx, struct repsFromTo2OtherInfo);
235         W_ERROR_HAVE_NO_MEMORY(reps->other_info);
236         reps->other_info->dns_name1 = reps1->other_info->dns_name;
237         reps->replica_flags = reps1->replica_flags;
238         memcpy(reps->schedule, reps1->schedule, sizeof(reps1->schedule));
239         reps->reserved = reps1->reserved;
240         reps->highwatermark = reps1->highwatermark;
241         reps->source_dsa_obj_guid = reps1->source_dsa_obj_guid;
242         reps->source_dsa_invocation_id = reps1->source_dsa_invocation_id;
243         reps->transport_guid = reps1->transport_guid;
244
245         *reps2 = reps;
246         return WERR_OK;
247 }
248
249 static WERROR fill_neighbor_from_repsFrom(TALLOC_CTX *mem_ctx,
250                                           struct ldb_context *samdb,
251                                           struct ldb_dn *nc_dn,
252                                           struct drsuapi_DsReplicaNeighbour *neigh,
253                                           struct repsFromTo2 *reps_from)
254 {
255         struct ldb_dn *source_dsa_dn;
256         int ret;
257         char *dsa_guid_str;
258         struct ldb_dn *transport_obj_dn = NULL;
259
260         neigh->source_dsa_address = reps_from->other_info->dns_name1;
261         neigh->replica_flags = reps_from->replica_flags;
262         neigh->last_attempt = reps_from->last_attempt;
263         neigh->source_dsa_obj_guid = reps_from->source_dsa_obj_guid;
264
265         dsa_guid_str = GUID_string(mem_ctx, &reps_from->source_dsa_obj_guid);
266         W_ERROR_HAVE_NO_MEMORY(dsa_guid_str);
267         ret = dsdb_find_dn_by_guid(samdb, mem_ctx, dsa_guid_str, &source_dsa_dn);
268
269         if (ret != LDB_SUCCESS) {
270                 DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
271                       dsa_guid_str));
272                 return WERR_DS_DRA_INTERNAL_ERROR;
273         }
274
275         neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
276         neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
277
278         if (dsdb_find_guid_by_dn(samdb, nc_dn, &neigh->naming_context_obj_guid)
279                         != LDB_SUCCESS) {
280                 return WERR_DS_DRA_INTERNAL_ERROR;
281         }
282
283         if (!GUID_all_zero(&reps_from->transport_guid)) {
284                 char *transp_guid_str = GUID_string(mem_ctx, &reps_from->transport_guid);
285                 W_ERROR_HAVE_NO_MEMORY(transp_guid_str);
286                 if (dsdb_find_dn_by_guid(samdb, mem_ctx, transp_guid_str,
287                                          &transport_obj_dn) != LDB_SUCCESS)
288                 {
289                         return WERR_DS_DRA_INTERNAL_ERROR;
290                 }
291         }
292
293         neigh->transport_obj_dn = ldb_dn_get_linearized(transport_obj_dn);
294         neigh->source_dsa_invocation_id = reps_from->source_dsa_invocation_id;
295         neigh->transport_obj_guid = reps_from->transport_guid;
296         neigh->highest_usn = reps_from->highwatermark.highest_usn;
297         neigh->tmp_highest_usn = reps_from->highwatermark.tmp_highest_usn;
298         neigh->last_success = reps_from->last_success;
299         neigh->result_last_attempt = reps_from->result_last_attempt;
300         neigh->consecutive_sync_failures = reps_from->consecutive_sync_failures;
301         neigh->reserved = 0; /* Unused. MUST be 0. */
302
303         return WERR_OK;
304 }
305
306 /*
307   Get the inbound neighbours of this DC
308   See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
309 */
310 static WERROR kccdrs_replica_get_info_neighbours(TALLOC_CTX *mem_ctx,
311                                                  struct kccsrv_service *service,
312                                                  struct ldb_context *samdb,
313                                                  struct drsuapi_DsReplicaGetInfo *r,
314                                                  union drsuapi_DsReplicaInfo *reply,
315                                                  int base_index,
316                                                  struct GUID req_src_dsa_guid,
317                                                  const char *object_dn_str)
318 {
319         WERROR status;
320         int i, j;
321         struct ldb_dn *nc_dn = NULL;
322         struct ncList *p_nc_list = NULL;
323         struct repsFromToBlob *reps_from_blob = NULL;
324         struct repsFromTo2 *reps_from = NULL;
325         uint32_t c_reps_from;
326         int i_rep;
327         struct drsuapi_DsReplicaNeighbour neigh;
328         struct ncList *nc_list = NULL;
329
330         status = get_ncs_list(mem_ctx, samdb, service, object_dn_str, &nc_list);
331         W_ERROR_NOT_OK_RETURN(status);
332
333         i = j = 0;
334
335         reply->neighbours = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbourCtr);
336         W_ERROR_HAVE_NO_MEMORY(reply->neighbours);
337         reply->neighbours->reserved = 0;
338         reply->neighbours->count = 0;
339
340         /* foreach nc in ncs */
341         for (p_nc_list = nc_list; p_nc_list != NULL; p_nc_list = p_nc_list->next) {
342
343                 nc_dn = p_nc_list->dn;
344
345                 /* load the nc's repsFromTo blob */
346                 status = dsdb_loadreps(samdb, mem_ctx, nc_dn, "repsFrom",
347                                 &reps_from_blob, &c_reps_from);
348                 W_ERROR_NOT_OK_RETURN(status);
349
350                 /* foreach r in nc!repsFrom */
351                 for (i_rep = 0; i_rep < c_reps_from; i_rep++) {
352
353                         /* put all info on reps_from */
354                         if (reps_from_blob[i_rep].version == 1) {
355                                 status = copy_repsfrom_1_to_2(mem_ctx, &reps_from,
356                                                               &reps_from_blob[i_rep].ctr.ctr1);
357                                 W_ERROR_NOT_OK_RETURN(status);
358                         } else { /* reps_from->version == 2 */
359                                 reps_from = &reps_from_blob[i_rep].ctr.ctr2;
360                         }
361
362                         if (GUID_all_zero(&req_src_dsa_guid) ||
363                             GUID_compare(&req_src_dsa_guid, &reps_from->source_dsa_obj_guid) == 0)
364                         {
365
366                                 if (i >= base_index) {
367                                         status = fill_neighbor_from_repsFrom(mem_ctx, samdb,
368                                                                              nc_dn, &neigh,
369                                                                              reps_from);
370                                         W_ERROR_NOT_OK_RETURN(status);
371
372                                         /* append the neighbour to the neighbours array */
373                                         reply->neighbours->array = talloc_realloc(mem_ctx,
374                                                                                     reply->neighbours->array,
375                                                                                     struct drsuapi_DsReplicaNeighbour,
376                                                                                     reply->neighbours->count + 1);
377                                         reply->neighbours->array[reply->neighbours->count++] = neigh;
378                                         j++;
379                                 }
380
381                                 i++;
382                         }
383                 }
384         }
385
386         return WERR_OK;
387 }
388
389 static WERROR fill_neighbor_from_repsTo(TALLOC_CTX *mem_ctx,
390                                         struct ldb_context *samdb, struct ldb_dn *nc_dn,
391                                         struct drsuapi_DsReplicaNeighbour *neigh,
392                                         struct repsFromTo2 *reps_to)
393 {
394         char *dsa_guid_str;
395         int ret;
396         struct ldb_dn *source_dsa_dn;
397
398         neigh->source_dsa_address = reps_to->other_info->dns_name1;
399         neigh->replica_flags = reps_to->replica_flags;
400         neigh->last_attempt = reps_to->last_attempt;
401         neigh->source_dsa_obj_guid = reps_to->source_dsa_obj_guid;
402
403         dsa_guid_str = GUID_string(mem_ctx, &reps_to->source_dsa_obj_guid);
404         W_ERROR_HAVE_NO_MEMORY(dsa_guid_str);
405
406         ret = dsdb_find_dn_by_guid(samdb, mem_ctx, dsa_guid_str, &source_dsa_dn);
407         if (ret != LDB_SUCCESS) {
408                 DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
409                          dsa_guid_str));
410                 return WERR_DS_DRA_INTERNAL_ERROR;
411         }
412
413         neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
414         neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
415
416         ret = dsdb_find_guid_by_dn(samdb, nc_dn,
417                         &neigh->naming_context_obj_guid);
418         if (ret != LDB_SUCCESS) {
419                 DEBUG(0,(__location__ ": Failed to find GUID for DN %s\n",
420                          ldb_dn_get_linearized(nc_dn)));
421                 return WERR_DS_DRA_INTERNAL_ERROR;
422         }
423
424         return WERR_OK;
425 }
426
427 /*
428   Get the outbound neighbours of this DC
429   See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_REPSTO
430 */
431 static WERROR kccdrs_replica_get_info_repsto(TALLOC_CTX *mem_ctx,
432                                              struct kccsrv_service *service,
433                                              struct ldb_context *samdb,
434                                              struct drsuapi_DsReplicaGetInfo *r,
435                                              union drsuapi_DsReplicaInfo *reply,
436                                              int base_index,
437                                              struct GUID req_src_dsa_guid,
438                                              const char *object_dn_str)
439 {
440         WERROR status;
441         int i, j;
442         struct ncList *p_nc_list = NULL;
443         struct ldb_dn *nc_dn = NULL;
444         struct repsFromToBlob *reps_to_blob;
445         struct repsFromTo2 *reps_to;
446         uint32_t c_reps_to;
447         int i_rep;
448         struct drsuapi_DsReplicaNeighbour neigh;
449         struct ncList *nc_list = NULL;
450
451         status = get_ncs_list(mem_ctx, samdb, service, object_dn_str, &nc_list);
452         W_ERROR_NOT_OK_RETURN(status);
453
454         i = j = 0;
455
456         reply->neighbours02 = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbourCtr);
457         W_ERROR_HAVE_NO_MEMORY(reply->neighbours02);
458         reply->neighbours02->reserved = 0;
459         reply->neighbours02->count = 0;
460
461         /* foreach nc in ncs */
462         for (p_nc_list = nc_list; p_nc_list != NULL; p_nc_list = p_nc_list->next) {
463
464                 nc_dn = p_nc_list->dn;
465
466                 status = dsdb_loadreps(samdb, mem_ctx, nc_dn, "repsTo",
467                                 &reps_to_blob, &c_reps_to);
468                 W_ERROR_NOT_OK_RETURN(status);
469
470                 /* foreach r in nc!repsTo */
471                 for (i_rep = 0; i_rep < c_reps_to; i_rep++) {
472
473                         /* put all info on reps_to */
474                         if (reps_to_blob[i_rep].version == 1) {
475                                 status = copy_repsfrom_1_to_2(mem_ctx,
476                                                               &reps_to,
477                                                               &reps_to_blob[i_rep].ctr.ctr1);
478                                 W_ERROR_NOT_OK_RETURN(status);
479                         } else { /* reps_to->version == 2 */
480                                 reps_to = &reps_to_blob[i_rep].ctr.ctr2;
481                         }
482
483                         if (i >= base_index) {
484                                 status = fill_neighbor_from_repsTo(mem_ctx,
485                                                                    samdb, nc_dn,
486                                                                    &neigh, reps_to);
487                                 W_ERROR_NOT_OK_RETURN(status);
488
489                                 /* append the neighbour to the neighbours array */
490                                 reply->neighbours02->array = talloc_realloc(mem_ctx,
491                                                                             reply->neighbours02->array,
492                                                                             struct drsuapi_DsReplicaNeighbour,
493                                                                             reply->neighbours02->count + 1);
494                                 reply->neighbours02->array[reply->neighbours02->count++] = neigh;
495                                 j++;
496                         }
497                         i++;
498                 }
499         }
500
501         return WERR_OK;
502 }
503
504 NTSTATUS kccdrs_replica_get_info(struct irpc_message *msg,
505                                  struct drsuapi_DsReplicaGetInfo *req)
506 {
507         WERROR status;
508         struct drsuapi_DsReplicaGetInfoRequest1 *req1;
509         struct drsuapi_DsReplicaGetInfoRequest2 *req2;
510         int base_index;
511         union drsuapi_DsReplicaInfo *reply;
512         struct GUID req_src_dsa_guid;
513         const char *object_dn_str = NULL;
514         struct kccsrv_service *service;
515         struct ldb_context *samdb;
516         TALLOC_CTX *mem_ctx;
517         enum drsuapi_DsReplicaInfoType info_type;
518
519         service = talloc_get_type(msg->private_data, struct kccsrv_service);
520         samdb = service->samdb;
521         mem_ctx = talloc_new(msg);
522         NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
523
524         NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo, req);
525
526         /* check request version */
527         if (req->in.level != DRSUAPI_DS_REPLICA_GET_INFO &&
528             req->in.level != DRSUAPI_DS_REPLICA_GET_INFO2)
529         {
530                 DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo level %u\n",
531                          req->in.level));
532                 status = WERR_REVISION_MISMATCH;
533                 goto done;
534         }
535
536         if (req->in.level == DRSUAPI_DS_REPLICA_GET_INFO) {
537                 req1 = &req->in.req->req1;
538                 base_index = 0;
539                 info_type = req1->info_type;
540                 object_dn_str = req1->object_dn;
541                 req_src_dsa_guid = req1->guid1;
542
543         } else { /* r->in.level == DRSUAPI_DS_REPLICA_GET_INFO2 */
544                 req2 = &req->in.req->req2;
545                 if (req2->enumeration_context == 0xffffffff) {
546                         /* no more data is available */
547                         status = WERR_NO_MORE_ITEMS; /* on MS-DRSR it is ERROR_NO_MORE_ITEMS */
548                         goto done;
549                 }
550
551                 base_index = req2->enumeration_context;
552                 info_type = req2->info_type;
553                 object_dn_str = req2->object_dn;
554                 req_src_dsa_guid = req2->guid1;
555         }
556
557         /* allocate the reply and fill in some fields */
558         reply = talloc_zero(mem_ctx, union drsuapi_DsReplicaInfo);
559         NT_STATUS_HAVE_NO_MEMORY(reply);
560         req->out.info = reply;
561         req->out.info_type = talloc(mem_ctx, enum drsuapi_DsReplicaInfoType);
562         NT_STATUS_HAVE_NO_MEMORY(req->out.info_type);
563         *req->out.info_type = info_type;
564
565         /* Based on the infoType requested, retrieve the corresponding
566          * information and construct the response message */
567         switch (info_type) {
568
569         case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
570                 status = kccdrs_replica_get_info_neighbours(mem_ctx, service, samdb, req,
571                                                             reply, base_index, req_src_dsa_guid,
572                                                             object_dn_str);
573                 break;
574         case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02: /* On MS-DRSR it is DS_REPL_INFO_REPSTO */
575                 status = kccdrs_replica_get_info_repsto(mem_ctx, service, samdb, req,
576                                                         reply, base_index, req_src_dsa_guid,
577                                                         object_dn_str);
578                 break;
579         case DRSUAPI_DS_REPLICA_INFO_CURSORS: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_FOR_NC */
580                 status = kccdrs_replica_get_info_cursors(mem_ctx, samdb, req, reply,
581                                                          ldb_dn_new(mem_ctx, samdb, object_dn_str));
582                 break;
583         case DRSUAPI_DS_REPLICA_INFO_CURSORS2: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_2_FOR_NC */
584                 status = kccdrs_replica_get_info_cursors2(mem_ctx, samdb, req, reply,
585                                                           ldb_dn_new(mem_ctx, samdb, object_dn_str));
586                 break;
587         case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS: /* On MS-DRSR it is DS_REPL_INFO_PENDING_OPS */
588                 status = kccdrs_replica_get_info_pending_ops(mem_ctx, samdb, req, reply,
589                                                              ldb_dn_new(mem_ctx, samdb, object_dn_str));
590                 break;
591
592         case DRSUAPI_DS_REPLICA_INFO_CURSORS3: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
593         case DRSUAPI_DS_REPLICA_INFO_CURSORS05: /* On MS-DRSR it is DS_REPL_INFO_UPTODATE_VECTOR_V1 */
594         case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
595         case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
596         case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_ATTR_VALUE */
597         case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2: /* On MS-DRSR it is DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE */
598         case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES: /* On MS-DRSR it is DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES */
599         case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES: /* On MS-DRSR it is DS_REPL_INFO_KCC_LINK_FAILURES */
600         case DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
601         case DRSUAPI_DS_REPLICA_INFO_06: /* On MS-DRSR it is DS_REPL_INFO_SERVER_OUTGOING_CALLS */
602         default:
603                 DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo info_type %u\n",
604                          info_type));
605                 status = WERR_INVALID_LEVEL;
606                 break;
607         }
608
609 done:
610         /* put the status on the result field of the reply */
611         req->out.result = status;
612         NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo, req);
613         return NT_STATUS_OK;
614 }