Finish removal of iconv_convenience in public API's.
[kai/samba.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-2010
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 "dsdb/common/proto.h"
26 #include "auth/auth.h"
27 #include "smbd/service.h"
28 #include "lib/events/events.h"
29 #include "lib/messaging/irpc.h"
30 #include "dsdb/kcc/kcc_service.h"
31 #include "lib/ldb/include/ldb_errors.h"
32 #include "../lib/util/dlinklist.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "librpc/gen_ndr/ndr_drsuapi.h"
35 #include "librpc/gen_ndr/ndr_drsblobs.h"
36 #include "param/param.h"
37 #include "dsdb/common/util.h"
38
39
40 /*
41    get the stamp values for the linked attribute 'linked_attr_name' of the object 'dn'
42 */
43 static WERROR get_linked_attribute_value_stamp(TALLOC_CTX *mem_ctx, struct ldb_context *samdb,
44                                        struct ldb_dn *dn, const char *linked_attr_name,
45                                        uint32_t *attr_version, NTTIME *attr_change_time, uint32_t *attr_orig_usn)
46 {
47         struct ldb_result *res;
48         int ret;
49         const char *attrs[2];
50         struct ldb_dn *attr_ext_dn;
51         NTSTATUS ntstatus;
52
53         attrs[0] = linked_attr_name;
54         attrs[1] = NULL;
55
56         ret = dsdb_search_dn(samdb, mem_ctx, &res, dn, attrs,
57                              DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_REVEAL_INTERNALS);
58         if (ret != LDB_SUCCESS) {
59                 DEBUG(0, (__location__ ": Failed search for attribute %s on %s",
60                                 linked_attr_name, ldb_dn_get_linearized(dn)));
61                 return WERR_INTERNAL_ERROR;
62         }
63
64         attr_ext_dn = ldb_msg_find_attr_as_dn(samdb, mem_ctx, res->msgs[0], linked_attr_name);
65         if (!attr_ext_dn) {
66                 DEBUG(0, (__location__ ": Failed search for attribute %s on %s",
67                                 linked_attr_name, ldb_dn_get_linearized(dn)));
68                 return WERR_INTERNAL_ERROR;
69         }
70
71         DEBUG(0, ("linked_attr_name = %s, attr_ext_dn = %s", linked_attr_name,
72                   ldb_dn_get_extended_linearized(mem_ctx, attr_ext_dn, 1)));
73
74         ntstatus = dsdb_get_extended_dn_uint32(attr_ext_dn, attr_version, "RMD_VERSION");
75         if (!NT_STATUS_IS_OK(ntstatus)) {
76                 DEBUG(0, (__location__ ": Could not extract component %s from dn \"%s\"",
77                                 "RMD_VERSION", ldb_dn_get_extended_linearized(mem_ctx, attr_ext_dn, 1)));
78                 return WERR_INTERNAL_ERROR;
79         }
80
81         ntstatus = dsdb_get_extended_dn_nttime(attr_ext_dn, attr_change_time, "RMD_CHANGETIME");
82         if (!NT_STATUS_IS_OK(ntstatus)) {
83                 DEBUG(0, (__location__ ": Could not extract component %s from dn \"%s\"",
84                                 "RMD_CHANGETIME", ldb_dn_get_extended_linearized(mem_ctx, attr_ext_dn, 1)));
85                 return WERR_INTERNAL_ERROR;
86         }
87
88         ntstatus = dsdb_get_extended_dn_uint32(attr_ext_dn, attr_version, "RMD_ORIGINATING_USN");
89         if (!NT_STATUS_IS_OK(ntstatus)) {
90                 DEBUG(0, (__location__ ": Could not extract component %s from dn \"%s\"",
91                                 "RMD_ORIGINATING_USN", ldb_dn_get_extended_linearized(mem_ctx, attr_ext_dn, 1)));
92                 return WERR_INTERNAL_ERROR;
93         }
94
95         return WERR_OK;
96 }
97
98 static WERROR get_repl_prop_metadata_ctr(TALLOC_CTX *mem_ctx,
99                                          struct ldb_context *samdb,
100                                          struct ldb_dn *dn,
101                                          struct replPropertyMetaDataBlob *obj_metadata_ctr)
102 {
103         int ret;
104         struct ldb_result *res;
105         const char *attrs[] = { "replPropertyMetaData", NULL };
106         const struct ldb_val *omd_value;
107         enum ndr_err_code ndr_err;
108
109         ret = ldb_search(samdb, mem_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
110         if (ret != LDB_SUCCESS || res->count != 1) {
111                 DEBUG(0, (__location__ ": Failed search for replPropertyMetaData attribute on %s",
112                           ldb_dn_get_linearized(dn)));
113                 return WERR_INTERNAL_ERROR;
114         }
115
116         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
117         if (!omd_value) {
118                 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
119                          ldb_dn_get_linearized(dn)));
120                 talloc_free(res);
121                 return WERR_INTERNAL_ERROR;
122         }
123
124         ndr_err = ndr_pull_struct_blob(omd_value, mem_ctx,
125                                         obj_metadata_ctr,
126                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
127         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
128                 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
129                          ldb_dn_get_linearized(dn)));
130                 talloc_free(res);
131                 return WERR_INTERNAL_ERROR;
132         }
133
134         talloc_free(res);
135         return WERR_OK;
136 }
137
138 /*
139   get the DN of the nTDSDSA object from the configuration partition
140   whose invocationId is 'invocation_id'
141   put the value on 'dn_str'
142 */
143 static WERROR get_dn_from_invocation_id(TALLOC_CTX *mem_ctx,
144                                         struct ldb_context *samdb,
145                                         struct GUID *invocation_id,
146                                         const char **dn_str)
147 {
148         char *invocation_id_str;
149         const char *attrs_invocation[] = { NULL };
150         struct ldb_message *msg;
151         int ret;
152
153         invocation_id_str = GUID_string(mem_ctx, invocation_id);
154         W_ERROR_HAVE_NO_MEMORY(invocation_id_str);
155
156         ret = dsdb_search_one(samdb, invocation_id_str, &msg, ldb_get_config_basedn(samdb), LDB_SCOPE_SUBTREE,
157                               attrs_invocation, 0, "(&(objectClass=nTDSDSA)(invocationId=%s))", invocation_id_str);
158         if (ret != LDB_SUCCESS) {
159                 DEBUG(0, (__location__ ": Failed search for the object DN under %s whose invocationId is %s",
160                           invocation_id_str, ldb_dn_get_linearized(ldb_get_config_basedn(samdb))));
161                 talloc_free(invocation_id_str);
162                 return WERR_INTERNAL_ERROR;
163         }
164
165         *dn_str = ldb_dn_alloc_linearized(mem_ctx, msg->dn);
166         talloc_free(invocation_id_str);
167         return WERR_OK;
168 }
169
170 /*
171   get metadata version 2 info for a specified object DN
172 */
173 static WERROR kccdrs_replica_get_info_obj_metadata2(TALLOC_CTX *mem_ctx,
174                                                     struct ldb_context *samdb,
175                                                     struct drsuapi_DsReplicaGetInfo *r,
176                                                     union drsuapi_DsReplicaInfo *reply,
177                                                     struct ldb_dn *dn,
178                                                     uint32_t base_index)
179 {
180         WERROR status;
181         struct replPropertyMetaDataBlob omd_ctr;
182         struct replPropertyMetaData1 *attr;
183         struct drsuapi_DsReplicaObjMetaData2Ctr *metadata2;
184         const struct dsdb_schema *schema;
185
186         uint32_t i, j;
187
188         DEBUG(0, ("kccdrs_replica_get_info_obj_metadata2() called\n"));
189
190         if (!dn) {
191                 return WERR_INVALID_PARAMETER;
192         }
193
194         if (!ldb_dn_validate(dn)) {
195                 return WERR_DS_DRA_BAD_DN;
196         }
197
198         status = get_repl_prop_metadata_ctr(mem_ctx, samdb, dn, &omd_ctr);
199         W_ERROR_NOT_OK_RETURN(status);
200
201         schema = dsdb_get_schema(samdb, reply);
202         if (!schema) {
203                 DEBUG(0,(__location__": Failed to get the schema\n"));
204                 return WERR_INTERNAL_ERROR;
205         }
206
207         reply->objmetadata2 = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjMetaData2Ctr);
208         W_ERROR_HAVE_NO_MEMORY(reply->objmetadata2);
209         metadata2 = reply->objmetadata2;
210         metadata2->enumeration_context = 0;
211
212         /* For each replicated attribute of the object */
213         for (i = 0, j = 0; i < omd_ctr.ctr.ctr1.count; i++) {
214                 const struct dsdb_attribute *schema_attr;
215                 uint32_t attr_version;
216                 NTTIME attr_change_time;
217                 uint32_t attr_originating_usn;
218
219                 /*
220                   attr := attrsSeq[i]
221                   s := AttrStamp(object, attr)
222                 */
223                 /* get a reference to the attribute on 'omd_ctr' */
224                 attr = &omd_ctr.ctr.ctr1.array[j];
225
226                 schema_attr = dsdb_attribute_by_attributeID_id(schema, attr->attid);
227
228                 DEBUG(0, ("attribute_id = %d, attribute_name: %s\n", attr->attid, schema_attr->lDAPDisplayName));
229
230                 /*
231                   if (attr in Link Attributes of object and
232                     dwInVersion = 2 and DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS in msgIn.ulFlags)
233                 */
234                 if (schema_attr &&
235                     schema_attr->linkID != 0 && /* Checks if attribute is a linked attribute */
236                     (schema_attr->linkID % 2) == 0 && /* is it a forward link? only forward links have the LinkValueStamp */
237                     r->in.level == 2 &&
238                     (r->in.req->req2.flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) /* on MS-DRSR it is DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS */
239                 {
240                         /*
241                           ls := LinkValueStamp of the most recent
242                                 value change in object!attr
243                         */
244                         status = get_linked_attribute_value_stamp(mem_ctx, samdb, dn, schema_attr->lDAPDisplayName,
245                                                                   &attr_version, &attr_change_time, &attr_originating_usn);
246                         W_ERROR_NOT_OK_RETURN(status);
247
248                         /*
249                          Aligning to MS-DRSR 4.1.13.3:
250                          's' on the doc is 'attr->originating_change_time' here
251                          'ls' on the doc is 'attr_change_time' here
252                         */
253
254                         /* if (ls is more recent than s (based on order in which the change was applied on server)) then */
255                         if (attr_change_time > attr->originating_change_time) {
256                                 /*
257                                  Improve the stamp with the link value stamp.
258                                   s.dwVersion := ls.dwVersion
259                                   s.timeChanged := ls.timeChanged
260                                   s.uuidOriginating := NULLGUID
261                                   s.usnOriginating := ls.usnOriginating
262                                 */
263                                 attr->version = attr_version;
264                                 attr->originating_change_time = attr_change_time;
265                                 attr->originating_invocation_id = GUID_zero();
266                                 attr->originating_usn = attr_originating_usn;
267                         }
268                 }
269
270                 if (i < base_index) {
271                         continue;
272                 }
273
274                 metadata2->array = talloc_realloc(mem_ctx, metadata2->array,
275                                                   struct drsuapi_DsReplicaObjMetaData2, j + 1);
276                 W_ERROR_HAVE_NO_MEMORY(metadata2->array);
277                 metadata2->array[j].attribute_name = schema_attr->lDAPDisplayName;
278                 metadata2->array[j].local_usn = attr->local_usn;
279                 metadata2->array[j].originating_change_time = attr->originating_change_time;
280                 metadata2->array[j].originating_invocation_id = attr->originating_invocation_id;
281                 metadata2->array[j].originating_usn = attr->originating_usn;
282                 metadata2->array[j].version = attr->version;
283
284                 /*
285                   originating_dsa_dn := GetDNFromInvocationID(originating_invocation_id)
286                   GetDNFromInvocationID() should return the DN of the nTDSDSAobject that has the specified invocation ID
287                   See MS-DRSR 4.1.13.3 and 4.1.13.2.1
288                 */
289                 status = get_dn_from_invocation_id(mem_ctx, samdb,
290                                                    &attr->originating_invocation_id,
291                                                    &metadata2->array[j].originating_dsa_dn);
292                 W_ERROR_NOT_OK_RETURN(status);
293                 j++;
294                 metadata2->count = j;
295
296         }
297
298         return WERR_OK;
299 }
300
301 /*
302   get cursors info for a specified DN
303 */
304 static WERROR kccdrs_replica_get_info_cursors(TALLOC_CTX *mem_ctx,
305                                               struct ldb_context *samdb,
306                                               struct drsuapi_DsReplicaGetInfo *r,
307                                               union drsuapi_DsReplicaInfo *reply,
308                                               struct ldb_dn *dn)
309 {
310         int ret;
311
312         if (!ldb_dn_validate(dn)) {
313                 return WERR_INVALID_PARAMETER;
314         }
315         reply->cursors = talloc(mem_ctx, struct drsuapi_DsReplicaCursorCtr);
316         W_ERROR_HAVE_NO_MEMORY(reply->cursors);
317
318         reply->cursors->reserved = 0;
319
320         ret = dsdb_load_udv_v1(samdb, dn, reply->cursors, &reply->cursors->array, &reply->cursors->count);
321         if (ret != LDB_SUCCESS) {
322                 return WERR_DS_DRA_BAD_NC;
323         }
324         return WERR_OK;
325 }
326
327 /*
328   get cursors2 info for a specified DN
329 */
330 static WERROR kccdrs_replica_get_info_cursors2(TALLOC_CTX *mem_ctx,
331                                                struct ldb_context *samdb,
332                                                struct drsuapi_DsReplicaGetInfo *r,
333                                                union drsuapi_DsReplicaInfo *reply,
334                                                struct ldb_dn *dn)
335 {
336         int ret;
337
338         if (!ldb_dn_validate(dn)) {
339                 return WERR_INVALID_PARAMETER;
340         }
341         reply->cursors2 = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2Ctr);
342         W_ERROR_HAVE_NO_MEMORY(reply->cursors2);
343
344         ret = dsdb_load_udv_v2(samdb, dn, reply->cursors2, &reply->cursors2->array, &reply->cursors2->count);
345         if (ret != LDB_SUCCESS) {
346                 return WERR_DS_DRA_BAD_NC;
347         }
348
349         reply->cursors2->enumeration_context = reply->cursors2->count;
350         return WERR_OK;
351 }
352
353 /*
354   get pending ops info for a specified DN
355 */
356 static WERROR kccdrs_replica_get_info_pending_ops(TALLOC_CTX *mem_ctx,
357                                                   struct ldb_context *samdb,
358                                                   struct drsuapi_DsReplicaGetInfo *r,
359                                                   union drsuapi_DsReplicaInfo *reply,
360                                                   struct ldb_dn *dn)
361 {
362         struct timeval now = timeval_current();
363
364         if (!ldb_dn_validate(dn)) {
365                 return WERR_INVALID_PARAMETER;
366         }
367         reply->pendingops = talloc(mem_ctx, struct drsuapi_DsReplicaOpCtr);
368         W_ERROR_HAVE_NO_MEMORY(reply->pendingops);
369
370         /* claim no pending ops for now */
371         reply->pendingops->time = timeval_to_nttime(&now);
372         reply->pendingops->count = 0;
373         reply->pendingops->array = NULL;
374
375         return WERR_OK;
376 }
377
378 struct ncList {
379         struct ldb_dn *dn;
380         struct ncList *prev, *next;
381 };
382
383 /*
384   Fill 'master_nc_list' with the master ncs hosted by this server
385 */
386 static WERROR get_master_ncs(TALLOC_CTX *mem_ctx, struct ldb_context *samdb,
387                              const char *ntds_guid_str, struct ncList **master_nc_list)
388 {
389         const char *attrs[] = { "hasMasterNCs", NULL };
390         struct ldb_result *res;
391         struct ncList *nc_list = NULL;
392         struct ncList *nc_list_elem;
393         int ret;
394         unsigned int i;
395         char *nc_str;
396
397         ret = ldb_search(samdb, mem_ctx, &res, ldb_get_config_basedn(samdb),
398                         LDB_SCOPE_DEFAULT, attrs, "(objectguid=%s)", ntds_guid_str);
399
400         if (ret != LDB_SUCCESS) {
401                 DEBUG(0,(__location__ ": Failed objectguid search - %s\n", ldb_errstring(samdb)));
402                 return WERR_INTERNAL_ERROR;
403         }
404
405         if (res->count == 0) {
406                 DEBUG(0,(__location__ ": Failed: objectguid=%s not found\n", ntds_guid_str));
407                 return WERR_INTERNAL_ERROR;
408         }
409
410         for (i = 0; i < res->count; i++) {
411                 struct ldb_message_element *msg_elem = ldb_msg_find_element(res->msgs[i], "hasMasterNCs");
412                 unsigned int k;
413
414                 if (!msg_elem || msg_elem->num_values == 0) {
415                         DEBUG(0,(__location__ ": Failed: Attribute hasMasterNCs not found - %s\n",
416                               ldb_errstring(samdb)));
417                         return WERR_INTERNAL_ERROR;
418                 }
419
420                 for (k = 0; k < msg_elem->num_values; k++) {
421                         int len = msg_elem->values[k].length;
422
423                         /* copy the string on msg_elem->values[k]->data to nc_str */
424                         nc_str = talloc_array(mem_ctx, char, len);
425                         W_ERROR_HAVE_NO_MEMORY(nc_str);
426                         memcpy(nc_str, msg_elem->values[k].data, len);
427                         nc_str[len] = '\0';
428
429                         nc_list_elem = talloc_zero(mem_ctx, struct ncList);
430                         W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
431                         nc_list_elem->dn = ldb_dn_new(mem_ctx, samdb, nc_str);
432                         W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
433                         DLIST_ADD(nc_list, nc_list_elem);
434                 }
435
436         }
437
438         *master_nc_list = nc_list;
439         return WERR_OK;
440 }
441
442 /*
443   Fill 'nc_list' with the ncs list. (MS-DRSR 4.1.13.3)
444   if the object dn is specified, fill 'nc_list' only with this dn
445   otherwise, fill 'nc_list' with all master ncs hosted by this server
446 */
447 static WERROR get_ncs_list(TALLOC_CTX *mem_ctx,
448                 struct ldb_context *samdb,
449                 struct kccsrv_service *service,
450                 const char *object_dn_str,
451                 struct ncList **nc_list)
452 {
453         WERROR status;
454         struct ncList *nc_list_elem;
455         struct ldb_dn *nc_dn;
456
457         if (object_dn_str != NULL) {
458                 /* ncs := { object_dn } */
459                 *nc_list = NULL;
460                 nc_dn = ldb_dn_new(mem_ctx, samdb, object_dn_str);
461                 nc_list_elem = talloc_zero(mem_ctx, struct ncList);
462                 W_ERROR_HAVE_NO_MEMORY(nc_list_elem);
463                 nc_list_elem->dn = nc_dn;
464                 DLIST_ADD_END(*nc_list, nc_list_elem, struct ncList*);
465         } else {
466                 /* ncs := getNCs() from ldb database.
467                  * getNCs() must return an array containing
468                  * the DSNames of all NCs hosted by this
469                  * server.
470                  */
471                 char *ntds_guid_str = GUID_string(mem_ctx, &service->ntds_guid);
472                 W_ERROR_HAVE_NO_MEMORY(ntds_guid_str);
473                 status = get_master_ncs(mem_ctx, samdb, ntds_guid_str, nc_list);
474                 W_ERROR_NOT_OK_RETURN(status);
475         }
476
477         return WERR_OK;
478 }
479
480 /*
481   Copy the fields from 'reps1' to 'reps2', leaving zeroed the fields on
482   'reps2' that aren't available on 'reps1'.
483 */
484 static WERROR copy_repsfrom_1_to_2(TALLOC_CTX *mem_ctx,
485                                  struct repsFromTo2 **reps2,
486                                  struct repsFromTo1 *reps1)
487 {
488         struct repsFromTo2* reps;
489
490         reps = talloc_zero(mem_ctx, struct repsFromTo2);
491         W_ERROR_HAVE_NO_MEMORY(reps);
492
493         reps->blobsize = reps1->blobsize;
494         reps->consecutive_sync_failures = reps1->consecutive_sync_failures;
495         reps->last_attempt = reps1->last_attempt;
496         reps->last_success = reps1->last_success;
497         reps->other_info = talloc_zero(mem_ctx, struct repsFromTo2OtherInfo);
498         W_ERROR_HAVE_NO_MEMORY(reps->other_info);
499         reps->other_info->dns_name1 = reps1->other_info->dns_name;
500         reps->replica_flags = reps1->replica_flags;
501         memcpy(reps->schedule, reps1->schedule, sizeof(reps1->schedule));
502         reps->reserved = reps1->reserved;
503         reps->highwatermark = reps1->highwatermark;
504         reps->source_dsa_obj_guid = reps1->source_dsa_obj_guid;
505         reps->source_dsa_invocation_id = reps1->source_dsa_invocation_id;
506         reps->transport_guid = reps1->transport_guid;
507
508         *reps2 = reps;
509         return WERR_OK;
510 }
511
512 static WERROR fill_neighbor_from_repsFrom(TALLOC_CTX *mem_ctx,
513                                           struct ldb_context *samdb,
514                                           struct ldb_dn *nc_dn,
515                                           struct drsuapi_DsReplicaNeighbour *neigh,
516                                           struct repsFromTo2 *reps_from)
517 {
518         struct ldb_dn *source_dsa_dn;
519         int ret;
520         struct ldb_dn *transport_obj_dn = NULL;
521
522         neigh->source_dsa_address = reps_from->other_info->dns_name1;
523         neigh->replica_flags = reps_from->replica_flags;
524         neigh->last_attempt = reps_from->last_attempt;
525         neigh->source_dsa_obj_guid = reps_from->source_dsa_obj_guid;
526
527         ret = dsdb_find_dn_by_guid(samdb, mem_ctx, &reps_from->source_dsa_obj_guid,
528                                    &source_dsa_dn);
529
530         if (ret != LDB_SUCCESS) {
531                 DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
532                          GUID_string(mem_ctx, &reps_from->source_dsa_obj_guid)));
533                 return WERR_DS_DRA_INTERNAL_ERROR;
534         }
535
536         neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
537         neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
538
539         if (dsdb_find_guid_by_dn(samdb, nc_dn, &neigh->naming_context_obj_guid)
540                         != LDB_SUCCESS) {
541                 return WERR_DS_DRA_INTERNAL_ERROR;
542         }
543
544         if (!GUID_all_zero(&reps_from->transport_guid)) {
545                 ret = dsdb_find_dn_by_guid(samdb, mem_ctx, &reps_from->transport_guid,
546                                            &transport_obj_dn);
547                 if (ret != LDB_SUCCESS) {
548                         return WERR_DS_DRA_INTERNAL_ERROR;
549                 }
550         }
551
552         neigh->transport_obj_dn = ldb_dn_get_linearized(transport_obj_dn);
553         neigh->source_dsa_invocation_id = reps_from->source_dsa_invocation_id;
554         neigh->transport_obj_guid = reps_from->transport_guid;
555         neigh->highest_usn = reps_from->highwatermark.highest_usn;
556         neigh->tmp_highest_usn = reps_from->highwatermark.tmp_highest_usn;
557         neigh->last_success = reps_from->last_success;
558         neigh->result_last_attempt = reps_from->result_last_attempt;
559         neigh->consecutive_sync_failures = reps_from->consecutive_sync_failures;
560         neigh->reserved = 0; /* Unused. MUST be 0. */
561
562         return WERR_OK;
563 }
564
565 /*
566   Get the inbound neighbours of this DC
567   See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_NEIGHBORS
568 */
569 static WERROR kccdrs_replica_get_info_neighbours(TALLOC_CTX *mem_ctx,
570                                                  struct kccsrv_service *service,
571                                                  struct ldb_context *samdb,
572                                                  struct drsuapi_DsReplicaGetInfo *r,
573                                                  union drsuapi_DsReplicaInfo *reply,
574                                                  uint32_t base_index,
575                                                  struct GUID req_src_dsa_guid,
576                                                  const char *object_dn_str)
577 {
578         WERROR status;
579         uint32_t i, j;
580         struct ldb_dn *nc_dn = NULL;
581         struct ncList *p_nc_list = NULL;
582         struct repsFromToBlob *reps_from_blob = NULL;
583         struct repsFromTo2 *reps_from = NULL;
584         uint32_t c_reps_from;
585         uint32_t i_rep;
586         struct drsuapi_DsReplicaNeighbour neigh;
587         struct ncList *nc_list = NULL;
588
589         status = get_ncs_list(mem_ctx, samdb, service, object_dn_str, &nc_list);
590         W_ERROR_NOT_OK_RETURN(status);
591
592         i = j = 0;
593
594         reply->neighbours = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbourCtr);
595         W_ERROR_HAVE_NO_MEMORY(reply->neighbours);
596         reply->neighbours->reserved = 0;
597         reply->neighbours->count = 0;
598
599         /* foreach nc in ncs */
600         for (p_nc_list = nc_list; p_nc_list != NULL; p_nc_list = p_nc_list->next) {
601
602                 nc_dn = p_nc_list->dn;
603
604                 /* load the nc's repsFromTo blob */
605                 status = dsdb_loadreps(samdb, mem_ctx, nc_dn, "repsFrom",
606                                 &reps_from_blob, &c_reps_from);
607                 W_ERROR_NOT_OK_RETURN(status);
608
609                 /* foreach r in nc!repsFrom */
610                 for (i_rep = 0; i_rep < c_reps_from; i_rep++) {
611
612                         /* put all info on reps_from */
613                         if (reps_from_blob[i_rep].version == 1) {
614                                 status = copy_repsfrom_1_to_2(mem_ctx, &reps_from,
615                                                               &reps_from_blob[i_rep].ctr.ctr1);
616                                 W_ERROR_NOT_OK_RETURN(status);
617                         } else { /* reps_from->version == 2 */
618                                 reps_from = &reps_from_blob[i_rep].ctr.ctr2;
619                         }
620
621                         if (GUID_all_zero(&req_src_dsa_guid) ||
622                             GUID_compare(&req_src_dsa_guid, &reps_from->source_dsa_obj_guid) == 0)
623                         {
624
625                                 if (i >= base_index) {
626                                         status = fill_neighbor_from_repsFrom(mem_ctx, samdb,
627                                                                              nc_dn, &neigh,
628                                                                              reps_from);
629                                         W_ERROR_NOT_OK_RETURN(status);
630
631                                         /* append the neighbour to the neighbours array */
632                                         reply->neighbours->array = talloc_realloc(mem_ctx,
633                                                                                     reply->neighbours->array,
634                                                                                     struct drsuapi_DsReplicaNeighbour,
635                                                                                     reply->neighbours->count + 1);
636                                         reply->neighbours->array[reply->neighbours->count++] = neigh;
637                                         j++;
638                                 }
639
640                                 i++;
641                         }
642                 }
643         }
644
645         return WERR_OK;
646 }
647
648 static WERROR fill_neighbor_from_repsTo(TALLOC_CTX *mem_ctx,
649                                         struct ldb_context *samdb, struct ldb_dn *nc_dn,
650                                         struct drsuapi_DsReplicaNeighbour *neigh,
651                                         struct repsFromTo2 *reps_to)
652 {
653         int ret;
654         struct ldb_dn *source_dsa_dn;
655
656         neigh->source_dsa_address = reps_to->other_info->dns_name1;
657         neigh->replica_flags = reps_to->replica_flags;
658         neigh->last_attempt = reps_to->last_attempt;
659         neigh->source_dsa_obj_guid = reps_to->source_dsa_obj_guid;
660
661         ret = dsdb_find_dn_by_guid(samdb, mem_ctx, &reps_to->source_dsa_obj_guid, &source_dsa_dn);
662         if (ret != LDB_SUCCESS) {
663                 DEBUG(0,(__location__ ": Failed to find DN for neighbor GUID %s\n",
664                          GUID_string(mem_ctx, &reps_to->source_dsa_obj_guid)));
665                 return WERR_DS_DRA_INTERNAL_ERROR;
666         }
667
668         neigh->source_dsa_obj_dn = ldb_dn_get_linearized(source_dsa_dn);
669         neigh->naming_context_dn = ldb_dn_get_linearized(nc_dn);
670
671         ret = dsdb_find_guid_by_dn(samdb, nc_dn,
672                         &neigh->naming_context_obj_guid);
673         if (ret != LDB_SUCCESS) {
674                 DEBUG(0,(__location__ ": Failed to find GUID for DN %s\n",
675                          ldb_dn_get_linearized(nc_dn)));
676                 return WERR_DS_DRA_INTERNAL_ERROR;
677         }
678
679         return WERR_OK;
680 }
681
682 /*
683   Get the outbound neighbours of this DC
684   See details on MS-DRSR 4.1.13.3, for infoType DS_REPL_INFO_REPSTO
685 */
686 static WERROR kccdrs_replica_get_info_repsto(TALLOC_CTX *mem_ctx,
687                                              struct kccsrv_service *service,
688                                              struct ldb_context *samdb,
689                                              struct drsuapi_DsReplicaGetInfo *r,
690                                              union drsuapi_DsReplicaInfo *reply,
691                                              uint32_t base_index,
692                                              struct GUID req_src_dsa_guid,
693                                              const char *object_dn_str)
694 {
695         WERROR status;
696         uint32_t i, j;
697         struct ncList *p_nc_list = NULL;
698         struct ldb_dn *nc_dn = NULL;
699         struct repsFromToBlob *reps_to_blob;
700         struct repsFromTo2 *reps_to;
701         uint32_t c_reps_to;
702         uint32_t i_rep;
703         struct drsuapi_DsReplicaNeighbour neigh;
704         struct ncList *nc_list = NULL;
705
706         status = get_ncs_list(mem_ctx, samdb, service, object_dn_str, &nc_list);
707         W_ERROR_NOT_OK_RETURN(status);
708
709         i = j = 0;
710
711         reply->repsto = talloc_zero(mem_ctx, struct drsuapi_DsReplicaNeighbourCtr);
712         W_ERROR_HAVE_NO_MEMORY(reply->repsto);
713         reply->repsto->reserved = 0;
714         reply->repsto->count = 0;
715
716         /* foreach nc in ncs */
717         for (p_nc_list = nc_list; p_nc_list != NULL; p_nc_list = p_nc_list->next) {
718
719                 nc_dn = p_nc_list->dn;
720
721                 status = dsdb_loadreps(samdb, mem_ctx, nc_dn, "repsTo",
722                                 &reps_to_blob, &c_reps_to);
723                 W_ERROR_NOT_OK_RETURN(status);
724
725                 /* foreach r in nc!repsTo */
726                 for (i_rep = 0; i_rep < c_reps_to; i_rep++) {
727
728                         /* put all info on reps_to */
729                         if (reps_to_blob[i_rep].version == 1) {
730                                 status = copy_repsfrom_1_to_2(mem_ctx,
731                                                               &reps_to,
732                                                               &reps_to_blob[i_rep].ctr.ctr1);
733                                 W_ERROR_NOT_OK_RETURN(status);
734                         } else { /* reps_to->version == 2 */
735                                 reps_to = &reps_to_blob[i_rep].ctr.ctr2;
736                         }
737
738                         if (i >= base_index) {
739                                 status = fill_neighbor_from_repsTo(mem_ctx,
740                                                                    samdb, nc_dn,
741                                                                    &neigh, reps_to);
742                                 W_ERROR_NOT_OK_RETURN(status);
743
744                                 /* append the neighbour to the neighbours array */
745                                 reply->repsto->array = talloc_realloc(mem_ctx,
746                                                                             reply->repsto->array,
747                                                                             struct drsuapi_DsReplicaNeighbour,
748                                                                             reply->repsto->count + 1);
749                                 reply->repsto->array[reply->repsto->count++] = neigh;
750                                 j++;
751                         }
752                         i++;
753                 }
754         }
755
756         return WERR_OK;
757 }
758
759 NTSTATUS kccdrs_replica_get_info(struct irpc_message *msg,
760                                  struct drsuapi_DsReplicaGetInfo *req)
761 {
762         WERROR status;
763         struct drsuapi_DsReplicaGetInfoRequest1 *req1;
764         struct drsuapi_DsReplicaGetInfoRequest2 *req2;
765         uint32_t base_index;
766         union drsuapi_DsReplicaInfo *reply;
767         struct GUID req_src_dsa_guid;
768         const char *object_dn_str = NULL;
769         struct kccsrv_service *service;
770         struct ldb_context *samdb;
771         TALLOC_CTX *mem_ctx;
772         enum drsuapi_DsReplicaInfoType info_type;
773         uint32_t flags;
774         const char *attribute_name, *value_dn;
775
776         service = talloc_get_type(msg->private_data, struct kccsrv_service);
777         samdb = service->samdb;
778         mem_ctx = talloc_new(msg);
779         NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
780
781         NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaGetInfo, req);
782
783         /* check request version */
784         if (req->in.level != DRSUAPI_DS_REPLICA_GET_INFO &&
785             req->in.level != DRSUAPI_DS_REPLICA_GET_INFO2)
786         {
787                 DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo level %u\n",
788                          req->in.level));
789                 status = WERR_REVISION_MISMATCH;
790                 goto done;
791         }
792
793         if (req->in.level == DRSUAPI_DS_REPLICA_GET_INFO) {
794                 req1 = &req->in.req->req1;
795                 base_index = 0;
796                 info_type = req1->info_type;
797                 object_dn_str = req1->object_dn;
798                 req_src_dsa_guid = req1->source_dsa_guid;
799         } else { /* r->in.level == DRSUAPI_DS_REPLICA_GET_INFO2 */
800                 req2 = &req->in.req->req2;
801                 if (req2->enumeration_context == 0xffffffff) {
802                         /* no more data is available */
803                         status = WERR_NO_MORE_ITEMS; /* on MS-DRSR it is ERROR_NO_MORE_ITEMS */
804                         goto done;
805                 }
806
807                 base_index = req2->enumeration_context;
808                 info_type = req2->info_type;
809                 object_dn_str = req2->object_dn;
810                 req_src_dsa_guid = req2->source_dsa_guid;
811                 flags = req2->flags;
812                 attribute_name = req2->attribute_name;
813                 value_dn = req2->value_dn_str;
814         }
815
816         /* allocate the reply and fill in some fields */
817         reply = talloc_zero(mem_ctx, union drsuapi_DsReplicaInfo);
818         NT_STATUS_HAVE_NO_MEMORY(reply);
819         req->out.info = reply;
820         req->out.info_type = talloc(mem_ctx, enum drsuapi_DsReplicaInfoType);
821         NT_STATUS_HAVE_NO_MEMORY(req->out.info_type);
822         *req->out.info_type = info_type;
823
824         /* Based on the infoType requested, retrieve the corresponding
825          * information and construct the response message */
826         switch (info_type) {
827
828         case DRSUAPI_DS_REPLICA_INFO_NEIGHBORS:
829                 status = kccdrs_replica_get_info_neighbours(mem_ctx, service, samdb, req,
830                                                             reply, base_index, req_src_dsa_guid,
831                                                             object_dn_str);
832                 break;
833         case DRSUAPI_DS_REPLICA_INFO_REPSTO:
834                 status = kccdrs_replica_get_info_repsto(mem_ctx, service, samdb, req,
835                                                         reply, base_index, req_src_dsa_guid,
836                                                         object_dn_str);
837                 break;
838         case DRSUAPI_DS_REPLICA_INFO_CURSORS: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_FOR_NC */
839                 status = kccdrs_replica_get_info_cursors(mem_ctx, samdb, req, reply,
840                                                          ldb_dn_new(mem_ctx, samdb, object_dn_str));
841                 break;
842         case DRSUAPI_DS_REPLICA_INFO_CURSORS2: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_2_FOR_NC */
843                 status = kccdrs_replica_get_info_cursors2(mem_ctx, samdb, req, reply,
844                                                           ldb_dn_new(mem_ctx, samdb, object_dn_str));
845                 break;
846         case DRSUAPI_DS_REPLICA_INFO_PENDING_OPS:
847                 status = kccdrs_replica_get_info_pending_ops(mem_ctx, samdb, req, reply,
848                                                              ldb_dn_new(mem_ctx, samdb, object_dn_str));
849                 break;
850         case DRSUAPI_DS_REPLICA_INFO_CURSORS3: /* On MS-DRSR it is DS_REPL_INFO_CURSORS_3_FOR_NC */
851                 status = WERR_INVALID_LEVEL;
852                 break;
853         case DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1: /* On MS-DRSR it is DS_REPL_INFO_UPTODATE_VECTOR_V1 */
854                 status = WERR_INVALID_LEVEL;
855                 break;
856         case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
857                 status = WERR_INVALID_LEVEL;
858                 break;
859         case DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_OBJ */
860                 status = kccdrs_replica_get_info_obj_metadata2(mem_ctx, samdb, req, reply,
861                                                                ldb_dn_new(mem_ctx, samdb, object_dn_str), base_index);
862                 break;
863         case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA: /* On MS-DRSR it is DS_REPL_INFO_METADATA_FOR_ATTR_VALUE */
864                 status = WERR_INVALID_LEVEL;
865                 break;
866         case DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2: /* On MS-DRSR it is DS_REPL_INFO_METADATA_2_FOR_ATTR_VALUE */
867                 status = WERR_INVALID_LEVEL;
868                 break;
869         case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES: /* On MS-DRSR it is DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES */
870                 status = WERR_INVALID_LEVEL;
871                 break;
872         case DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES: /* On MS-DRSR it is DS_REPL_INFO_KCC_LINK_FAILURES */
873                 status = WERR_INVALID_LEVEL;
874                 break;
875         case DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS: /* On MS-DRSR it is DS_REPL_INFO_CLIENT_CONTEXTS */
876                 status = WERR_INVALID_LEVEL;
877                 break;
878         case DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS: /* On MS-DRSR it is DS_REPL_INFO_SERVER_OUTGOING_CALLS */
879                 status = WERR_INVALID_LEVEL;
880                 break;
881         default:
882                 DEBUG(1,(__location__ ": Unsupported DsReplicaGetInfo info_type %u\n",
883                          info_type));
884                 status = WERR_INVALID_LEVEL;
885                 break;
886         }
887
888 done:
889         /* put the status on the result field of the reply */
890         req->out.result = status;
891         NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaGetInfo, req);
892         return NT_STATUS_OK;
893 }