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