getncchanges: Tie destination DSA GUID to authenticating RODC for REPL_SECRET
[nivanova/samba-autobuild/.git] / source4 / rpc_server / drsuapi / getncchanges.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    implement the DSGetNCChanges call
5
6    Copyright (C) Anatoliy Atanasov 2009
7    Copyright (C) Andrew Tridgell 2009-2010
8    Copyright (C) Andrew Bartlett 2010-2016
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "rpc_server/dcerpc_server.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "param/param.h"
28 #include "librpc/gen_ndr/ndr_drsblobs.h"
29 #include "librpc/gen_ndr/ndr_drsuapi.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "libcli/security/security.h"
32 #include "libcli/security/session.h"
33 #include "rpc_server/drsuapi/dcesrv_drsuapi.h"
34 #include "rpc_server/dcerpc_server_proto.h"
35 #include "../libcli/drsuapi/drsuapi.h"
36 #include "lib/util/binsearch.h"
37 #include "lib/util/tsort.h"
38 #include "auth/session.h"
39 #include "dsdb/common/util.h"
40 #include "lib/dbwrap/dbwrap.h"
41 #include "lib/dbwrap/dbwrap_rbt.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43
44 /* state of a partially completed getncchanges call */
45 struct drsuapi_getncchanges_state {
46         struct db_context *anc_cache;
47         struct GUID *guids;
48         uint32_t num_records;
49         uint32_t num_processed;
50         struct ldb_dn *ncRoot_dn;
51         struct GUID ncRoot_guid;
52         bool is_schema_nc;
53         uint64_t min_usn;
54         uint64_t max_usn;
55         struct drsuapi_DsReplicaHighWaterMark last_hwm;
56         struct ldb_dn *last_dn;
57         struct drsuapi_DsReplicaHighWaterMark final_hwm;
58         struct drsuapi_DsReplicaCursor2CtrEx *final_udv;
59         struct drsuapi_DsReplicaLinkedAttribute *la_list;
60         uint32_t la_count;
61         struct la_for_sorting *la_sorted;
62         uint32_t la_idx;
63 };
64
65 /* We must keep the GUIDs in NDR form for sorting */
66 struct la_for_sorting {
67         struct drsuapi_DsReplicaLinkedAttribute *link;
68         uint8_t target_guid[16];
69         uint8_t source_guid[16];
70 };
71
72 static int drsuapi_DsReplicaHighWaterMark_cmp(const struct drsuapi_DsReplicaHighWaterMark *h1,
73                                               const struct drsuapi_DsReplicaHighWaterMark *h2)
74 {
75         if (h1->highest_usn < h2->highest_usn) {
76                 return -1;
77         } else if (h1->highest_usn > h2->highest_usn) {
78                 return 1;
79         } else if (h1->tmp_highest_usn < h2->tmp_highest_usn) {
80                 return -1;
81         } else if (h1->tmp_highest_usn > h2->tmp_highest_usn) {
82                 return 1;
83         } else if (h1->reserved_usn < h2->reserved_usn) {
84                 return -1;
85         } else if (h1->reserved_usn > h2->reserved_usn) {
86                 return 1;
87         }
88
89         return 0;
90 }
91
92 /*
93   build a DsReplicaObjectIdentifier from a ldb msg
94  */
95 static struct drsuapi_DsReplicaObjectIdentifier *get_object_identifier(TALLOC_CTX *mem_ctx,
96                                                                        const struct ldb_message *msg)
97 {
98         struct drsuapi_DsReplicaObjectIdentifier *identifier;
99         struct dom_sid *sid;
100
101         identifier = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
102         if (identifier == NULL) {
103                 return NULL;
104         }
105
106         identifier->dn = ldb_dn_alloc_linearized(identifier, msg->dn);
107         identifier->guid = samdb_result_guid(msg, "objectGUID");
108
109         sid = samdb_result_dom_sid(identifier, msg, "objectSid");
110         if (sid) {
111                 identifier->sid = *sid;
112         } else {
113                 ZERO_STRUCT(identifier->sid);
114         }
115         return identifier;
116 }
117
118 static int udv_compare(const struct GUID *guid1, struct GUID guid2)
119 {
120         return GUID_compare(guid1, &guid2);
121 }
122
123 /*
124   see if we can filter an attribute using the uptodateness_vector
125  */
126 static bool udv_filter(const struct drsuapi_DsReplicaCursorCtrEx *udv,
127                        const struct GUID *originating_invocation_id,
128                        uint64_t originating_usn)
129 {
130         const struct drsuapi_DsReplicaCursor *c;
131         if (udv == NULL) return false;
132         BINARY_ARRAY_SEARCH(udv->cursors, udv->count, source_dsa_invocation_id,
133                             originating_invocation_id, udv_compare, c);
134         if (c && originating_usn <= c->highest_usn) {
135                 return true;
136         }
137         return false;
138
139 }
140
141 static int uint32_t_cmp(uint32_t a1, uint32_t a2)
142 {
143         if (a1 == a2) return 0;
144         return a1 > a2 ? 1 : -1;
145 }
146
147 static int uint32_t_ptr_cmp(uint32_t *a1, uint32_t *a2, void *unused)
148 {
149         if (*a1 == *a2) return 0;
150         return *a1 > *a2 ? 1 : -1;
151 }
152
153 static WERROR getncchanges_attid_remote_to_local(const struct dsdb_schema *schema,
154                                                  const struct dsdb_syntax_ctx *ctx,
155                                                  enum drsuapi_DsAttributeId remote_attid_as_enum,
156                                                  enum drsuapi_DsAttributeId *local_attid_as_enum,
157                                                  const struct dsdb_attribute **_sa)
158 {
159         WERROR werr;
160         const struct dsdb_attribute *sa = NULL;
161
162         if (ctx->pfm_remote == NULL) {
163                 DEBUG(7, ("No prefixMap supplied, falling back to local prefixMap.\n"));
164                 goto fail;
165         }
166
167         werr = dsdb_attribute_drsuapi_remote_to_local(ctx,
168                                                       remote_attid_as_enum,
169                                                       local_attid_as_enum,
170                                                       _sa);
171         if (!W_ERROR_IS_OK(werr)) {
172                 DEBUG(3, ("WARNING: Unable to resolve remote attid, falling back to local prefixMap.\n"));
173                 goto fail;
174         }
175
176         return werr;
177 fail:
178
179         sa = dsdb_attribute_by_attributeID_id(schema, remote_attid_as_enum);
180         if (sa == NULL) {
181                 return WERR_DS_DRA_SCHEMA_MISMATCH;
182         } else {
183                 if (local_attid_as_enum != NULL) {
184                         *local_attid_as_enum = sa->attributeID_id;
185                 }
186                 if (_sa != NULL) {
187                         *_sa = sa;
188                 }
189                 return WERR_OK;
190         }
191 }
192
193 static WERROR getncchanges_update_revealed_list(struct ldb_context *sam_ctx,
194                                                 TALLOC_CTX *mem_ctx,
195                                                 struct ldb_message **msg,
196                                                 struct ldb_dn *object_dn,
197                                                 const struct dsdb_attribute *sa,
198                                                 struct replPropertyMetaData1 *meta_data,
199                                                 struct ldb_message *revealed_users)
200 {
201         enum ndr_err_code ndr_err;
202         int ldb_err;
203         unsigned i;
204         char *attr_str = NULL;
205         char *attr_hex = NULL;
206         DATA_BLOB attr_blob;
207         struct ldb_message_element *existing = NULL, *el_add = NULL, *el_del = NULL;
208         const char * const * secret_attributes = ldb_get_opaque(sam_ctx, "LDB_SECRET_ATTRIBUTE_LIST");
209
210         if (!ldb_attr_in_list(secret_attributes,
211                               sa->lDAPDisplayName)) {
212                 return WERR_OK;
213         }
214
215
216         ndr_err = ndr_push_struct_blob(&attr_blob, mem_ctx, meta_data, (ndr_push_flags_fn_t)ndr_push_replPropertyMetaData1);
217         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
218                 return WERR_DS_DRA_INTERNAL_ERROR;
219         }
220
221         attr_hex = hex_encode_talloc(mem_ctx, attr_blob.data, attr_blob.length);
222         if (attr_hex == NULL) {
223                 return WERR_NOT_ENOUGH_MEMORY;
224         }
225
226         attr_str = talloc_asprintf(mem_ctx, "B:%zd:%s:%s", attr_blob.length*2, attr_hex, ldb_dn_get_linearized(object_dn));
227         if (attr_str == NULL) {
228                 return WERR_NOT_ENOUGH_MEMORY;
229         }
230
231         existing = ldb_msg_find_element(revealed_users, "msDS-RevealedUsers");
232         if (existing != NULL) {
233                 /* Replace the old value (if one exists) with the current one */
234                 for (i = 0; i < existing->num_values; i++) {
235                         struct dsdb_dn *existing_dn = dsdb_dn_parse_trusted(mem_ctx, sam_ctx, &existing->values[i], DSDB_SYNTAX_BINARY_DN);
236                         if (ldb_dn_compare(object_dn, existing_dn->dn) == 0) {
237                                 struct replPropertyMetaData1 existing_meta_data;
238                                 ndr_err = ndr_pull_struct_blob_all_noalloc(&existing_dn->extra_part,
239                                                                &existing_meta_data,
240                                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaData1);
241                                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
242                                         return WERR_DS_DRA_INTERNAL_ERROR;
243                                 }
244
245                                 if (existing_meta_data.attid == sa->attributeID_id) {
246                                         ldb_err = ldb_msg_add_empty(*msg, "msDS-RevealedUsers", LDB_FLAG_MOD_DELETE, &el_del);
247                                         if (ldb_err != LDB_SUCCESS) {
248                                                 return WERR_DS_DRA_INTERNAL_ERROR;
249                                         }
250
251                                         el_del->values = talloc_array((*msg)->elements, struct ldb_val, 1);
252                                         if (el_del->values == NULL) {
253                                                 return WERR_NOT_ENOUGH_MEMORY;
254                                         }
255                                         el_del->values[0] = existing->values[i];
256                                         el_del->num_values = 1;
257                                 }
258                         }
259                 }
260         }
261
262         ldb_err = ldb_msg_add_empty(*msg, "msDS-RevealedUsers", LDB_FLAG_MOD_ADD, &el_add);
263         if (ldb_err != LDB_SUCCESS) {
264                 return WERR_DS_DRA_INTERNAL_ERROR;
265         }
266
267         el_add->values = talloc_array((*msg)->elements, struct ldb_val, 1);
268         if (el_add->values == NULL) {
269                 return WERR_NOT_ENOUGH_MEMORY;
270
271         }
272
273         el_add->values[0] = data_blob_string_const(attr_str);
274         el_add->num_values = 1;
275
276         return WERR_OK;
277 }
278
279 /* 
280   drsuapi_DsGetNCChanges for one object
281 */
282 static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItemEx *obj,
283                                           const struct ldb_message *msg,
284                                           struct ldb_context *sam_ctx,
285                                           struct ldb_dn *ncRoot_dn,
286                                           bool   is_schema_nc,
287                                           struct dsdb_schema *schema,
288                                           DATA_BLOB *session_key,
289                                           uint64_t highest_usn,
290                                           uint32_t replica_flags,
291                                           struct drsuapi_DsPartialAttributeSet *partial_attribute_set,
292                                           struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector,
293                                           enum drsuapi_DsExtendedOperation extended_op,
294                                           bool force_object_return,
295                                           uint32_t *local_pas,
296                                           struct ldb_dn *machine_dn)
297 {
298         const struct ldb_val *md_value;
299         uint32_t i, n;
300         struct replPropertyMetaDataBlob md;
301         uint32_t rid = 0;
302         int ldb_err;
303         enum ndr_err_code ndr_err;
304         uint32_t *attids;
305         const char *rdn;
306         const struct dsdb_attribute *rdn_sa;
307         uint64_t uSNChanged;
308         unsigned int instanceType;
309         struct dsdb_syntax_ctx syntax_ctx;
310         struct ldb_result *res = NULL;
311         struct ldb_message *revealed_list_msg = NULL, *existing_revealed_list_msg = NULL;
312         WERROR werr;
313         int ret;
314
315         /* make dsdb sytanx context for conversions */
316         dsdb_syntax_ctx_init(&syntax_ctx, sam_ctx, schema);
317         syntax_ctx.is_schema_nc = is_schema_nc;
318
319         uSNChanged = ldb_msg_find_attr_as_uint64(msg, "uSNChanged", 0);
320         instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType", 0);
321         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
322                 obj->is_nc_prefix = true;
323                 obj->parent_object_guid = NULL;
324         } else {
325                 obj->is_nc_prefix = false;
326                 obj->parent_object_guid = talloc(obj, struct GUID);
327                 if (obj->parent_object_guid == NULL) {
328                         return WERR_DS_DRA_INTERNAL_ERROR;
329                 }
330                 *obj->parent_object_guid = samdb_result_guid(msg, "parentGUID");
331                 if (GUID_all_zero(obj->parent_object_guid)) {
332                         DEBUG(0,(__location__ ": missing parentGUID for %s\n",
333                                  ldb_dn_get_linearized(msg->dn)));
334                         return WERR_DS_DRA_INTERNAL_ERROR;
335                 }
336         }
337         obj->next_object = NULL;
338
339         md_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
340         if (!md_value) {
341                 /* nothing to send */
342                 return WERR_OK;
343         }
344
345         if (instanceType & INSTANCE_TYPE_UNINSTANT) {
346                 /* don't send uninstantiated objects */
347                 return WERR_OK;
348         }
349
350         if (uSNChanged <= highest_usn) {
351                 /* nothing to send */
352                 return WERR_OK;
353         }
354
355         ndr_err = ndr_pull_struct_blob(md_value, obj, &md,
356                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
357         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
358                 return WERR_DS_DRA_INTERNAL_ERROR;
359         }
360
361         if (md.version != 1) {
362                 return WERR_DS_DRA_INTERNAL_ERROR;
363         }
364
365         rdn = ldb_dn_get_rdn_name(msg->dn);
366         if (rdn == NULL) {
367                 DEBUG(0,(__location__ ": No rDN for %s\n", ldb_dn_get_linearized(msg->dn)));
368                 return WERR_DS_DRA_INTERNAL_ERROR;
369         }
370
371         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn);
372         if (rdn_sa == NULL) {
373                 DEBUG(0,(__location__ ": Can't find dsds_attribute for rDN %s in %s\n",
374                          rdn, ldb_dn_get_linearized(msg->dn)));
375                 return WERR_DS_DRA_INTERNAL_ERROR;
376         }
377
378         obj->meta_data_ctr = talloc(obj, struct drsuapi_DsReplicaMetaDataCtr);
379         attids = talloc_array(obj, uint32_t, md.ctr.ctr1.count);
380
381         obj->object.identifier = get_object_identifier(obj, msg);
382         if (obj->object.identifier == NULL) {
383                 return WERR_NOT_ENOUGH_MEMORY;
384         }
385         dom_sid_split_rid(NULL, &obj->object.identifier->sid, NULL, &rid);
386
387         obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count);
388
389         if (extended_op == DRSUAPI_EXOP_REPL_SECRET) {
390                 /* Get the existing revealed users for the destination */
391                 static const char *machine_attrs[] = { "msDS-RevealedUsers", NULL };
392
393                 revealed_list_msg = ldb_msg_new(sam_ctx);
394                 if (revealed_list_msg == NULL) {
395                         return WERR_NOT_ENOUGH_MEMORY;
396                 }
397                 revealed_list_msg->dn = machine_dn;
398
399                 ldb_err = dsdb_search_dn(sam_ctx, obj, &res, machine_dn, machine_attrs, 0);
400                 if (ldb_err != LDB_SUCCESS || res->count != 1) {
401                         return WERR_DS_DRA_INTERNAL_ERROR;
402                 }
403
404                 existing_revealed_list_msg = res->msgs[0];
405         }
406
407         for (n=i=0; i<md.ctr.ctr1.count; i++) {
408                 const struct dsdb_attribute *sa;
409                 bool force_attribute = false;
410
411                 /* if the attribute has not changed, and it is not the
412                    instanceType then don't include it */
413                 if (md.ctr.ctr1.array[i].local_usn < highest_usn &&
414                     extended_op != DRSUAPI_EXOP_REPL_SECRET &&
415                     md.ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) continue;
416
417                 /* don't include the rDN */
418                 if (md.ctr.ctr1.array[i].attid == rdn_sa->attributeID_id) continue;
419
420                 sa = dsdb_attribute_by_attributeID_id(schema, md.ctr.ctr1.array[i].attid);
421                 if (!sa) {
422                         DEBUG(0,(__location__ ": Failed to find attribute in schema for attrid %u mentioned in replPropertyMetaData of %s\n",
423                                  (unsigned int)md.ctr.ctr1.array[i].attid,
424                                  ldb_dn_get_linearized(msg->dn)));
425                         return WERR_DS_DRA_INTERNAL_ERROR;
426                 }
427
428                 if (sa->linkID) {
429                         struct ldb_message_element *el;
430                         el = ldb_msg_find_element(msg, sa->lDAPDisplayName);
431                         if (el && el->num_values && dsdb_dn_is_upgraded_link_val(&el->values[0])) {
432                                 /* don't send upgraded links inline */
433                                 continue;
434                         }
435                 }
436
437                 if (extended_op == DRSUAPI_EXOP_REPL_SECRET &&
438                     !dsdb_attr_in_rodc_fas(sa)) {
439                         force_attribute = true;
440                         DEBUG(4,("Forcing attribute %s in %s\n",
441                                  sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
442                         werr = getncchanges_update_revealed_list(sam_ctx, obj,
443                                                                  &revealed_list_msg,
444                                                                  msg->dn, sa,
445                                                                  &md.ctr.ctr1.array[i],
446                                                                  existing_revealed_list_msg);
447                         if (!W_ERROR_IS_OK(werr)) {
448                                 return werr;
449                         }
450                 }
451
452                 /* filter by uptodateness_vector */
453                 if (md.ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType &&
454                     !force_attribute &&
455                     udv_filter(uptodateness_vector,
456                                &md.ctr.ctr1.array[i].originating_invocation_id,
457                                md.ctr.ctr1.array[i].originating_usn)) {
458                         continue;
459                 }
460
461                 /* filter by partial_attribute_set */
462                 if (partial_attribute_set && !force_attribute) {
463                         uint32_t *result = NULL;
464                         BINARY_ARRAY_SEARCH_V(local_pas, partial_attribute_set->num_attids, sa->attributeID_id,
465                                               uint32_t_cmp, result);
466                         if (result == NULL) {
467                                 continue;
468                         }
469                 }
470
471                 obj->meta_data_ctr->meta_data[n].originating_change_time = md.ctr.ctr1.array[i].originating_change_time;
472                 obj->meta_data_ctr->meta_data[n].version = md.ctr.ctr1.array[i].version;
473                 obj->meta_data_ctr->meta_data[n].originating_invocation_id = md.ctr.ctr1.array[i].originating_invocation_id;
474                 obj->meta_data_ctr->meta_data[n].originating_usn = md.ctr.ctr1.array[i].originating_usn;
475                 attids[n] = md.ctr.ctr1.array[i].attid;
476
477                 n++;
478         }
479
480         if (revealed_list_msg != NULL) {
481                 ret = ldb_transaction_start(sam_ctx);
482                 if (ret != LDB_SUCCESS) {
483                         DEBUG(0,(__location__ ": Failed transaction start - %s\n",
484                                  ldb_errstring(sam_ctx)));
485                         return WERR_DS_DRA_INTERNAL_ERROR;
486                 }
487
488                 ret = ldb_modify(sam_ctx, revealed_list_msg);
489                 if (ret != LDB_SUCCESS) {
490                         DEBUG(0,(__location__ ": Failed to commit revealed links - %s\n",
491                                  ldb_errstring(sam_ctx)));
492                         ldb_transaction_cancel(sam_ctx);
493                         return WERR_DS_DRA_INTERNAL_ERROR;
494                 }
495
496                 ret = ldb_transaction_commit(sam_ctx);
497                 if (ret != LDB_SUCCESS) {
498                         DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
499                                  ldb_errstring(sam_ctx)));
500                         return WERR_DS_DRA_INTERNAL_ERROR;
501                 }
502         }
503
504         /* ignore it if its an empty change. Note that renames always
505          * change the 'name' attribute, so they won't be ignored by
506          * this
507
508          * the force_object_return check is used to force an empty
509          * object return when we timeout in the getncchanges loop.
510          * This allows us to return an empty object, which keeps the
511          * client happy while preventing timeouts
512          */
513         if (n == 0 ||
514             (n == 1 &&
515              attids[0] == DRSUAPI_ATTID_instanceType &&
516              !force_object_return)) {
517                 talloc_free(obj->meta_data_ctr);
518                 obj->meta_data_ctr = NULL;
519                 return WERR_OK;
520         }
521
522         obj->meta_data_ctr->count = n;
523
524         obj->object.flags = DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER;
525         obj->object.attribute_ctr.num_attributes = obj->meta_data_ctr->count;
526         obj->object.attribute_ctr.attributes = talloc_array(obj, struct drsuapi_DsReplicaAttribute,
527                                                             obj->object.attribute_ctr.num_attributes);
528         if (obj->object.attribute_ctr.attributes == NULL) {
529                 return WERR_NOT_ENOUGH_MEMORY;
530         }
531
532         /*
533          * Note that the meta_data array and the attributes array must
534          * be the same size and in the same order
535          */
536         for (i=0; i<obj->object.attribute_ctr.num_attributes; i++) {
537                 struct ldb_message_element *el;
538                 const struct dsdb_attribute *sa;
539
540                 sa = dsdb_attribute_by_attributeID_id(schema, attids[i]);
541                 if (!sa) {
542                         DEBUG(0,("Unable to find attributeID %u in schema\n", attids[i]));
543                         return WERR_DS_DRA_INTERNAL_ERROR;
544                 }
545
546                 el = ldb_msg_find_element(msg, sa->lDAPDisplayName);
547                 if (el == NULL) {
548                         /* this happens for attributes that have been removed */
549                         DEBUG(5,("No element '%s' for attributeID %u in message\n",
550                                  sa->lDAPDisplayName, attids[i]));
551                         ZERO_STRUCT(obj->object.attribute_ctr.attributes[i]);
552                         obj->object.attribute_ctr.attributes[i].attid =
553                                         dsdb_attribute_get_attid(sa, syntax_ctx.is_schema_nc);
554                 } else {
555                         werr = sa->syntax->ldb_to_drsuapi(&syntax_ctx, sa, el, obj,
556                                                           &obj->object.attribute_ctr.attributes[i]);
557                         if (!W_ERROR_IS_OK(werr)) {
558                                 DEBUG(0,("Unable to convert %s on %s to DRS object - %s\n",
559                                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn),
560                                          win_errstr(werr)));
561                                 return werr;
562                         }
563                         /* if DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING is set
564                          * check if attribute is secret and send a null value
565                          */
566                         if (replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
567                                 drsuapi_process_secret_attribute(&obj->object.attribute_ctr.attributes[i],
568                                                                  &obj->meta_data_ctr->meta_data[i]);
569                         }
570                         /* some attributes needs to be encrypted
571                            before being sent */
572                         werr = drsuapi_encrypt_attribute(obj, session_key, rid, 
573                                                          &obj->object.attribute_ctr.attributes[i]);
574                         if (!W_ERROR_IS_OK(werr)) {
575                                 DEBUG(0,("Unable to encrypt %s on %s in DRS object - %s\n",
576                                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn),
577                                          win_errstr(werr)));
578                                 return werr;
579                         }
580                 }
581                 if (attids[i] != obj->object.attribute_ctr.attributes[i].attid) {
582                         DEBUG(0, ("Unable to replicate attribute %s on %s via DRS, incorrect attributeID:  "
583                                   "0x%08x vs 0x%08x "
584                                   "Run dbcheck!\n",
585                                   sa->lDAPDisplayName,
586                                   ldb_dn_get_linearized(msg->dn),
587                                   attids[i],
588                                   obj->object.attribute_ctr.attributes[i].attid));
589                         return WERR_DS_DATABASE_ERROR;
590                 }
591         }
592
593         return WERR_OK;
594 }
595
596 /*
597   add one linked attribute from an object to the list of linked
598   attributes in a getncchanges request
599  */
600 static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx,
601                                     struct ldb_context *sam_ctx,
602                                     const struct dsdb_schema *schema,
603                                     const struct dsdb_attribute *sa,
604                                     const struct ldb_message *msg,
605                                     struct dsdb_dn *dsdb_dn,
606                                     struct drsuapi_DsReplicaLinkedAttribute **la_list,
607                                     uint32_t *la_count,
608                                     bool is_schema_nc)
609 {
610         struct drsuapi_DsReplicaLinkedAttribute *la;
611         bool active;
612         NTSTATUS status;
613         WERROR werr;
614
615         (*la_list) = talloc_realloc(mem_ctx, *la_list, struct drsuapi_DsReplicaLinkedAttribute, (*la_count)+1);
616         W_ERROR_HAVE_NO_MEMORY(*la_list);
617
618         la = &(*la_list)[*la_count];
619
620         la->identifier = get_object_identifier(*la_list, msg);
621         W_ERROR_HAVE_NO_MEMORY(la->identifier);
622
623         active = (dsdb_dn_rmd_flags(dsdb_dn->dn) & DSDB_RMD_FLAG_DELETED) == 0;
624
625         if (!active) {
626                 /* We have to check that the inactive link still point to an existing object */
627                 struct GUID guid;
628                 struct ldb_dn *tdn;
629                 int ret;
630                 const char *v;
631
632                 v = ldb_msg_find_attr_as_string(msg, "isDeleted", "FALSE");
633                 if (strncmp(v, "TRUE", 4) == 0) {
634                         /*
635                           * Note: we skip the transmition of the deleted link even if the other part used to
636                           * know about it because when we transmit the deletion of the object, the link will
637                           * be deleted too due to deletion of object where link points and Windows do so.
638                           */
639                         if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008_R2) {
640                                 v = ldb_msg_find_attr_as_string(msg, "isRecycled", "FALSE");
641                                 /*
642                                  * On Windows 2008R2 isRecycled is always present even if FL or DL are < FL 2K8R2
643                                  * if it join an existing domain with deleted objets, it firsts impose to have a
644                                  * schema with the is-Recycled object and for all deleted objects it adds the isRecycled
645                                  * either during initial replication or after the getNCChanges.
646                                  * Behavior of samba has been changed to always have this attribute if it's present in the schema.
647                                  *
648                                  * So if FL <2K8R2 isRecycled might be here or not but we don't care, it's meaning less.
649                                  * If FL >=2K8R2 we are sure that this attribute will be here.
650                                  * For this kind of forest level we do not return the link if the object is recycled
651                                  * (isRecycled = true).
652                                  */
653                                 if (strncmp(v, "TRUE", 4) == 0) {
654                                         DEBUG(2, (" object %s is recycled, not returning linked attribute !\n",
655                                                                 ldb_dn_get_linearized(msg->dn)));
656                                         return WERR_OK;
657                                 }
658                         } else {
659                                 return WERR_OK;
660                         }
661                 }
662                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
663                 if (!NT_STATUS_IS_OK(status)) {
664                         DEBUG(0,(__location__ " Unable to extract GUID in linked attribute '%s' in '%s'\n",
665                                 sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
666                         return ntstatus_to_werror(status);
667                 }
668                 ret = dsdb_find_dn_by_guid(sam_ctx, mem_ctx, &guid, 0, &tdn);
669                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
670                         DEBUG(2, (" Search of guid %s returned 0 objects, skipping it !\n",
671                                                 GUID_string(mem_ctx, &guid)));
672                         return WERR_OK;
673                 } else if (ret != LDB_SUCCESS) {
674                         DEBUG(0, (__location__ " Search of guid %s failed with error code %d\n",
675                                                 GUID_string(mem_ctx, &guid),
676                                                 ret));
677                         return WERR_OK;
678                 }
679         }
680         la->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
681         la->flags = active?DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:0;
682
683         status = dsdb_get_extended_dn_uint32(dsdb_dn->dn, &la->meta_data.version, "RMD_VERSION");
684         if (!NT_STATUS_IS_OK(status)) {
685                 DEBUG(0,(__location__ " No RMD_VERSION in linked attribute '%s' in '%s'\n",
686                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
687                 return ntstatus_to_werror(status);
688         }
689         status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->meta_data.originating_change_time, "RMD_CHANGETIME");
690         if (!NT_STATUS_IS_OK(status)) {
691                 DEBUG(0,(__location__ " No RMD_CHANGETIME in linked attribute '%s' in '%s'\n",
692                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
693                 return ntstatus_to_werror(status);
694         }
695         status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &la->meta_data.originating_invocation_id, "RMD_INVOCID");
696         if (!NT_STATUS_IS_OK(status)) {
697                 DEBUG(0,(__location__ " No RMD_INVOCID in linked attribute '%s' in '%s'\n",
698                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
699                 return ntstatus_to_werror(status);
700         }
701         status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &la->meta_data.originating_usn, "RMD_ORIGINATING_USN");
702         if (!NT_STATUS_IS_OK(status)) {
703                 DEBUG(0,(__location__ " No RMD_ORIGINATING_USN in linked attribute '%s' in '%s'\n",
704                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
705                 return ntstatus_to_werror(status);
706         }
707
708         status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->originating_add_time, "RMD_ADDTIME");
709         if (!NT_STATUS_IS_OK(status)) {
710                 /* this is possible for upgraded links */
711                 la->originating_add_time = la->meta_data.originating_change_time;
712         }
713
714         werr = dsdb_dn_la_to_blob(sam_ctx, sa, schema, *la_list, dsdb_dn, &la->value.blob);
715         W_ERROR_NOT_OK_RETURN(werr);
716
717         (*la_count)++;
718         return WERR_OK;
719 }
720
721
722 /*
723   add linked attributes from an object to the list of linked
724   attributes in a getncchanges request
725  */
726 static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx,
727                                        TALLOC_CTX *mem_ctx,
728                                        struct ldb_dn *ncRoot_dn,
729                                        bool is_schema_nc,
730                                        struct dsdb_schema *schema,
731                                        uint64_t highest_usn,
732                                        uint32_t replica_flags,
733                                        const struct ldb_message *msg,
734                                        struct drsuapi_DsReplicaLinkedAttribute **la_list,
735                                        uint32_t *la_count,
736                                        struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector)
737 {
738         unsigned int i;
739         TALLOC_CTX *tmp_ctx = NULL;
740         uint64_t uSNChanged = ldb_msg_find_attr_as_uint64(msg, "uSNChanged", 0);
741         bool is_critical = ldb_msg_find_attr_as_bool(msg, "isCriticalSystemObject", false);
742
743         if (replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
744                 if (!is_critical) {
745                         return WERR_OK;
746                 }
747         }
748
749         if (uSNChanged <= highest_usn) {
750                 return WERR_OK;
751         }
752
753         tmp_ctx = talloc_new(mem_ctx);
754         if (tmp_ctx == NULL) {
755                 return WERR_NOT_ENOUGH_MEMORY;
756         }
757
758         for (i=0; i<msg->num_elements; i++) {
759                 struct ldb_message_element *el = &msg->elements[i];
760                 const struct dsdb_attribute *sa;
761                 unsigned int j;
762
763                 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
764
765                 if (!sa || sa->linkID == 0 || (sa->linkID & 1)) {
766                         /* we only want forward links */
767                         continue;
768                 }
769
770                 if (el->num_values && !dsdb_dn_is_upgraded_link_val(&el->values[0])) {
771                         /* its an old style link, it will have been
772                          * sent in the main replication data */
773                         continue;
774                 }
775
776                 for (j=0; j<el->num_values; j++) {
777                         struct dsdb_dn *dsdb_dn;
778                         uint64_t local_usn;
779                         uint64_t originating_usn;
780                         NTSTATUS status, status2;
781                         WERROR werr;
782                         struct GUID originating_invocation_id;
783
784                         dsdb_dn = dsdb_dn_parse(tmp_ctx, sam_ctx, &el->values[j], sa->syntax->ldap_oid);
785                         if (dsdb_dn == NULL) {
786                                 DEBUG(1,(__location__ ": Failed to parse DN for %s in %s\n",
787                                          el->name, ldb_dn_get_linearized(msg->dn)));
788                                 talloc_free(tmp_ctx);
789                                 return WERR_DS_DRA_INTERNAL_ERROR;
790                         }
791
792                         status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &local_usn, "RMD_LOCAL_USN");
793                         if (!NT_STATUS_IS_OK(status)) {
794                                 /* this can happen for attributes
795                                    given to us with old style meta
796                                    data */
797                                 continue;
798                         }
799
800                         if (local_usn > uSNChanged) {
801                                 DEBUG(1,(__location__ ": uSNChanged less than RMD_LOCAL_USN for %s on %s\n",
802                                          el->name, ldb_dn_get_linearized(msg->dn)));
803                                 talloc_free(tmp_ctx);
804                                 return WERR_DS_DRA_INTERNAL_ERROR;
805                         }
806
807                         if (local_usn <= highest_usn) {
808                                 continue;
809                         }
810
811                         status = dsdb_get_extended_dn_guid(dsdb_dn->dn,
812                                                            &originating_invocation_id,
813                                                            "RMD_INVOCID");
814                         status2 = dsdb_get_extended_dn_uint64(dsdb_dn->dn,
815                                                               &originating_usn,
816                                                               "RMD_ORIGINATING_USN");
817
818                         if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2)) {
819                                 if (udv_filter(uptodateness_vector,
820                                                &originating_invocation_id,
821                                                originating_usn)) {
822                                         continue;
823                                 }
824                         }
825
826                         werr = get_nc_changes_add_la(mem_ctx, sam_ctx, schema,
827                                                      sa, msg, dsdb_dn, la_list,
828                                                      la_count, is_schema_nc);
829                         if (!W_ERROR_IS_OK(werr)) {
830                                 talloc_free(tmp_ctx);
831                                 return werr;
832                         }
833                 }
834         }
835
836         talloc_free(tmp_ctx);
837         return WERR_OK;
838 }
839
840 /*
841   fill in the cursors return based on the replUpToDateVector for the ncRoot_dn
842  */
843 static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx,
844                                  struct ldb_dn *ncRoot_dn,
845                                  struct drsuapi_DsReplicaCursor2CtrEx *udv)
846 {
847         int ret;
848
849         udv->version = 2;
850         udv->reserved1 = 0;
851         udv->reserved2 = 0;
852
853         ret = dsdb_load_udv_v2(sam_ctx, ncRoot_dn, udv, &udv->cursors, &udv->count);
854         if (ret != LDB_SUCCESS) {
855                 DEBUG(0,(__location__ ": Failed to load UDV for %s - %s\n",
856                          ldb_dn_get_linearized(ncRoot_dn), ldb_errstring(sam_ctx)));
857                 return WERR_DS_DRA_INTERNAL_ERROR;
858         }
859
860         return WERR_OK;
861 }
862
863
864 /* comparison function for linked attributes - see CompareLinks() in
865  * MS-DRSR section 4.1.10.5.17 */
866 static int linked_attribute_compare(const struct la_for_sorting *la1,
867                                     const struct la_for_sorting *la2,
868                                     void *opaque)
869 {
870         int c;
871         c = memcmp(la1->source_guid,
872                    la2->source_guid, sizeof(la2->source_guid));
873         if (c != 0) {
874                 return c;
875         }
876
877         if (la1->link->attid != la2->link->attid) {
878                 return la1->link->attid < la2->link->attid? -1:1;
879         }
880
881         if ((la1->link->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) !=
882             (la2->link->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) {
883                 return (la1->link->flags &
884                         DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)? 1:-1;
885         }
886
887         return memcmp(la1->target_guid,
888                       la2->target_guid, sizeof(la2->target_guid));
889 }
890
891 struct drsuapi_changed_objects {
892         struct ldb_dn *dn;
893         struct GUID guid;
894         uint64_t usn;
895 };
896
897 /*
898   sort the objects we send first by uSNChanged
899  */
900 static int site_res_cmp_usn_order(struct drsuapi_changed_objects *m1,
901                                   struct drsuapi_changed_objects *m2,
902                                   struct drsuapi_getncchanges_state *getnc_state)
903 {
904         int ret;
905
906         ret = ldb_dn_compare(getnc_state->ncRoot_dn, m1->dn);
907         if (ret == 0) {
908                 return -1;
909         }
910
911         ret = ldb_dn_compare(getnc_state->ncRoot_dn, m2->dn);
912         if (ret == 0) {
913                 return 1;
914         }
915
916         if (m1->usn == m2->usn) {
917                 return ldb_dn_compare(m2->dn, m1->dn);
918         }
919
920         if (m1->usn < m2->usn) {
921                 return -1;
922         }
923
924         return 1;
925 }
926
927
928 /*
929   handle a DRSUAPI_EXOP_FSMO_RID_ALLOC call
930  */
931 static WERROR getncchanges_rid_alloc(struct drsuapi_bind_state *b_state,
932                                      TALLOC_CTX *mem_ctx,
933                                      struct drsuapi_DsGetNCChangesRequest10 *req10,
934                                      struct drsuapi_DsGetNCChangesCtr6 *ctr6,
935                                      struct ldb_dn **rid_manager_dn)
936 {
937         struct ldb_dn *req_dn, *ntds_dn = NULL;
938         int ret;
939         struct ldb_context *ldb = b_state->sam_ctx;
940         struct ldb_result *ext_res;
941         struct dsdb_fsmo_extended_op *exop;
942         bool is_us;
943
944         /*
945           steps:
946             - verify that the DN being asked for is the RID Manager DN
947             - verify that we are the RID Manager
948          */
949
950         /* work out who is the RID Manager, also return to caller */
951         ret = samdb_rid_manager_dn(ldb, mem_ctx, rid_manager_dn);
952         if (ret != LDB_SUCCESS) {
953                 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s\n", ldb_errstring(ldb)));
954                 return WERR_DS_DRA_INTERNAL_ERROR;
955         }
956
957         req_dn = drs_ObjectIdentifier_to_dn(mem_ctx, ldb, req10->naming_context);
958         if (!ldb_dn_validate(req_dn) ||
959             ldb_dn_compare(req_dn, *rid_manager_dn) != 0) {
960                 /* that isn't the RID Manager DN */
961                 DEBUG(0,(__location__ ": RID Alloc request for wrong DN %s\n",
962                          drs_ObjectIdentifier_to_string(mem_ctx, req10->naming_context)));
963                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
964                 return WERR_OK;
965         }
966
967         /* TODO: make sure ntds_dn is a valid nTDSDSA object */
968         ret = dsdb_find_dn_by_guid(ldb, mem_ctx, &req10->destination_dsa_guid, 0, &ntds_dn);
969         if (ret != LDB_SUCCESS) {
970                 DEBUG(0, (__location__ ": Unable to find NTDS object for guid %s - %s\n",
971                           GUID_string(mem_ctx, &req10->destination_dsa_guid), ldb_errstring(ldb)));
972                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_UNKNOWN_CALLER;
973                 return WERR_OK;
974         }
975
976         /* find the DN of the RID Manager */
977         ret = samdb_reference_dn_is_our_ntdsa(ldb, *rid_manager_dn, "fSMORoleOwner", &is_us);
978         if (ret != LDB_SUCCESS) {
979                 DEBUG(0,("Failed to find fSMORoleOwner in RID Manager object\n"));
980                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
981                 return WERR_DS_DRA_INTERNAL_ERROR;
982         }
983
984         if (!is_us) {
985                 /* we're not the RID Manager - go away */
986                 DEBUG(0,(__location__ ": RID Alloc request when not RID Manager\n"));
987                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
988                 return WERR_OK;
989         }
990
991         exop = talloc(mem_ctx, struct dsdb_fsmo_extended_op);
992         W_ERROR_HAVE_NO_MEMORY(exop);
993
994         exop->fsmo_info = req10->fsmo_info;
995         exop->destination_dsa_guid = req10->destination_dsa_guid;
996
997         ret = ldb_transaction_start(ldb);
998         if (ret != LDB_SUCCESS) {
999                 DEBUG(0,(__location__ ": Failed transaction start - %s\n",
1000                          ldb_errstring(ldb)));
1001                 return WERR_DS_DRA_INTERNAL_ERROR;
1002         }
1003
1004         ret = ldb_extended(ldb, DSDB_EXTENDED_ALLOCATE_RID_POOL, exop, &ext_res);
1005         if (ret != LDB_SUCCESS) {
1006                 DEBUG(0,(__location__ ": Failed extended allocation RID pool operation - %s\n",
1007                          ldb_errstring(ldb)));
1008                 ldb_transaction_cancel(ldb);
1009                 return WERR_DS_DRA_INTERNAL_ERROR;
1010         }
1011
1012         ret = ldb_transaction_commit(ldb);
1013         if (ret != LDB_SUCCESS) {
1014                 DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
1015                          ldb_errstring(ldb)));
1016                 return WERR_DS_DRA_INTERNAL_ERROR;
1017         }
1018
1019         talloc_free(ext_res);
1020
1021         DEBUG(2,("Allocated RID pool for server %s\n",
1022                  GUID_string(mem_ctx, &req10->destination_dsa_guid)));
1023
1024         ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
1025
1026         return WERR_OK;
1027 }
1028
1029 /*
1030   return an array of SIDs from a ldb_message given an attribute name
1031   assumes the SIDs are in extended DN format
1032  */
1033 static WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx,
1034                                         struct ldb_message *msg,
1035                                         TALLOC_CTX *mem_ctx,
1036                                         const char *attr,
1037                                         const struct dom_sid ***sids)
1038 {
1039         struct ldb_message_element *el;
1040         unsigned int i;
1041
1042         el = ldb_msg_find_element(msg, attr);
1043         if (!el) {
1044                 *sids = NULL;
1045                 return WERR_OK;
1046         }
1047
1048         (*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1);
1049         W_ERROR_HAVE_NO_MEMORY(*sids);
1050
1051         for (i=0; i<el->num_values; i++) {
1052                 struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]);
1053                 NTSTATUS status;
1054                 struct dom_sid *sid;
1055
1056                 sid = talloc(*sids, struct dom_sid);
1057                 W_ERROR_HAVE_NO_MEMORY(sid);
1058                 status = dsdb_get_extended_dn_sid(dn, sid, "SID");
1059                 if (!NT_STATUS_IS_OK(status)) {
1060                         return WERR_INTERNAL_DB_CORRUPTION;
1061                 }
1062                 (*sids)[i] = sid;
1063         }
1064         (*sids)[i] = NULL;
1065
1066         return WERR_OK;
1067 }
1068
1069
1070 /*
1071   return an array of SIDs from a ldb_message given an attribute name
1072   assumes the SIDs are in NDR form
1073  */
1074 static WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
1075                                          struct ldb_message *msg,
1076                                          TALLOC_CTX *mem_ctx,
1077                                          const char *attr,
1078                                          const struct dom_sid ***sids)
1079 {
1080         struct ldb_message_element *el;
1081         unsigned int i;
1082
1083         el = ldb_msg_find_element(msg, attr);
1084         if (!el) {
1085                 *sids = NULL;
1086                 return WERR_OK;
1087         }
1088
1089         (*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1);
1090         W_ERROR_HAVE_NO_MEMORY(*sids);
1091
1092         for (i=0; i<el->num_values; i++) {
1093                 enum ndr_err_code ndr_err;
1094                 struct dom_sid *sid;
1095
1096                 sid = talloc(*sids, struct dom_sid);
1097                 W_ERROR_HAVE_NO_MEMORY(sid);
1098
1099                 ndr_err = ndr_pull_struct_blob(&el->values[i], sid, sid,
1100                                                (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
1101                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1102                         return WERR_INTERNAL_DB_CORRUPTION;
1103                 }
1104                 (*sids)[i] = sid;
1105         }
1106         (*sids)[i] = NULL;
1107
1108         return WERR_OK;
1109 }
1110
1111 /*
1112   see if any SIDs in list1 are in list2
1113  */
1114 static bool sid_list_match(const struct dom_sid **list1, const struct dom_sid **list2)
1115 {
1116         unsigned int i, j;
1117         /* do we ever have enough SIDs here to worry about O(n^2) ? */
1118         for (i=0; list1[i]; i++) {
1119                 for (j=0; list2[j]; j++) {
1120                         if (dom_sid_equal(list1[i], list2[j])) {
1121                                 return true;
1122                         }
1123                 }
1124         }
1125         return false;
1126 }
1127
1128 /*
1129   handle a DRSUAPI_EXOP_REPL_SECRET call
1130  */
1131 static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state,
1132                                        TALLOC_CTX *mem_ctx,
1133                                        struct drsuapi_DsGetNCChangesRequest10 *req10,
1134                                        struct dom_sid *user_sid,
1135                                        struct drsuapi_DsGetNCChangesCtr6 *ctr6,
1136                                        bool has_get_all_changes,
1137                                        struct ldb_dn **machine_dn)
1138 {
1139         struct drsuapi_DsReplicaObjectIdentifier *ncRoot = req10->naming_context;
1140         struct ldb_dn *obj_dn = NULL;
1141         struct ldb_dn *ntds_dn = NULL, *server_dn = NULL;
1142         struct ldb_dn *rodc_dn, *krbtgt_link_dn;
1143         int ret;
1144         const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL };
1145         const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL };
1146         struct ldb_result *rodc_res, *obj_res;
1147         const struct dom_sid **never_reveal_sids, **reveal_sids, **token_sids;
1148         WERROR werr;
1149
1150         DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_SECRET extended op on %s\n",
1151                  drs_ObjectIdentifier_to_string(mem_ctx, ncRoot)));
1152
1153         /*
1154          * we need to work out if we will allow this DC to
1155          * replicate the secrets for this object
1156          *
1157          * see 4.1.10.5.14 GetRevealSecretsPolicyForUser for details
1158          * of this function
1159          */
1160
1161         if (b_state->sam_ctx_system == NULL) {
1162                 /* this operation needs system level access */
1163                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_ACCESS_DENIED;
1164                 return WERR_DS_DRA_SOURCE_DISABLED;
1165         }
1166
1167         /*
1168          * Before we accept or deny, fetch the machine DN for the destination
1169          * DSA GUID.
1170          *
1171          * If we are the RODC, we will check that this matches the SID.
1172          */
1173         ret = dsdb_find_dn_by_guid(b_state->sam_ctx_system, mem_ctx,
1174                                    &req10->destination_dsa_guid, 0,
1175                                    &ntds_dn);
1176         if (ret != LDB_SUCCESS) {
1177                 goto failed;
1178         }
1179
1180         server_dn = ldb_dn_get_parent(mem_ctx, ntds_dn);
1181         if (server_dn == NULL) {
1182                 goto failed;
1183         }
1184
1185         ret = samdb_reference_dn(b_state->sam_ctx_system, mem_ctx, server_dn,
1186                                  "serverReference", machine_dn);
1187
1188         if (ret != LDB_SUCCESS) {
1189                 goto failed;
1190         }
1191
1192         /*
1193          * In MS-DRSR.pdf 5.99 IsGetNCChangesPermissionGranted
1194          *
1195          * The pseudo code indicate
1196          * revealsecrets = true
1197          * if IsRevealSecretRequest(msgIn) then
1198          *   if AccessCheckCAR(ncRoot, Ds-Replication-Get-Changes-All) = false
1199          *   then
1200          *     if (msgIn.ulExtendedOp = EXOP_REPL_SECRETS) then
1201          *     <... check if this account is ok to be replicated on this DC ...>
1202          *     <... and if not reveal secrets = no ...>
1203          *     else
1204          *       reveal secrets = false
1205          *     endif
1206          *   endif
1207          * endif
1208          *
1209          * Which basically means that if you have GET_ALL_CHANGES rights (~== RWDC)
1210          * then you can do EXOP_REPL_SECRETS
1211          */
1212         if (has_get_all_changes) {
1213                 goto allowed;
1214         }
1215
1216         obj_dn = drs_ObjectIdentifier_to_dn(mem_ctx, b_state->sam_ctx_system, ncRoot);
1217         if (!ldb_dn_validate(obj_dn)) goto failed;
1218
1219         rodc_dn = ldb_dn_new_fmt(mem_ctx, b_state->sam_ctx_system, "<SID=%s>",
1220                                  dom_sid_string(mem_ctx, user_sid));
1221         if (!ldb_dn_validate(rodc_dn)) goto failed;
1222
1223         /* do the two searches we need */
1224         ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &rodc_res, rodc_dn, rodc_attrs,
1225                              DSDB_SEARCH_SHOW_EXTENDED_DN);
1226         if (ret != LDB_SUCCESS || rodc_res->count != 1) goto failed;
1227
1228         ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &obj_res, obj_dn, obj_attrs, 0);
1229         if (ret != LDB_SUCCESS || obj_res->count != 1) goto failed;
1230
1231         /* if the object SID is equal to the user_sid, allow */
1232         if (dom_sid_equal(user_sid,
1233                           samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid"))) {
1234                 goto allowed;
1235         }
1236
1237         /*
1238          * Must be an RODC account at this point, verify machine DN matches the
1239          * SID account
1240          */
1241         if (ldb_dn_compare(rodc_res->msgs[0]->dn, *machine_dn) != 0) {
1242                 goto denied;
1243         }
1244
1245         /* an RODC is allowed to get its own krbtgt account secrets */
1246         krbtgt_link_dn = samdb_result_dn(b_state->sam_ctx_system, mem_ctx,
1247                                          rodc_res->msgs[0], "msDS-KrbTgtLink", NULL);
1248         if (krbtgt_link_dn != NULL &&
1249             ldb_dn_compare(obj_dn, krbtgt_link_dn) == 0) {
1250                 goto allowed;
1251         }
1252
1253         /* but it isn't allowed to get anyone elses krbtgt secrets */
1254         if (samdb_result_dn(b_state->sam_ctx_system, mem_ctx,
1255                             obj_res->msgs[0], "msDS-KrbTgtLinkBL", NULL)) {
1256                 goto denied;
1257         }
1258
1259         if (ldb_msg_find_attr_as_uint(obj_res->msgs[0],
1260                                       "userAccountControl", 0) &
1261             UF_INTERDOMAIN_TRUST_ACCOUNT) {
1262                 goto denied;
1263         }
1264
1265         werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0],
1266                                          mem_ctx, "msDS-NeverRevealGroup", &never_reveal_sids);
1267         if (!W_ERROR_IS_OK(werr)) {
1268                 goto denied;
1269         }
1270
1271         werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0],
1272                                          mem_ctx, "msDS-RevealOnDemandGroup", &reveal_sids);
1273         if (!W_ERROR_IS_OK(werr)) {
1274                 goto denied;
1275         }
1276
1277         werr = samdb_result_sid_array_ndr(b_state->sam_ctx_system, obj_res->msgs[0],
1278                                          mem_ctx, "tokenGroups", &token_sids);
1279         if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
1280                 goto denied;
1281         }
1282
1283         if (never_reveal_sids &&
1284             sid_list_match(token_sids, never_reveal_sids)) {
1285                 goto denied;
1286         }
1287
1288         if (reveal_sids &&
1289             sid_list_match(token_sids, reveal_sids)) {
1290                 goto allowed;
1291         }
1292
1293         /* default deny */
1294 denied:
1295         DEBUG(2,(__location__ ": Denied single object with secret replication for %s by RODC %s\n",
1296                  ldb_dn_get_linearized(obj_dn), ldb_dn_get_linearized(rodc_res->msgs[0]->dn)));
1297         ctr6->extended_ret = DRSUAPI_EXOP_ERR_NONE;
1298         return WERR_DS_DRA_SECRETS_DENIED;
1299
1300 allowed:
1301         DEBUG(2,(__location__ ": Allowed single object with secret replication for %s by %s %s\n",
1302                  ldb_dn_get_linearized(obj_dn), has_get_all_changes?"RWDC":"RODC",
1303                  ldb_dn_get_linearized(rodc_res->msgs[0]->dn)));
1304         ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
1305         req10->highwatermark.highest_usn = 0;
1306         return WERR_OK;
1307
1308 failed:
1309         DEBUG(2,(__location__ ": Failed single secret replication for %s by RODC %s\n",
1310                  ldb_dn_get_linearized(obj_dn), dom_sid_string(mem_ctx, user_sid)));
1311         ctr6->extended_ret = DRSUAPI_EXOP_ERR_NONE;
1312         return WERR_DS_DRA_BAD_DN;
1313 }
1314
1315 /*
1316   handle a DRSUAPI_EXOP_REPL_OBJ call
1317  */
1318 static WERROR getncchanges_repl_obj(struct drsuapi_bind_state *b_state,
1319                                     TALLOC_CTX *mem_ctx,
1320                                     struct drsuapi_DsGetNCChangesRequest10 *req10,
1321                                     struct dom_sid *user_sid,
1322                                     struct drsuapi_DsGetNCChangesCtr6 *ctr6)
1323 {
1324         struct drsuapi_DsReplicaObjectIdentifier *ncRoot = req10->naming_context;
1325
1326         DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_OBJ extended op on %s\n",
1327                  drs_ObjectIdentifier_to_string(mem_ctx, ncRoot)));
1328
1329         ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
1330         return WERR_OK;
1331 }
1332
1333
1334 /*
1335   handle DRSUAPI_EXOP_FSMO_REQ_ROLE,
1336   DRSUAPI_EXOP_FSMO_RID_REQ_ROLE,
1337   and DRSUAPI_EXOP_FSMO_REQ_PDC calls
1338  */
1339 static WERROR getncchanges_change_master(struct drsuapi_bind_state *b_state,
1340                                          TALLOC_CTX *mem_ctx,
1341                                          struct drsuapi_DsGetNCChangesRequest10 *req10,
1342                                          struct drsuapi_DsGetNCChangesCtr6 *ctr6)
1343 {
1344         struct ldb_dn *req_dn, *ntds_dn;
1345         int ret;
1346         unsigned int i;
1347         struct ldb_context *ldb = b_state->sam_ctx;
1348         struct ldb_message *msg;
1349         bool is_us;
1350
1351         /*
1352           steps:
1353             - verify that the client dn exists
1354             - verify that we are the current master
1355          */
1356
1357         req_dn = drs_ObjectIdentifier_to_dn(mem_ctx, ldb, req10->naming_context);
1358         if (!ldb_dn_validate(req_dn)) {
1359                 /* that is not a valid dn */
1360                 DEBUG(0,(__location__ ": FSMO role transfer request for invalid DN %s\n",
1361                          drs_ObjectIdentifier_to_string(mem_ctx, req10->naming_context)));
1362                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
1363                 return WERR_OK;
1364         }
1365
1366         /* find the DN of the current role owner */
1367         ret = samdb_reference_dn_is_our_ntdsa(ldb, req_dn, "fSMORoleOwner", &is_us);
1368         if (ret != LDB_SUCCESS) {
1369                 DEBUG(0,("Failed to find fSMORoleOwner in RID Manager object\n"));
1370                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
1371                 return WERR_DS_DRA_INTERNAL_ERROR;
1372         }
1373
1374         if (!is_us) {
1375                 /* we're not the RID Manager or role owner - go away */
1376                 DEBUG(0,(__location__ ": FSMO role or RID manager transfer owner request when not role owner\n"));
1377                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
1378                 return WERR_OK;
1379         }
1380
1381         /* change the current master */
1382         msg = ldb_msg_new(ldb);
1383         W_ERROR_HAVE_NO_MEMORY(msg);
1384         msg->dn = drs_ObjectIdentifier_to_dn(msg, ldb, req10->naming_context);
1385         W_ERROR_HAVE_NO_MEMORY(msg->dn);
1386
1387         /* TODO: make sure ntds_dn is a valid nTDSDSA object */
1388         ret = dsdb_find_dn_by_guid(ldb, msg, &req10->destination_dsa_guid, 0, &ntds_dn);
1389         if (ret != LDB_SUCCESS) {
1390                 DEBUG(0, (__location__ ": Unable to find NTDS object for guid %s - %s\n",
1391                           GUID_string(mem_ctx, &req10->destination_dsa_guid), ldb_errstring(ldb)));
1392                 talloc_free(msg);
1393                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_UNKNOWN_CALLER;
1394                 return WERR_OK;
1395         }
1396
1397         ret = ldb_msg_add_string(msg, "fSMORoleOwner", ldb_dn_get_linearized(ntds_dn));
1398         if (ret != 0) {
1399                 talloc_free(msg);
1400                 return WERR_DS_DRA_INTERNAL_ERROR;
1401         }
1402
1403         for (i=0;i<msg->num_elements;i++) {
1404                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1405         }
1406
1407         ret = ldb_transaction_start(ldb);
1408         if (ret != LDB_SUCCESS) {
1409                 DEBUG(0,(__location__ ": Failed transaction start - %s\n",
1410                          ldb_errstring(ldb)));
1411                 return WERR_DS_DRA_INTERNAL_ERROR;
1412         }
1413
1414         ret = ldb_modify(ldb, msg);
1415         if (ret != LDB_SUCCESS) {
1416                 DEBUG(0,(__location__ ": Failed to change current owner - %s\n",
1417                          ldb_errstring(ldb)));
1418                 ldb_transaction_cancel(ldb);
1419                 return WERR_DS_DRA_INTERNAL_ERROR;
1420         }
1421
1422         ret = ldb_transaction_commit(ldb);
1423         if (ret != LDB_SUCCESS) {
1424                 DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
1425                          ldb_errstring(ldb)));
1426                 return WERR_DS_DRA_INTERNAL_ERROR;
1427         }
1428
1429         ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
1430
1431         return WERR_OK;
1432 }
1433
1434 /*
1435   see if this getncchanges request includes a request to reveal secret information
1436  */
1437 static WERROR dcesrv_drsuapi_is_reveal_secrets_request(struct drsuapi_bind_state *b_state,
1438                                                        struct drsuapi_DsGetNCChangesRequest10 *req10,
1439                                                        struct dsdb_schema_prefixmap *pfm_remote,
1440                                                        bool *is_secret_request)
1441 {
1442         enum drsuapi_DsExtendedOperation exop;
1443         uint32_t i;
1444         struct dsdb_schema *schema;
1445         struct dsdb_syntax_ctx syntax_ctx;
1446
1447         *is_secret_request = true;
1448
1449         exop = req10->extended_op;
1450
1451         switch (exop) {
1452         case DRSUAPI_EXOP_FSMO_REQ_ROLE:
1453         case DRSUAPI_EXOP_FSMO_RID_ALLOC:
1454         case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
1455         case DRSUAPI_EXOP_FSMO_REQ_PDC:
1456         case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
1457                 /* FSMO exops can reveal secrets */
1458                 *is_secret_request = true;
1459                 return WERR_OK;
1460         case DRSUAPI_EXOP_REPL_SECRET:
1461         case DRSUAPI_EXOP_REPL_OBJ:
1462         case DRSUAPI_EXOP_NONE:
1463                 break;
1464         }
1465
1466         if (req10->replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
1467                 *is_secret_request = false;
1468                 return WERR_OK;
1469         }
1470
1471         if (exop == DRSUAPI_EXOP_REPL_SECRET ||
1472             req10->partial_attribute_set == NULL) {
1473                 /* they want secrets */
1474                 *is_secret_request = true;
1475                 return WERR_OK;
1476         }
1477
1478         schema = dsdb_get_schema(b_state->sam_ctx, NULL);
1479         dsdb_syntax_ctx_init(&syntax_ctx, b_state->sam_ctx, schema);
1480         syntax_ctx.pfm_remote = pfm_remote;
1481
1482         /* check the attributes they asked for */
1483         for (i=0; i<req10->partial_attribute_set->num_attids; i++) {
1484                 const struct dsdb_attribute *sa;
1485                 WERROR werr = getncchanges_attid_remote_to_local(schema,
1486                                                                  &syntax_ctx,
1487                                                                  req10->partial_attribute_set->attids[i],
1488                                                                  NULL,
1489                                                                  &sa);
1490
1491                 if (!W_ERROR_IS_OK(werr)) {
1492                         DEBUG(0,(__location__": attid 0x%08X not found: %s\n",
1493                                  req10->partial_attribute_set->attids[i], win_errstr(werr)));
1494                         return werr;
1495                 }
1496
1497                 if (!dsdb_attr_in_rodc_fas(sa)) {
1498                         *is_secret_request = true;
1499                         return WERR_OK;
1500                 }
1501         }
1502
1503         if (req10->partial_attribute_set_ex) {
1504                 /* check the extended attributes they asked for */
1505                 for (i=0; i<req10->partial_attribute_set_ex->num_attids; i++) {
1506                         const struct dsdb_attribute *sa;
1507                         WERROR werr = getncchanges_attid_remote_to_local(schema,
1508                                                                          &syntax_ctx,
1509                                                                          req10->partial_attribute_set_ex->attids[i],
1510                                                                          NULL,
1511                                                                          &sa);
1512
1513                         if (!W_ERROR_IS_OK(werr)) {
1514                                 DEBUG(0,(__location__": attid 0x%08X not found: %s\n",
1515                                          req10->partial_attribute_set_ex->attids[i], win_errstr(werr)));
1516                                 return werr;
1517                         }
1518
1519                         if (!dsdb_attr_in_rodc_fas(sa)) {
1520                                 *is_secret_request = true;
1521                                 return WERR_OK;
1522                         }
1523                 }
1524         }
1525
1526         *is_secret_request = false;
1527         return WERR_OK;
1528 }
1529
1530 /*
1531   see if this getncchanges request is only for attributes in the GC
1532   partial attribute set
1533  */
1534 static WERROR dcesrv_drsuapi_is_gc_pas_request(struct drsuapi_bind_state *b_state,
1535                                                struct drsuapi_DsGetNCChangesRequest10 *req10,
1536                                                struct dsdb_schema_prefixmap *pfm_remote,
1537                                                bool *is_gc_pas_request)
1538 {
1539         enum drsuapi_DsExtendedOperation exop;
1540         uint32_t i;
1541         struct dsdb_schema *schema;
1542         struct dsdb_syntax_ctx syntax_ctx;
1543
1544         exop = req10->extended_op;
1545
1546         switch (exop) {
1547         case DRSUAPI_EXOP_FSMO_REQ_ROLE:
1548         case DRSUAPI_EXOP_FSMO_RID_ALLOC:
1549         case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
1550         case DRSUAPI_EXOP_FSMO_REQ_PDC:
1551         case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
1552         case DRSUAPI_EXOP_REPL_SECRET:
1553                 *is_gc_pas_request = false;
1554                 return WERR_OK;
1555         case DRSUAPI_EXOP_REPL_OBJ:
1556         case DRSUAPI_EXOP_NONE:
1557                 break;
1558         }
1559
1560         if (req10->partial_attribute_set == NULL) {
1561                 /* they want it all */
1562                 *is_gc_pas_request = false;
1563                 return WERR_OK;
1564         }
1565
1566         schema = dsdb_get_schema(b_state->sam_ctx, NULL);
1567         dsdb_syntax_ctx_init(&syntax_ctx, b_state->sam_ctx, schema);
1568         syntax_ctx.pfm_remote = pfm_remote;
1569
1570         /* check the attributes they asked for */
1571         for (i=0; i<req10->partial_attribute_set->num_attids; i++) {
1572                 const struct dsdb_attribute *sa;
1573                 WERROR werr = getncchanges_attid_remote_to_local(schema,
1574                                                                  &syntax_ctx,
1575                                                                  req10->partial_attribute_set->attids[i],
1576                                                                  NULL,
1577                                                                  &sa);
1578
1579                 if (!W_ERROR_IS_OK(werr)) {
1580                         DEBUG(0,(__location__": attid 0x%08X not found: %s\n",
1581                                  req10->partial_attribute_set->attids[i], win_errstr(werr)));
1582                         return werr;
1583                 }
1584
1585                 if (!sa->isMemberOfPartialAttributeSet) {
1586                         *is_gc_pas_request = false;
1587                         return WERR_OK;
1588                 }
1589         }
1590
1591         if (req10->partial_attribute_set_ex) {
1592                 /* check the extended attributes they asked for */
1593                 for (i=0; i<req10->partial_attribute_set_ex->num_attids; i++) {
1594                         const struct dsdb_attribute *sa;
1595                         WERROR werr = getncchanges_attid_remote_to_local(schema,
1596                                                                          &syntax_ctx,
1597                                                                          req10->partial_attribute_set_ex->attids[i],
1598                                                                          NULL,
1599                                                                          &sa);
1600
1601                         if (!W_ERROR_IS_OK(werr)) {
1602                                 DEBUG(0,(__location__": attid 0x%08X not found: %s\n",
1603                                          req10->partial_attribute_set_ex->attids[i], win_errstr(werr)));
1604                                 return werr;
1605                         }
1606
1607                         if (!sa->isMemberOfPartialAttributeSet) {
1608                                 *is_gc_pas_request = false;
1609                                 return WERR_OK;
1610                         }
1611                 }
1612         }
1613
1614         *is_gc_pas_request = true;
1615         return WERR_OK;
1616 }
1617
1618
1619 /*
1620   map from req8 to req10
1621  */
1622 static struct drsuapi_DsGetNCChangesRequest10 *
1623 getncchanges_map_req8(TALLOC_CTX *mem_ctx,
1624                       struct drsuapi_DsGetNCChangesRequest8 *req8)
1625 {
1626         struct drsuapi_DsGetNCChangesRequest10 *req10 = talloc_zero(mem_ctx,
1627                                                                     struct drsuapi_DsGetNCChangesRequest10);
1628         if (req10 == NULL) {
1629                 return NULL;
1630         }
1631
1632         req10->destination_dsa_guid = req8->destination_dsa_guid;
1633         req10->source_dsa_invocation_id = req8->source_dsa_invocation_id;
1634         req10->naming_context = req8->naming_context;
1635         req10->highwatermark = req8->highwatermark;
1636         req10->uptodateness_vector = req8->uptodateness_vector;
1637         req10->replica_flags = req8->replica_flags;
1638         req10->max_object_count = req8->max_object_count;
1639         req10->max_ndr_size = req8->max_ndr_size;
1640         req10->extended_op = req8->extended_op;
1641         req10->fsmo_info = req8->fsmo_info;
1642         req10->partial_attribute_set = req8->partial_attribute_set;
1643         req10->partial_attribute_set_ex = req8->partial_attribute_set_ex;
1644         req10->mapping_ctr = req8->mapping_ctr;
1645
1646         return req10;
1647 }
1648
1649 static const char *collect_objects_attrs[] = { "uSNChanged",
1650                                                "objectGUID" ,
1651                                                NULL };
1652
1653 /**
1654  * Collects object for normal replication cycle.
1655  */
1656 static WERROR getncchanges_collect_objects(struct drsuapi_bind_state *b_state,
1657                                            TALLOC_CTX *mem_ctx,
1658                                            struct drsuapi_DsGetNCChangesRequest10 *req10,
1659                                            struct ldb_dn *search_dn,
1660                                            const char *extra_filter,
1661                                            struct ldb_result **search_res)
1662 {
1663         int ret;
1664         char* search_filter;
1665         enum ldb_scope scope = LDB_SCOPE_SUBTREE;
1666         struct drsuapi_getncchanges_state *getnc_state = b_state->getncchanges_state;
1667         bool critical_only = false;
1668
1669         if (req10->replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
1670                 critical_only = true;
1671         }
1672
1673         if (req10->extended_op == DRSUAPI_EXOP_REPL_OBJ ||
1674             req10->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
1675                 scope = LDB_SCOPE_BASE;
1676                 critical_only = false;
1677         }
1678
1679         /* Construct response. */
1680         search_filter = talloc_asprintf(mem_ctx,
1681                                         "(uSNChanged>=%llu)",
1682                                         (unsigned long long)(getnc_state->min_usn+1));
1683
1684         if (extra_filter) {
1685                 search_filter = talloc_asprintf(mem_ctx, "(&%s(%s))", search_filter, extra_filter);
1686         }
1687
1688         if (critical_only) {
1689                 search_filter = talloc_asprintf(mem_ctx,
1690                                                 "(&%s(isCriticalSystemObject=TRUE))",
1691                                                 search_filter);
1692         }
1693
1694         if (req10->replica_flags & DRSUAPI_DRS_ASYNC_REP) {
1695                 scope = LDB_SCOPE_BASE;
1696         }
1697
1698         if (!search_dn) {
1699                 search_dn = getnc_state->ncRoot_dn;
1700         }
1701
1702         DEBUG(2,(__location__ ": getncchanges on %s using filter %s\n",
1703                  ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter));
1704         ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, getnc_state, search_res,
1705                                               search_dn, scope,
1706                                               collect_objects_attrs,
1707                                               search_filter);
1708         if (ret != LDB_SUCCESS) {
1709                 return WERR_DS_DRA_INTERNAL_ERROR;
1710         }
1711
1712         return WERR_OK;
1713 }
1714
1715 /**
1716  * Collects object for normal replication cycle.
1717  */
1718 static WERROR getncchanges_collect_objects_exop(struct drsuapi_bind_state *b_state,
1719                                                 TALLOC_CTX *mem_ctx,
1720                                                 struct drsuapi_DsGetNCChangesRequest10 *req10,
1721                                                 struct drsuapi_DsGetNCChangesCtr6 *ctr6,
1722                                                 struct ldb_dn *search_dn,
1723                                                 const char *extra_filter,
1724                                                 struct ldb_result **search_res)
1725 {
1726         /* we have nothing to do in case of ex-op failure */
1727         if (ctr6->extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
1728                 return WERR_OK;
1729         }
1730
1731         switch (req10->extended_op) {
1732         case DRSUAPI_EXOP_FSMO_RID_ALLOC:
1733         {
1734                 int ret;
1735                 struct ldb_dn *ntds_dn = NULL;
1736                 struct ldb_dn *server_dn = NULL;
1737                 struct ldb_dn *machine_dn = NULL;
1738                 struct ldb_dn *rid_set_dn = NULL;
1739                 struct ldb_result *search_res2 = NULL;
1740                 struct ldb_result *search_res3 = NULL;
1741                 TALLOC_CTX *frame = talloc_stackframe();
1742                 /* get RID manager, RID set and server DN (in that order) */
1743
1744                 /* This first search will get the RID Manager */
1745                 ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, frame,
1746                                                       search_res,
1747                                                       search_dn, LDB_SCOPE_BASE,
1748                                                       collect_objects_attrs,
1749                                                       NULL);
1750                 if (ret != LDB_SUCCESS) {
1751                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Manager object %s - %s",
1752                                   ldb_dn_get_linearized(search_dn),
1753                                   ldb_errstring(b_state->sam_ctx)));
1754                         TALLOC_FREE(frame);
1755                         return WERR_DS_DRA_INTERNAL_ERROR;
1756                 }
1757
1758                 if ((*search_res)->count != 1) {
1759                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Manager object %s - %u objects returned",
1760                                   ldb_dn_get_linearized(search_dn),
1761                                   (*search_res)->count));
1762                         TALLOC_FREE(frame);
1763                         return WERR_DS_DRA_INTERNAL_ERROR;
1764                 }
1765
1766                 /* Now extend it to the RID set */
1767
1768                 /* Find the computer account DN for the destination
1769                  * dsa GUID specified */
1770
1771                 ret = dsdb_find_dn_by_guid(b_state->sam_ctx, frame,
1772                                            &req10->destination_dsa_guid, 0,
1773                                            &ntds_dn);
1774                 if (ret != LDB_SUCCESS) {
1775                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Unable to find NTDS object for guid %s - %s\n",
1776                                   GUID_string(frame,
1777                                               &req10->destination_dsa_guid),
1778                                   ldb_errstring(b_state->sam_ctx)));
1779                         TALLOC_FREE(frame);
1780                         return WERR_DS_DRA_INTERNAL_ERROR;
1781                 }
1782
1783                 server_dn = ldb_dn_get_parent(frame, ntds_dn);
1784                 if (!server_dn) {
1785                         TALLOC_FREE(frame);
1786                         return WERR_DS_DRA_INTERNAL_ERROR;
1787                 }
1788
1789                 ret = samdb_reference_dn(b_state->sam_ctx, frame, server_dn,
1790                                          "serverReference", &machine_dn);
1791                 if (ret != LDB_SUCCESS) {
1792                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to find serverReference in %s - %s",
1793                                   ldb_dn_get_linearized(server_dn),
1794                                   ldb_errstring(b_state->sam_ctx)));
1795                         TALLOC_FREE(frame);
1796                         return WERR_DS_DRA_INTERNAL_ERROR;
1797                 }
1798
1799                 ret = samdb_reference_dn(b_state->sam_ctx, frame, machine_dn,
1800                                          "rIDSetReferences", &rid_set_dn);
1801                 if (ret != LDB_SUCCESS) {
1802                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to find rIDSetReferences in %s - %s",
1803                                   ldb_dn_get_linearized(server_dn),
1804                                   ldb_errstring(b_state->sam_ctx)));
1805                         TALLOC_FREE(frame);
1806                         return WERR_DS_DRA_INTERNAL_ERROR;
1807                 }
1808
1809
1810                 /* This first search will get the RID Manager, now get the RID set */
1811                 ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, frame,
1812                                                       &search_res2,
1813                                                       rid_set_dn, LDB_SCOPE_BASE,
1814                                                       collect_objects_attrs,
1815                                                       NULL);
1816                 if (ret != LDB_SUCCESS) {
1817                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Set object %s - %s",
1818                                   ldb_dn_get_linearized(rid_set_dn),
1819                                   ldb_errstring(b_state->sam_ctx)));
1820                         TALLOC_FREE(frame);
1821                         return WERR_DS_DRA_INTERNAL_ERROR;
1822                 }
1823
1824                 if (search_res2->count != 1) {
1825                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Set object %s - %u objects returned",
1826                                   ldb_dn_get_linearized(rid_set_dn),
1827                                   search_res2->count));
1828                         TALLOC_FREE(frame);
1829                         return WERR_DS_DRA_INTERNAL_ERROR;
1830                 }
1831
1832                 /* Finally get the server DN */
1833                 ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, frame,
1834                                                       &search_res3,
1835                                                       machine_dn, LDB_SCOPE_BASE,
1836                                                       collect_objects_attrs,
1837                                                       NULL);
1838                 if (ret != LDB_SUCCESS) {
1839                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get server object %s - %s",
1840                                   ldb_dn_get_linearized(server_dn),
1841                                   ldb_errstring(b_state->sam_ctx)));
1842                         TALLOC_FREE(frame);
1843                         return WERR_DS_DRA_INTERNAL_ERROR;
1844                 }
1845
1846                 if (search_res3->count != 1) {
1847                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get server object %s - %u objects returned",
1848                                   ldb_dn_get_linearized(server_dn),
1849                                   search_res3->count));
1850                         TALLOC_FREE(frame);
1851                         return WERR_DS_DRA_INTERNAL_ERROR;
1852                 }
1853
1854                 /* Now extend the original search_res with these answers */
1855                 (*search_res)->count = 3;
1856
1857                 (*search_res)->msgs = talloc_realloc(frame, (*search_res)->msgs,
1858                                                      struct ldb_message *,
1859                                                      (*search_res)->count);
1860                 if ((*search_res)->msgs == NULL) {
1861                         TALLOC_FREE(frame);
1862                         return WERR_NOT_ENOUGH_MEMORY;
1863                 }
1864
1865
1866                 talloc_steal(mem_ctx, *search_res);
1867                 (*search_res)->msgs[1] =
1868                         talloc_steal((*search_res)->msgs, search_res2->msgs[0]);
1869                 (*search_res)->msgs[2] =
1870                         talloc_steal((*search_res)->msgs, search_res3->msgs[0]);
1871
1872                 TALLOC_FREE(frame);
1873                 return WERR_OK;
1874         }
1875         default:
1876                 /* TODO: implement extended op specific collection
1877                  * of objects. Right now we just normal procedure
1878                  * for collecting objects */
1879                 return getncchanges_collect_objects(b_state, mem_ctx, req10, search_dn, extra_filter, search_res);
1880         }
1881 }
1882
1883 static void dcesrv_drsuapi_update_highwatermark(const struct ldb_message *msg,
1884                                                 uint64_t max_usn,
1885                                                 struct drsuapi_DsReplicaHighWaterMark *hwm)
1886 {
1887         uint64_t uSN = ldb_msg_find_attr_as_uint64(msg, "uSNChanged", 0);
1888
1889         if (uSN > max_usn) {
1890                 /*
1891                  * Only report the max_usn we had at the start
1892                  * of the replication cycle.
1893                  *
1894                  * If this object has changed lately we better
1895                  * let the destination dsa refetch the change.
1896                  * This is better than the risk of loosing some
1897                  * objects or linked attributes.
1898                  */
1899                 return;
1900         }
1901
1902         if (uSN <= hwm->tmp_highest_usn) {
1903                 return;
1904         }
1905
1906         hwm->tmp_highest_usn = uSN;
1907         hwm->reserved_usn = 0;
1908 }
1909
1910 static WERROR dcesrv_drsuapi_anc_cache_add(struct db_context *anc_cache,
1911                                            const struct GUID *guid)
1912 {
1913         enum ndr_err_code ndr_err;
1914         uint8_t guid_buf[16] = { 0, };
1915         DATA_BLOB b = {
1916                 .data = guid_buf,
1917                 .length = sizeof(guid_buf),
1918         };
1919         TDB_DATA key = {
1920                 .dptr = b.data,
1921                 .dsize = b.length,
1922         };
1923         TDB_DATA val = {
1924                 .dptr = NULL,
1925                 .dsize = 0,
1926         };
1927         NTSTATUS status;
1928
1929         ndr_err = ndr_push_struct_into_fixed_blob(&b, guid,
1930                         (ndr_push_flags_fn_t)ndr_push_GUID);
1931         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1932                 return WERR_DS_DRA_INTERNAL_ERROR;
1933         }
1934
1935         status = dbwrap_store(anc_cache, key, val, TDB_REPLACE);
1936         if (!NT_STATUS_IS_OK(status)) {
1937                 return WERR_DS_DRA_INTERNAL_ERROR;
1938         }
1939
1940         return WERR_OK;
1941 }
1942
1943 static WERROR dcesrv_drsuapi_anc_cache_exists(struct db_context *anc_cache,
1944                                               const struct GUID *guid)
1945 {
1946         enum ndr_err_code ndr_err;
1947         uint8_t guid_buf[16] = { 0, };
1948         DATA_BLOB b = {
1949                 .data = guid_buf,
1950                 .length = sizeof(guid_buf),
1951         };
1952         TDB_DATA key = {
1953                 .dptr = b.data,
1954                 .dsize = b.length,
1955         };
1956         bool exists;
1957
1958         ndr_err = ndr_push_struct_into_fixed_blob(&b, guid,
1959                         (ndr_push_flags_fn_t)ndr_push_GUID);
1960         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1961                 return WERR_DS_DRA_INTERNAL_ERROR;
1962         }
1963
1964         exists = dbwrap_exists(anc_cache, key);
1965         if (!exists) {
1966                 return WERR_OBJECT_NOT_FOUND;
1967         }
1968
1969         return WERR_OBJECT_NAME_EXISTS;
1970 }
1971
1972 /* 
1973   drsuapi_DsGetNCChanges
1974
1975   see MS-DRSR 4.1.10.5.2 for basic logic of this function
1976 */
1977 WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1978                                      struct drsuapi_DsGetNCChanges *r)
1979 {
1980         struct drsuapi_DsReplicaObjectIdentifier *ncRoot;
1981         int ret;
1982         uint32_t i, k;
1983         struct dsdb_schema *schema;
1984         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
1985         struct drsuapi_DsReplicaObjectListItemEx **currentObject;
1986         NTSTATUS status;
1987         DATA_BLOB session_key;
1988         WERROR werr;
1989         struct dcesrv_handle *h;
1990         struct drsuapi_bind_state *b_state;
1991         struct drsuapi_getncchanges_state *getnc_state;
1992         struct drsuapi_DsGetNCChangesRequest10 *req10;
1993         uint32_t options;
1994         uint32_t max_objects;
1995         uint32_t max_links;
1996         uint32_t link_count = 0;
1997         uint32_t link_total = 0;
1998         uint32_t link_given = 0;
1999         struct ldb_dn *search_dn = NULL;
2000         bool am_rodc, null_scope=false;
2001         enum security_user_level security_level;
2002         struct ldb_context *sam_ctx;
2003         struct dom_sid *user_sid;
2004         bool is_secret_request;
2005         bool is_gc_pas_request;
2006         struct drsuapi_changed_objects *changes;
2007         time_t max_wait;
2008         time_t start = time(NULL);
2009         bool max_wait_reached = false;
2010         bool has_get_all_changes = false;
2011         struct GUID invocation_id;
2012         static const struct drsuapi_DsReplicaLinkedAttribute no_linked_attr;
2013         struct dsdb_schema_prefixmap *pfm_remote = NULL;
2014         bool full = true;
2015         uint32_t *local_pas = NULL;
2016         struct ldb_dn *machine_dn = NULL; /* Only used for REPL SECRET EXOP */
2017
2018         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
2019         b_state = h->data;
2020
2021         sam_ctx = b_state->sam_ctx_system?b_state->sam_ctx_system:b_state->sam_ctx;
2022
2023         invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
2024
2025         *r->out.level_out = 6;
2026         /* TODO: linked attributes*/
2027         r->out.ctr->ctr6.linked_attributes_count = 0;
2028         r->out.ctr->ctr6.linked_attributes = discard_const_p(struct drsuapi_DsReplicaLinkedAttribute, &no_linked_attr);
2029
2030         r->out.ctr->ctr6.object_count = 0;
2031         r->out.ctr->ctr6.nc_object_count = 0;
2032         r->out.ctr->ctr6.more_data = false;
2033         r->out.ctr->ctr6.uptodateness_vector = NULL;
2034         r->out.ctr->ctr6.source_dsa_guid = *(samdb_ntds_objectGUID(sam_ctx));
2035         r->out.ctr->ctr6.source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
2036         r->out.ctr->ctr6.first_object = NULL;
2037
2038         /* a RODC doesn't allow for any replication */
2039         ret = samdb_rodc(sam_ctx, &am_rodc);
2040         if (ret == LDB_SUCCESS && am_rodc) {
2041                 DEBUG(0,(__location__ ": DsGetNCChanges attempt on RODC\n"));
2042                 return WERR_DS_DRA_SOURCE_DISABLED;
2043         }
2044
2045         /* Check request revision. 
2046          */
2047         switch (r->in.level) {
2048         case 8:
2049                 req10 = getncchanges_map_req8(mem_ctx, &r->in.req->req8);
2050                 if (req10 == NULL) {
2051                         return WERR_NOT_ENOUGH_MEMORY;
2052                 }
2053                 break;
2054         case 10:
2055                 req10 = &r->in.req->req10;
2056                 break;
2057         default:
2058                 DEBUG(0,(__location__ ": Request for DsGetNCChanges with unsupported level %u\n",
2059                          r->in.level));
2060                 return WERR_REVISION_MISMATCH;
2061         }
2062
2063
2064         /* Perform access checks. */
2065         /* TODO: we need to support a sync on a specific non-root
2066          * DN. We'll need to find the real partition root here */
2067         ncRoot = req10->naming_context;
2068         if (ncRoot == NULL) {
2069                 DEBUG(0,(__location__ ": Request for DsGetNCChanges with no NC\n"));
2070                 return WERR_DS_DRA_INVALID_PARAMETER;
2071         }
2072
2073         if (samdb_ntds_options(sam_ctx, &options) != LDB_SUCCESS) {
2074                 return WERR_DS_DRA_INTERNAL_ERROR;
2075         }
2076
2077         if ((options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL) &&
2078             !(req10->replica_flags & DRSUAPI_DRS_SYNC_FORCED)) {
2079                 return WERR_DS_DRA_SOURCE_DISABLED;
2080         }
2081
2082         user_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
2083
2084         /* all clients must have GUID_DRS_GET_CHANGES */
2085         werr = drs_security_access_check_nc_root(b_state->sam_ctx,
2086                                                  mem_ctx,
2087                                                  dce_call->conn->auth_state.session_info->security_token,
2088                                                  req10->naming_context,
2089                                                  GUID_DRS_GET_CHANGES);
2090         if (!W_ERROR_IS_OK(werr)) {
2091                 return werr;
2092         }
2093
2094         if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) {
2095                 full = req10->partial_attribute_set == NULL &&
2096                        req10->partial_attribute_set_ex == NULL;
2097         } else {
2098                 full = (options & DRSUAPI_DRS_WRIT_REP) != 0;
2099         }
2100
2101         werr = dsdb_schema_pfm_from_drsuapi_pfm(&req10->mapping_ctr, true,
2102                                                 mem_ctx, &pfm_remote, NULL);
2103
2104         /* We were supplied a partial attribute set, without the prefix map! */
2105         if (!full && !W_ERROR_IS_OK(werr)) {
2106                 if (req10->mapping_ctr.num_mappings == 0) {
2107                         /*
2108                          * Despite the fact MS-DRSR specifies that this shouldn't
2109                          * happen, Windows RODCs will in fact not provide a prefixMap.
2110                          */
2111                         DEBUG(5,(__location__ ": Failed to provide a remote prefixMap,"
2112                                  " falling back to local prefixMap\n"));
2113                 } else {
2114                         DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s\n",
2115                                  win_errstr(werr)));
2116                         return werr;
2117                 }
2118         }
2119
2120         /* allowed if the GC PAS and client has
2121            GUID_DRS_GET_FILTERED_ATTRIBUTES */
2122         werr = dcesrv_drsuapi_is_gc_pas_request(b_state, req10, pfm_remote, &is_gc_pas_request);
2123         if (!W_ERROR_IS_OK(werr)) {
2124                 return werr;
2125         }
2126         if (is_gc_pas_request) {
2127                 werr = drs_security_access_check_nc_root(b_state->sam_ctx,
2128                                                          mem_ctx,
2129                                                          dce_call->conn->auth_state.session_info->security_token,
2130                                                          req10->naming_context,
2131                                                          GUID_DRS_GET_FILTERED_ATTRIBUTES);
2132                 if (W_ERROR_IS_OK(werr)) {
2133                         goto allowed;
2134                 }
2135         }
2136
2137         werr = dcesrv_drsuapi_is_reveal_secrets_request(b_state, req10,
2138                                                         pfm_remote,
2139                                                         &is_secret_request);
2140         if (!W_ERROR_IS_OK(werr)) {
2141                 return werr;
2142         }
2143         if (is_secret_request) {
2144                 werr = drs_security_access_check_nc_root(b_state->sam_ctx,
2145                                                          mem_ctx,
2146                                                          dce_call->conn->auth_state.session_info->security_token,
2147                                                          req10->naming_context,
2148                                                          GUID_DRS_GET_ALL_CHANGES);
2149                 if (!W_ERROR_IS_OK(werr)) {
2150                         /* Only bail if this is not a EXOP_REPL_SECRET */
2151                         if (req10->extended_op != DRSUAPI_EXOP_REPL_SECRET) {
2152                                 return werr;
2153                         }
2154                 } else {
2155                         has_get_all_changes = true;
2156                 }
2157         }
2158
2159 allowed:
2160         /* for non-administrator replications, check that they have
2161            given the correct source_dsa_invocation_id */
2162         security_level = security_session_user_level(dce_call->conn->auth_state.session_info,
2163                                                      samdb_domain_sid(sam_ctx));
2164         if (security_level == SECURITY_RO_DOMAIN_CONTROLLER) {
2165                 if (req10->replica_flags & DRSUAPI_DRS_WRIT_REP) {
2166                         /* we rely on this flag being unset for RODC requests */
2167                         req10->replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
2168                 }
2169         }
2170
2171         if (req10->replica_flags & DRSUAPI_DRS_FULL_SYNC_PACKET) {
2172                 /* Ignore the _in_ uptpdateness vector*/
2173                 req10->uptodateness_vector = NULL;
2174         }
2175
2176         if (GUID_all_zero(&req10->source_dsa_invocation_id)) {
2177                 req10->source_dsa_invocation_id = invocation_id;
2178         }
2179
2180         if (!GUID_equal(&req10->source_dsa_invocation_id, &invocation_id)) {
2181                 /*
2182                  * The given highwatermark is only valid relative to the
2183                  * specified source_dsa_invocation_id.
2184                  */
2185                 ZERO_STRUCT(req10->highwatermark);
2186         }
2187
2188         getnc_state = b_state->getncchanges_state;
2189
2190         /* see if a previous replication has been abandoned */
2191         if (getnc_state) {
2192                 struct ldb_dn *new_dn = drs_ObjectIdentifier_to_dn(getnc_state, sam_ctx, ncRoot);
2193                 if (ldb_dn_compare(new_dn, getnc_state->ncRoot_dn) != 0) {
2194                         DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s (last_dn %s)\n",
2195                                  ldb_dn_get_linearized(new_dn),
2196                                  ldb_dn_get_linearized(getnc_state->ncRoot_dn),
2197                                  ldb_dn_get_linearized(getnc_state->last_dn)));
2198                         talloc_free(getnc_state);
2199                         getnc_state = NULL;
2200                 }
2201         }
2202
2203         if (getnc_state) {
2204                 ret = drsuapi_DsReplicaHighWaterMark_cmp(&getnc_state->last_hwm,
2205                                                          &req10->highwatermark);
2206                 if (ret != 0) {
2207                         DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication "
2208                                  "on DN %s %s highwatermark (last_dn %s)\n",
2209                                  ldb_dn_get_linearized(getnc_state->ncRoot_dn),
2210                                  (ret > 0) ? "older" : "newer",
2211                                  ldb_dn_get_linearized(getnc_state->last_dn)));
2212                         talloc_free(getnc_state);
2213                         getnc_state = NULL;
2214                 }
2215         }
2216
2217         if (getnc_state == NULL) {
2218                 getnc_state = talloc_zero(b_state, struct drsuapi_getncchanges_state);
2219                 if (getnc_state == NULL) {
2220                         return WERR_NOT_ENOUGH_MEMORY;
2221                 }
2222                 b_state->getncchanges_state = getnc_state;
2223                 getnc_state->ncRoot_dn = drs_ObjectIdentifier_to_dn(getnc_state, sam_ctx, ncRoot);
2224                 if (getnc_state->ncRoot_dn == NULL) {
2225                         return WERR_NOT_ENOUGH_MEMORY;
2226                 }
2227
2228                 ret = dsdb_find_guid_by_dn(b_state->sam_ctx_system,
2229                                            getnc_state->ncRoot_dn,
2230                                            &getnc_state->ncRoot_guid);
2231                 if (ret != LDB_SUCCESS) {
2232                         DEBUG(0,(__location__ ": Failed to find GUID of ncRoot_dn %s\n",
2233                                  ldb_dn_get_linearized(getnc_state->ncRoot_dn)));
2234                         return WERR_DS_DRA_INTERNAL_ERROR;
2235                 }
2236                 ncRoot->guid = getnc_state->ncRoot_guid;
2237
2238                 /* find out if we are to replicate Schema NC */
2239                 ret = ldb_dn_compare_base(ldb_get_schema_basedn(b_state->sam_ctx),
2240                                           getnc_state->ncRoot_dn);
2241
2242                 getnc_state->is_schema_nc = (0 == ret);
2243
2244                 if (req10->extended_op != DRSUAPI_EXOP_NONE) {
2245                         r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
2246                 }
2247
2248                 /*
2249                  * This is the first replication cycle and it is
2250                  * a good place to handle extended operations
2251                  *
2252                  * FIXME: we don't fully support extended operations yet
2253                  */
2254                 switch (req10->extended_op) {
2255                 case DRSUAPI_EXOP_NONE:
2256                         break;
2257                 case DRSUAPI_EXOP_FSMO_RID_ALLOC:
2258                         werr = getncchanges_rid_alloc(b_state, mem_ctx, req10, &r->out.ctr->ctr6, &search_dn);
2259                         W_ERROR_NOT_OK_RETURN(werr);
2260                         if (r->out.ctr->ctr6.extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
2261                                 return WERR_OK;
2262                         }
2263                         break;
2264                 case DRSUAPI_EXOP_REPL_SECRET:
2265                         werr = getncchanges_repl_secret(b_state, mem_ctx, req10,
2266                                                         user_sid,
2267                                                         &r->out.ctr->ctr6,
2268                                                         has_get_all_changes,
2269                                                         &machine_dn);
2270                         r->out.result = werr;
2271                         W_ERROR_NOT_OK_RETURN(werr);
2272                         break;
2273                 case DRSUAPI_EXOP_FSMO_REQ_ROLE:
2274                         werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
2275                         W_ERROR_NOT_OK_RETURN(werr);
2276                         if (r->out.ctr->ctr6.extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
2277                                 return WERR_OK;
2278                         }
2279                         break;
2280                 case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
2281                         werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
2282                         W_ERROR_NOT_OK_RETURN(werr);
2283                         if (r->out.ctr->ctr6.extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
2284                                 return WERR_OK;
2285                         }
2286                         break;
2287                 case DRSUAPI_EXOP_FSMO_REQ_PDC:
2288                         werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
2289                         W_ERROR_NOT_OK_RETURN(werr);
2290                         if (r->out.ctr->ctr6.extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
2291                                 return WERR_OK;
2292                         }
2293                         break;
2294                 case DRSUAPI_EXOP_REPL_OBJ:
2295                         werr = getncchanges_repl_obj(b_state, mem_ctx, req10, user_sid, &r->out.ctr->ctr6);
2296                         r->out.result = werr;
2297                         W_ERROR_NOT_OK_RETURN(werr);
2298                         break;
2299
2300                 case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
2301
2302                         DEBUG(0,(__location__ ": Request for DsGetNCChanges unsupported extended op 0x%x\n",
2303                                  (unsigned)req10->extended_op));
2304                         return WERR_DS_DRA_NOT_SUPPORTED;
2305                 }
2306         }
2307
2308         if (!ldb_dn_validate(getnc_state->ncRoot_dn) ||
2309             ldb_dn_is_null(getnc_state->ncRoot_dn)) {
2310                 DEBUG(0,(__location__ ": Bad DN '%s'\n",
2311                          drs_ObjectIdentifier_to_string(mem_ctx, ncRoot)));
2312                 return WERR_DS_DRA_INVALID_PARAMETER;
2313         }
2314
2315         ncRoot->guid = getnc_state->ncRoot_guid;
2316
2317         /* we need the session key for encrypting password attributes */
2318         status = dcesrv_inherited_session_key(dce_call->conn, &session_key);
2319         if (!NT_STATUS_IS_OK(status)) {
2320                 DEBUG(0,(__location__ ": Failed to get session key\n"));
2321                 return WERR_DS_DRA_INTERNAL_ERROR;
2322         }
2323
2324         /* 
2325            TODO: MS-DRSR section 4.1.10.1.1
2326            Work out if this is the start of a new cycle */
2327
2328         if (getnc_state->guids == NULL) {
2329                 const char *extra_filter;
2330                 struct ldb_result *search_res = NULL;
2331                 static const struct drsuapi_DsReplicaCursorCtrEx empty_udv;
2332                 const struct drsuapi_DsReplicaCursorCtrEx *udv = NULL;
2333
2334                 extra_filter = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter");
2335
2336                 if (req10->uptodateness_vector != NULL) {
2337                         udv = req10->uptodateness_vector;
2338                 } else {
2339                         udv = &empty_udv;
2340                 }
2341
2342                 getnc_state->min_usn = req10->highwatermark.highest_usn;
2343                 for (i = 0; i < udv->count; i++) {
2344                         bool match;
2345                         const struct drsuapi_DsReplicaCursor *cur =
2346                                 &udv->cursors[i];
2347
2348                         match = GUID_equal(&invocation_id,
2349                                            &cur->source_dsa_invocation_id);
2350                         if (!match) {
2351                                 continue;
2352                         }
2353                         if (cur->highest_usn > getnc_state->min_usn) {
2354                                 getnc_state->min_usn = cur->highest_usn;
2355                         }
2356                         break;
2357                 }
2358                 getnc_state->max_usn = getnc_state->min_usn;
2359
2360                 getnc_state->final_udv = talloc_zero(getnc_state,
2361                                         struct drsuapi_DsReplicaCursor2CtrEx);
2362                 if (getnc_state->final_udv == NULL) {
2363                         return WERR_NOT_ENOUGH_MEMORY;
2364                 }
2365                 werr = get_nc_changes_udv(sam_ctx, getnc_state->ncRoot_dn,
2366                                           getnc_state->final_udv);
2367                 if (!W_ERROR_IS_OK(werr)) {
2368                         return werr;
2369                 }
2370
2371                 if (req10->extended_op == DRSUAPI_EXOP_NONE) {
2372                         werr = getncchanges_collect_objects(b_state, mem_ctx, req10,
2373                                                             search_dn, extra_filter,
2374                                                             &search_res);
2375                 } else {
2376                         werr = getncchanges_collect_objects_exop(b_state, mem_ctx, req10,
2377                                                                  &r->out.ctr->ctr6,
2378                                                                  search_dn, extra_filter,
2379                                                                  &search_res);
2380                 }
2381                 W_ERROR_NOT_OK_RETURN(werr);
2382
2383                 /* extract out the GUIDs list */
2384                 getnc_state->num_records = search_res ? search_res->count : 0;
2385                 getnc_state->guids = talloc_array(getnc_state, struct GUID, getnc_state->num_records);
2386                 W_ERROR_HAVE_NO_MEMORY(getnc_state->guids);
2387
2388                 changes = talloc_array(getnc_state,
2389                                        struct drsuapi_changed_objects,
2390                                        getnc_state->num_records);
2391                 W_ERROR_HAVE_NO_MEMORY(changes);
2392
2393                 for (i=0; i<getnc_state->num_records; i++) {
2394                         changes[i].dn = search_res->msgs[i]->dn;
2395                         changes[i].guid = samdb_result_guid(search_res->msgs[i], "objectGUID");
2396                         changes[i].usn = ldb_msg_find_attr_as_uint64(search_res->msgs[i], "uSNChanged", 0);
2397
2398                         if (changes[i].usn > getnc_state->max_usn) {
2399                                 getnc_state->max_usn = changes[i].usn;
2400                         }
2401                 }
2402
2403                 /* RID_ALLOC returns 3 objects in a fixed order */
2404                 if (req10->extended_op == DRSUAPI_EXOP_FSMO_RID_ALLOC) {
2405                         /* Do nothing */
2406                 } else {
2407                         LDB_TYPESAFE_QSORT(changes,
2408                                            getnc_state->num_records,
2409                                            getnc_state,
2410                                            site_res_cmp_usn_order);
2411                 }
2412
2413                 for (i=0; i < getnc_state->num_records; i++) {
2414                         getnc_state->guids[i] = changes[i].guid;
2415                         if (GUID_all_zero(&getnc_state->guids[i])) {
2416                                 DEBUG(2,("getncchanges: bad objectGUID from %s\n",
2417                                          ldb_dn_get_linearized(search_res->msgs[i]->dn)));
2418                                 return WERR_DS_DRA_INTERNAL_ERROR;
2419                         }
2420                 }
2421
2422                 getnc_state->final_hwm.tmp_highest_usn = getnc_state->max_usn;
2423                 getnc_state->final_hwm.reserved_usn = 0;
2424                 getnc_state->final_hwm.highest_usn = getnc_state->max_usn;
2425
2426                 talloc_free(search_res);
2427                 talloc_free(changes);
2428
2429                 if (req10->extended_op != DRSUAPI_EXOP_NONE) {
2430                         /* Do nothing */
2431                 } else if (req10->replica_flags & DRSUAPI_DRS_GET_ANC) {
2432                         getnc_state->anc_cache = db_open_rbt(getnc_state);
2433                         if (getnc_state->anc_cache == NULL) {
2434                                 return WERR_NOT_ENOUGH_MEMORY;
2435                         }
2436                 }
2437         }
2438
2439         if (req10->uptodateness_vector) {
2440                 /* make sure its sorted */
2441                 TYPESAFE_QSORT(req10->uptodateness_vector->cursors,
2442                                req10->uptodateness_vector->count,
2443                                drsuapi_DsReplicaCursor_compare);
2444         }
2445
2446         /* Prefix mapping */
2447         schema = dsdb_get_schema(sam_ctx, mem_ctx);
2448         if (!schema) {
2449                 DEBUG(0,("No schema in sam_ctx\n"));
2450                 return WERR_DS_DRA_INTERNAL_ERROR;
2451         }
2452
2453         r->out.ctr->ctr6.naming_context = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
2454         if (r->out.ctr->ctr6.naming_context == NULL) {
2455                 return WERR_NOT_ENOUGH_MEMORY;
2456         }
2457         *r->out.ctr->ctr6.naming_context = *ncRoot;
2458
2459         /* find the SID if there is one */
2460         dsdb_find_sid_by_dn(sam_ctx, getnc_state->ncRoot_dn, &r->out.ctr->ctr6.naming_context->sid);
2461
2462         dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, &ctr);
2463         r->out.ctr->ctr6.mapping_ctr = *ctr;
2464
2465         r->out.ctr->ctr6.source_dsa_guid = *(samdb_ntds_objectGUID(sam_ctx));
2466         r->out.ctr->ctr6.source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
2467
2468         r->out.ctr->ctr6.old_highwatermark = req10->highwatermark;
2469         r->out.ctr->ctr6.new_highwatermark = req10->highwatermark;
2470
2471         currentObject = &r->out.ctr->ctr6.first_object;
2472
2473         max_objects = lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max object sync", 1000);
2474         /*
2475          * The client control here only applies in normal replication, not extended
2476          * operations, which return a fixed set, even if the caller
2477          * sets max_object_count == 0
2478          */
2479         if (req10->extended_op == DRSUAPI_EXOP_NONE) {
2480                 /* use this to force single objects at a time, which is useful
2481                  * for working out what object is giving problems
2482                  */
2483                 if (req10->max_object_count < max_objects) {
2484                         max_objects = req10->max_object_count;
2485                 }
2486         }
2487         /*
2488          * TODO: work out how the maximum should be calculated
2489          */
2490         max_links = lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max link sync", 1500);
2491
2492         /*
2493          * Maximum time that we can spend in a getncchanges
2494          * in order to avoid timeout of the other part.
2495          * 10 seconds by default.
2496          */
2497         max_wait = lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "max work time", 10);
2498
2499         if (req10->partial_attribute_set != NULL) {
2500                 struct dsdb_syntax_ctx syntax_ctx;
2501                 uint32_t j = 0;
2502
2503                 dsdb_syntax_ctx_init(&syntax_ctx, b_state->sam_ctx, schema);
2504                 syntax_ctx.pfm_remote = pfm_remote;
2505
2506                 local_pas = talloc_array(b_state, uint32_t, req10->partial_attribute_set->num_attids);
2507
2508                 for (j = 0; j < req10->partial_attribute_set->num_attids; j++) {
2509                         getncchanges_attid_remote_to_local(schema,
2510                                                            &syntax_ctx,
2511                                                            req10->partial_attribute_set->attids[j],
2512                                                            (enum drsuapi_DsAttributeId *)&local_pas[j],
2513                                                            NULL);
2514                 }
2515
2516                 LDB_TYPESAFE_QSORT(local_pas,
2517                                    req10->partial_attribute_set->num_attids,
2518                                    NULL,
2519                                    uint32_t_ptr_cmp);
2520         }
2521
2522         for (i=getnc_state->num_processed;
2523              i<getnc_state->num_records &&
2524                      !null_scope &&
2525                      (r->out.ctr->ctr6.object_count < max_objects)
2526                      && !max_wait_reached;
2527             i++) {
2528                 struct drsuapi_DsReplicaObjectListItemEx *new_objs = NULL;
2529                 struct drsuapi_DsReplicaObjectListItemEx *obj;
2530                 struct ldb_message *msg;
2531                 static const char * const msg_attrs[] = {
2532                                             "*",
2533                                             "nTSecurityDescriptor",
2534                                             "parentGUID",
2535                                             "replPropertyMetaData",
2536                                             DSDB_SECRET_ATTRIBUTES,
2537                                             NULL };
2538                 struct ldb_result *msg_res;
2539                 struct ldb_dn *msg_dn;
2540                 const struct GUID *next_anc_guid = NULL;
2541
2542                 obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx);
2543                 W_ERROR_HAVE_NO_MEMORY(obj);
2544
2545                 msg_dn = ldb_dn_new_fmt(obj, sam_ctx, "<GUID=%s>", GUID_string(obj, &getnc_state->guids[i]));
2546                 W_ERROR_HAVE_NO_MEMORY(msg_dn);
2547
2548
2549                 /* by re-searching here we avoid having a lot of full
2550                  * records in memory between calls to getncchanges
2551                  */
2552                 ret = drsuapi_search_with_extended_dn(sam_ctx, obj, &msg_res,
2553                                                       msg_dn,
2554                                                       LDB_SCOPE_BASE, msg_attrs, NULL);
2555                 if (ret != LDB_SUCCESS) {
2556                         if (ret != LDB_ERR_NO_SUCH_OBJECT) {
2557                                 DEBUG(1,("getncchanges: failed to fetch DN %s - %s\n",
2558                                          ldb_dn_get_extended_linearized(obj, msg_dn, 1), ldb_errstring(sam_ctx)));
2559                         }
2560                         talloc_free(obj);
2561                         continue;
2562                 }
2563
2564                 msg = msg_res->msgs[0];
2565
2566                 /*
2567                  * If it has already been added as an ancestor of
2568                  * an object, we don't need to do anything more,
2569                  * as we've already added the links.
2570                  */
2571                 if (getnc_state->anc_cache != NULL) {
2572                         werr = dcesrv_drsuapi_anc_cache_exists(getnc_state->anc_cache,
2573                                                                &getnc_state->guids[i]);
2574                         if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
2575                                 dcesrv_drsuapi_update_highwatermark(msg,
2576                                                 getnc_state->max_usn,
2577                                                 &r->out.ctr->ctr6.new_highwatermark);
2578                                 /* no attributes to send */
2579                                 talloc_free(obj);
2580                                 continue;
2581                         }
2582                 }
2583
2584                 max_wait_reached = (time(NULL) - start > max_wait);
2585
2586                 werr = get_nc_changes_build_object(obj, msg,
2587                                                    sam_ctx, getnc_state->ncRoot_dn,
2588                                                    getnc_state->is_schema_nc,
2589                                                    schema, &session_key, getnc_state->min_usn,
2590                                                    req10->replica_flags,
2591                                                    req10->partial_attribute_set,
2592                                                    req10->uptodateness_vector,
2593                                                    req10->extended_op,
2594                                                    max_wait_reached,
2595                                                    local_pas, machine_dn);
2596                 if (!W_ERROR_IS_OK(werr)) {
2597                         return werr;
2598                 }
2599
2600                 werr = get_nc_changes_add_links(sam_ctx, getnc_state,
2601                                                 getnc_state->ncRoot_dn,
2602                                                 getnc_state->is_schema_nc,
2603                                                 schema, getnc_state->min_usn,
2604                                                 req10->replica_flags,
2605                                                 msg,
2606                                                 &getnc_state->la_list,
2607                                                 &getnc_state->la_count,
2608                                                 req10->uptodateness_vector);
2609                 if (!W_ERROR_IS_OK(werr)) {
2610                         return werr;
2611                 }
2612
2613                 dcesrv_drsuapi_update_highwatermark(msg,
2614                                         getnc_state->max_usn,
2615                                         &r->out.ctr->ctr6.new_highwatermark);
2616
2617                 if (obj->meta_data_ctr == NULL) {
2618                         DEBUG(8,(__location__ ": getncchanges skipping send of object %s\n",
2619                                  ldb_dn_get_linearized(msg->dn)));
2620                         /* no attributes to send */
2621                         talloc_free(obj);
2622                         continue;
2623                 }
2624
2625                 new_objs = obj;
2626
2627                 if (getnc_state->anc_cache != NULL) {
2628                         werr = dcesrv_drsuapi_anc_cache_add(getnc_state->anc_cache,
2629                                                             &getnc_state->guids[i]);
2630                         if (!W_ERROR_IS_OK(werr)) {
2631                                 return werr;
2632                         }
2633
2634                         next_anc_guid = obj->parent_object_guid;
2635                 }
2636
2637                 while (next_anc_guid != NULL) {
2638                         struct drsuapi_DsReplicaObjectListItemEx *anc_obj = NULL;
2639                         struct ldb_message *anc_msg = NULL;
2640                         struct ldb_result *anc_res = NULL;
2641                         struct ldb_dn *anc_dn = NULL;
2642
2643                         werr = dcesrv_drsuapi_anc_cache_exists(getnc_state->anc_cache,
2644                                                                next_anc_guid);
2645                         if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
2646                                 /*
2647                                  * We don't need to send it twice.
2648                                  */
2649                                 break;
2650                         }
2651                         if (W_ERROR_IS_OK(werr)) {
2652                                 return WERR_INTERNAL_ERROR;
2653                         }
2654                         if (!W_ERROR_EQUAL(werr, WERR_OBJECT_NOT_FOUND)) {
2655                                 return werr;
2656                         }
2657                         werr = WERR_OK;
2658
2659                         anc_obj = talloc_zero(mem_ctx,
2660                                         struct drsuapi_DsReplicaObjectListItemEx);
2661                         if (anc_obj == NULL) {
2662                                 return WERR_NOT_ENOUGH_MEMORY;
2663                         }
2664
2665                         anc_dn = ldb_dn_new_fmt(anc_obj, sam_ctx, "<GUID=%s>",
2666                                         GUID_string(anc_obj, next_anc_guid));
2667                         if (anc_dn == NULL) {
2668                                 return WERR_NOT_ENOUGH_MEMORY;
2669                         }
2670
2671                         ret = drsuapi_search_with_extended_dn(sam_ctx, anc_obj,
2672                                                               &anc_res, anc_dn,
2673                                                               LDB_SCOPE_BASE,
2674                                                               msg_attrs, NULL);
2675                         if (ret != LDB_SUCCESS) {
2676                                 const char *anc_str = NULL;
2677                                 const char *obj_str = NULL;
2678
2679                                 anc_str = ldb_dn_get_extended_linearized(anc_obj,
2680                                                                          anc_dn,
2681                                                                          1);
2682                                 obj_str = ldb_dn_get_extended_linearized(anc_obj,
2683                                                  &n